Scippy

    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-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 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#include <string.h>
    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 SCIP_Real rhs, /**< the right hand side of the cut */
    276 int nvars, /**< the number of variables in the cut */
    277 SCIP_Real* cutcoefs, /**< the coefficients of the MIR cut */
    278 int* cutinds, /**< the variable indices of the MIR cut */
    279 SCIP_Real* cutrhs, /**< the RHS of the MIR cut */
    280 int* cutnnz, /**< the number of non-zeros in the cut */
    281 SCIP_Bool* success /**< was the MIR cut successfully computed? */
    282 )
    283{
    284 SCIP_AGGRROW* aggrrow;
    285 SCIP_Real* rowvals;
    286 int* rowinds;
    287
    288 SCIP_Real cutefficacy;
    289 int cutrank;
    290 SCIP_Bool cutislocal;
    291
    292 SCIP_Bool cutsuccess;
    293
    294 int i;
    295
    296 /* creating the aggregation row. There will be only a single row in this aggregation, since it is only used to
    297 * compute the MIR coefficients
    298 */
    299 SCIP_CALL( SCIPaggrRowCreate(masterprob, &aggrrow) );
    300
    301 /* retrieving the indices for the variables in the optimality cut. All of the values must be negated, since the
    302 * aggregation row requires a RHS, where the optimality cut is computed with an LHS
    303 */
    304 SCIP_CALL( SCIPallocBufferArray(masterprob, &rowvals, nvars) );
    305 SCIP_CALL( SCIPallocBufferArray(masterprob, &rowinds, nvars) );
    306
    307 assert(SCIPisInfinity(masterprob, rhs));
    308 assert(!SCIPisInfinity(masterprob, lhs));
    309 for( i = 0; i < nvars; i++ )
    310 {
    311 rowinds[i] = SCIPvarGetProbindex(vars[i]);
    312 assert(rowinds[i] >= 0);
    313 rowvals[i] = -vals[i];
    314 }
    315
    316 /* adding the optimality cut to the aggregation row */
    317 SCIP_CALL( SCIPaggrRowAddCustomCons(masterprob, aggrrow, rowinds, rowvals, nvars, -lhs, 1.0, 1, FALSE) );
    318
    319 /* calculating a flow cover for the optimality cut */
    320 cutefficacy = 0.0;
    321 SCIP_CALL( SCIPcalcFlowCover(masterprob, sol, TRUE, 0.9999, FALSE, aggrrow, cutcoefs, cutrhs, cutinds, cutnnz,
    322 &cutefficacy, NULL, &cutislocal, &cutsuccess) );
    323 (*success) = cutsuccess;
    324
    325 /* calculating the MIR coefficients for the optimality cut */
    326 SCIP_CALL( SCIPcalcMIR(masterprob, sol, TRUE, 0.9999, 1, FALSE, FALSE, NULL, NULL, 0.001, 0.999, 1.0, aggrrow,
    327 cutcoefs, cutrhs, cutinds, cutnnz, &cutefficacy, &cutrank, &cutislocal, &cutsuccess) );
    328 (*success) = ((*success) || cutsuccess);
    329
    330 /* the cut is only successful if the efficacy is high enough */
    331 (*success) = (*success) && SCIPisEfficacious(masterprob, cutefficacy);
    332
    333 /* try to tighten the coefficients of the cut */
    334 if( (*success) )
    335 {
    336 SCIP_Bool redundant;
    337 int nchgcoefs;
    338
    339 redundant = SCIPcutsTightenCoefficients(masterprob, FALSE, cutcoefs, cutrhs, cutinds, cutnnz, &nchgcoefs);
    340
    341 (*success) = !redundant;
    342 }
    343
    344 /* freeing the local memory */
    345 SCIPfreeBufferArray(masterprob, &rowinds);
    346 SCIPfreeBufferArray(masterprob, &rowvals);
    347 SCIPaggrRowFree(masterprob, &aggrrow);
    348
    349 return SCIP_OKAY;
    350}
    351
    352/** computes a standard Benders' optimality cut from the dual solutions of the LP */
    353static
    355 SCIP* masterprob, /**< the SCIP instance of the master problem */
    356 SCIP* subproblem, /**< the SCIP instance of the subproblem */
    357 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    358 SCIP_VAR*** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
    359 SCIP_Real** vals, /**< pointer to array of coefficients of the variables in the generated cut */
    360 SCIP_Real* lhs, /**< the left hand side of the cut */
    361 SCIP_Real* rhs, /**< the right hand side of the cut */
    362 int* nvars, /**< the number of variables in the cut */
    363 int* varssize, /**< the number of variables in the array */
    364 SCIP_Real* checkobj, /**< stores the objective function computed from the dual solution */
    365 SCIP_Bool* success /**< was the cut generation successful? */
    366 )
    367{
    368 SCIP_VAR** subvars;
    369 SCIP_VAR** fixedvars;
    370 int nsubvars;
    371 int nfixedvars;
    372 SCIP_Real dualsol;
    373 SCIP_Real addval;
    374 int nrows;
    375 int i;
    376
    377 (*checkobj) = 0;
    378
    379 assert(masterprob != NULL);
    380 assert(subproblem != NULL);
    381 assert(benders != NULL);
    382 assert(vars != NULL);
    383 assert(*vars != NULL);
    384 assert(vals != NULL);
    385 assert(*vals != NULL);
    386
    387 (*success) = FALSE;
    388
    389 /* looping over all LP rows and setting the coefficients of the cut */
    390 nrows = SCIPgetNLPRows(subproblem);
    391 for( i = 0; i < nrows; i++ )
    392 {
    393 SCIP_ROW* lprow;
    394
    395 lprow = SCIPgetLPRows(subproblem)[i];
    396 assert(lprow != NULL);
    397
    398 dualsol = SCIProwGetDualsol(lprow);
    399 assert( !SCIPisInfinity(subproblem, dualsol) && !SCIPisInfinity(subproblem, -dualsol) );
    400
    401 if( SCIPisZero(subproblem, dualsol) )
    402 continue;
    403
    404 if( dualsol > 0.0 )
    405 addval = dualsol*SCIProwGetLhs(lprow);
    406 else
    407 addval = dualsol*SCIProwGetRhs(lprow);
    408
    409 (*lhs) += addval;
    410
    411 /* if the bound becomes infinite, then the cut generation terminates. */
    412 if( SCIPisInfinity(masterprob, (*lhs)) || SCIPisInfinity(masterprob, -(*lhs))
    413 || SCIPisInfinity(masterprob, addval) || SCIPisInfinity(masterprob, -addval))
    414 {
    415 (*success) = FALSE;
    416 SCIPdebugMsg(masterprob, "Infinite bound when generating optimality cut. lhs = %g addval = %g.\n", (*lhs), addval);
    417 return SCIP_OKAY;
    418 }
    419 }
    420
    421 nsubvars = SCIPgetNVars(subproblem);
    422 subvars = SCIPgetVars(subproblem);
    423 nfixedvars = SCIPgetNFixedVars(subproblem);
    424 fixedvars = SCIPgetFixedVars(subproblem);
    425
    426 /* looping over all variables to update the coefficients in the computed cut. */
    427 for( i = 0; i < nsubvars + nfixedvars; i++ )
    428 {
    429 SCIP_VAR* var;
    430 SCIP_VAR* mastervar;
    431 SCIP_Real redcost;
    432
    433 if( i < nsubvars )
    434 var = subvars[i];
    435 else
    436 var = fixedvars[i - nsubvars];
    437
    438 /* retrieving the master problem variable for the given subproblem variable. */
    439 SCIP_CALL( SCIPgetBendersMasterVar(masterprob, benders, var, &mastervar) );
    440
    441 redcost = SCIPgetVarRedcost(subproblem, var);
    442
    443 (*checkobj) += SCIPvarGetUnchangedObj(var)*SCIPvarGetSol(var, TRUE);
    444
    445 /* checking whether the subproblem variable has a corresponding master variable. */
    446 if( mastervar != NULL )
    447 {
    448 SCIP_Real coef;
    449
    450 coef = -1.0*(SCIPvarGetObj(var) + redcost);
    451
    452 if( !SCIPisZero(masterprob, coef) )
    453 {
    454 /* adding the variable to the storage */
    455 SCIP_CALL( addVariableToArray(masterprob, vars, vals, mastervar, coef, nvars, varssize) );
    456 }
    457 }
    458 else
    459 {
    460 if( !SCIPisZero(subproblem, redcost) )
    461 {
    462 addval = 0;
    463
    464 if( SCIPisPositive(subproblem, redcost) )
    465 addval = redcost*SCIPvarGetLbLocal(var);
    466 else if( SCIPisNegative(subproblem, redcost) )
    467 addval = redcost*SCIPvarGetUbLocal(var);
    468
    469 (*lhs) += addval;
    470
    471 /* if the bound becomes infinite, then the cut generation terminates. */
    472 if( SCIPisInfinity(masterprob, (*lhs)) || SCIPisInfinity(masterprob, -(*lhs))
    473 || SCIPisInfinity(masterprob, addval) || SCIPisInfinity(masterprob, -addval))
    474 {
    475 (*success) = FALSE;
    476 SCIPdebugMsg(masterprob, "Infinite bound when generating optimality cut.\n");
    477 return SCIP_OKAY;
    478 }
    479 }
    480 }
    481 }
    482
    483 assert(SCIPisInfinity(masterprob, (*rhs)));
    484 /* the rhs should be infinite. If it changes, then there is an error */
    485 if( !SCIPisInfinity(masterprob, (*rhs)) )
    486 {
    487 (*success) = FALSE;
    488 SCIPdebugMsg(masterprob, "RHS is not infinite. rhs = %g.\n", (*rhs));
    489 return SCIP_OKAY;
    490 }
    491
    492 (*success) = TRUE;
    493
    494 return SCIP_OKAY;
    495}
    496
    497/** computes a standard Benders' optimality cut from the dual solutions of the NLP */
    498static
    500 SCIP* masterprob, /**< the SCIP instance of the master problem */
    501 SCIP* subproblem, /**< the SCIP instance of the subproblem */
    502 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    503 SCIP_VAR*** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
    504 SCIP_Real** vals, /**< pointer to array of coefficients of the variables in the generated cut */
    505 SCIP_Real* lhs, /**< the left hand side of the cut */
    506 SCIP_Real* rhs, /**< the right hand side of the cut */
    507 int* nvars, /**< the number of variables in the cut */
    508 int* varssize, /**< the number of variables in the array */
    509 SCIP_Real objective, /**< the objective function of the subproblem */
    510 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
    511 SCIP_Real* consdualvals, /**< dual variables for the constraints, can be NULL */
    512 SCIP_Real* varlbdualvals, /**< the dual variables for the variable lower bounds, can be NULL */
    513 SCIP_Real* varubdualvals, /**< the dual variables for the variable upper bounds, can be NULL */
    514 SCIP_HASHMAP* row2idx, /**< mapping between the row in the subproblem to the index in the dual array, can be NULL */
    515 SCIP_HASHMAP* var2idx, /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
    516 SCIP_Real* checkobj, /**< stores the objective function computed from the dual solution */
    517 SCIP_Bool* success /**< was the cut generation successful? */
    518 )
    519{
    520 SCIP_VAR** subvars;
    521 SCIP_VAR** fixedvars;
    522 int nsubvars;
    523 int nfixedvars;
    524 SCIP_Real dirderiv;
    525 SCIP_Real dualsol;
    526 int nrows;
    527 int idx;
    528 int i;
    529
    530 (*checkobj) = 0;
    531
    532 assert(masterprob != NULL);
    533 assert(subproblem != NULL);
    534 assert(benders != NULL);
    535 assert(SCIPisNLPConstructed(subproblem));
    536 assert(SCIPgetNLPSolstat(subproblem) <= SCIP_NLPSOLSTAT_FEASIBLE || consdualvals != NULL);
    537 assert(SCIPhasNLPSolution(subproblem) || consdualvals != NULL);
    538
    539 (*success) = FALSE;
    540
    541 if( !(primalvals == NULL && consdualvals == NULL && varlbdualvals == NULL && varubdualvals == NULL && row2idx == NULL && var2idx == NULL)
    542 && !(primalvals != NULL && consdualvals != NULL && varlbdualvals != NULL && varubdualvals != NULL && row2idx != NULL && var2idx != NULL) ) /*lint !e845*/
    543 {
    544 SCIPerrorMessage("The optimality cut must generated from either a SCIP instance or all of the dual solutions and indices must be supplied");
    545 (*success) = FALSE;
    546
    547 return SCIP_ERROR;
    548 }
    549
    550 nsubvars = SCIPgetNNLPVars(subproblem);
    551 subvars = SCIPgetNLPVars(subproblem);
    552 nfixedvars = SCIPgetNFixedVars(subproblem);
    553 fixedvars = SCIPgetFixedVars(subproblem);
    554
    555 /* our optimality cut implementation assumes that SCIP did not modify the objective function and sense,
    556 * that is, that the objective function value of the NLP corresponds to the value of the auxiliary variable
    557 * if that wouldn't be the case, then the scaling and offset may have to be considered when adding the
    558 * auxiliary variable to the cut (cons/row)?
    559 */
    560 assert(SCIPgetTransObjoffset(subproblem) == 0.0);
    561 assert(SCIPgetTransObjscale(subproblem) == 1.0);
    562 assert(SCIPgetObjsense(subproblem) == SCIP_OBJSENSE_MINIMIZE);
    563
    564 (*lhs) = objective;
    565 assert(!SCIPisInfinity(subproblem, REALABS(*lhs)));
    566
    567 (*rhs) = SCIPinfinity(masterprob);
    568
    569 dirderiv = 0.0;
    570
    571 /* looping over all NLP rows and setting the corresponding coefficients of the cut */
    572 nrows = SCIPgetNNLPNlRows(subproblem);
    573 for( i = 0; i < nrows; i++ )
    574 {
    575 SCIP_NLROW* nlrow;
    576
    577 nlrow = SCIPgetNLPNlRows(subproblem)[i];
    578 assert(nlrow != NULL);
    579
    580 if( row2idx != NULL && consdualvals != NULL )
    581 {
    582 assert(SCIPhashmapExists(row2idx, (void*)nlrow) );
    583 idx = SCIPhashmapGetImageInt(row2idx, (void*)nlrow);
    584 dualsol = consdualvals[idx];
    585 }
    586 else
    587 dualsol = SCIPnlrowGetDualsol(nlrow);
    588 assert( !SCIPisInfinity(subproblem, dualsol) && !SCIPisInfinity(subproblem, -dualsol) );
    589
    590 if( SCIPisZero(subproblem, dualsol) )
    591 continue;
    592
    593 SCIP_CALL( SCIPaddNlRowGradientBenderscutOpt(masterprob, subproblem, benders, nlrow,
    594 -dualsol, primalvals, var2idx, &dirderiv, vars, vals, nvars, varssize) );
    595 }
    596
    597 /* looping over sub- and fixed variables to compute checkobj */
    598 for( i = 0; i < nsubvars; i++ )
    599 (*checkobj) += SCIPvarGetObj(subvars[i]) * getNlpVarSol(subvars[i], primalvals, var2idx);
    600
    601 for( i = 0; i < nfixedvars; i++ )
    602 *checkobj += SCIPvarGetUnchangedObj(fixedvars[i]) * getNlpVarSol(fixedvars[i], primalvals, var2idx);
    603
    604 *lhs += dirderiv;
    605
    606 /* if the side became infinite or dirderiv was infinite, then the cut generation terminates. */
    607 if( SCIPisInfinity(masterprob, *lhs) || SCIPisInfinity(masterprob, -*lhs)
    608 || SCIPisInfinity(masterprob, dirderiv) || SCIPisInfinity(masterprob, -dirderiv))
    609 {
    610 (*success) = FALSE;
    611 SCIPdebugMsg(masterprob, "Infinite bound when generating optimality cut. lhs = %g dirderiv = %g.\n", *lhs, dirderiv);
    612 return SCIP_OKAY;
    613 }
    614
    615 (*success) = TRUE;
    616
    617 return SCIP_OKAY;
    618}
    619
    620
    621/** Adds the auxiliary variable to the generated cut. If this is the first optimality cut for the subproblem, then the
    622 * auxiliary variable is first created and added to the master problem.
    623 */
    624static
    626 SCIP* masterprob, /**< the SCIP instance of the master problem */
    627 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    628 SCIP_VAR** vars, /**< the variables in the generated cut with non-zero coefficient */
    629 SCIP_Real* vals, /**< the coefficients of the variables in the generated cut */
    630 int* nvars, /**< the number of variables in the cut */
    631 int probnumber /**< the number of the pricing problem */
    632 )
    633{
    634 SCIP_VAR* auxiliaryvar;
    635
    636 assert(masterprob != NULL);
    637 assert(benders != NULL);
    638 assert(vars != NULL);
    639 assert(vals != NULL);
    640
    641 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
    642
    643 vars[(*nvars)] = auxiliaryvar;
    644 vals[(*nvars)] = 1.0;
    645 (*nvars)++;
    646
    647 return SCIP_OKAY;
    648}
    649
    650
    651/*
    652 * Callback methods of Benders' decomposition cuts
    653 */
    654
    655/** destructor of Benders' decomposition cuts to free user data (called when SCIP is exiting) */
    656static
    657SCIP_DECL_BENDERSCUTFREE(benderscutFreeOpt)
    658{ /*lint --e{715}*/
    659 SCIP_BENDERSCUTDATA* benderscutdata;
    660
    661 assert( benderscut != NULL );
    662 assert( strcmp(SCIPbenderscutGetName(benderscut), BENDERSCUT_NAME) == 0 );
    663
    664 /* free Benders' cut data */
    665 benderscutdata = SCIPbenderscutGetData(benderscut);
    666 assert( benderscutdata != NULL );
    667
    668 SCIPfreeBlockMemory(scip, &benderscutdata);
    669
    670 SCIPbenderscutSetData(benderscut, NULL);
    671
    672 return SCIP_OKAY;
    673}
    674
    675
    676/** execution method of Benders' decomposition cuts */
    677static
    678SCIP_DECL_BENDERSCUTEXEC(benderscutExecOpt)
    679{ /*lint --e{715}*/
    680 SCIP* subproblem;
    681 SCIP_BENDERSCUTDATA* benderscutdata;
    682 SCIP_Bool nlprelaxation;
    683 SCIP_Bool addcut;
    684 char cutname[SCIP_MAXSTRLEN];
    685
    686 assert(scip != NULL);
    687 assert(benders != NULL);
    688 assert(benderscut != NULL);
    689 assert(result != NULL);
    690 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    691
    692 /* retrieving the Benders' cut data */
    693 benderscutdata = SCIPbenderscutGetData(benderscut);
    694
    695 /* if the cuts are generated prior to the solving stage, then rows can not be generated. So constraints must be
    696 * added to the master problem.
    697 */
    699 addcut = FALSE;
    700 else
    701 addcut = benderscutdata->addcuts;
    702
    703 /* setting the name of the generated cut */
    704 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "optimalitycut_%d_%" SCIP_LONGINT_FORMAT, probnumber,
    705 SCIPbenderscutGetNFound(benderscut) );
    706
    707 subproblem = SCIPbendersSubproblem(benders, probnumber);
    708
    709 if( subproblem == NULL )
    710 {
    711 SCIPdebugMsg(scip, "The subproblem %d is set to NULL. The <%s> Benders' decomposition cut can not be executed.\n",
    712 probnumber, BENDERSCUT_NAME);
    713
    714 (*result) = SCIP_DIDNOTRUN;
    715 return SCIP_OKAY;
    716 }
    717
    718 /* setting a flag to indicate whether the NLP relaxation should be used to generate cuts */
    719 nlprelaxation = SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem);
    720
    721 /* only generate optimality cuts if the subproblem LP or NLP is optimal,
    722 * since we use the dual solution of the LP/NLP to construct the optimality cut
    723 */
    724 if( SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING &&
    725 ((!nlprelaxation && SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_OPTIMAL) ||
    726 (nlprelaxation && SCIPgetNLPSolstat(subproblem) <= SCIP_NLPSOLSTAT_FEASIBLE)) )
    727 {
    728 /* generating a cut for a given subproblem */
    729 SCIP_CALL( SCIPgenerateAndApplyBendersOptCut(scip, subproblem, benders, benderscut, sol, probnumber, cutname,
    730 SCIPbendersGetSubproblemObjval(benders, probnumber), NULL, NULL, NULL, NULL, NULL, NULL, type, addcut,
    731 FALSE, result) );
    732
    733 /* if it was not possible to generate a cut, this could be due to numerical issues. So the solution to the LP is
    734 * resolved and the generation of the cut is reattempted. For NLPs, we do not have such a polishing yet.
    735 */
    736 if( (*result) == SCIP_DIDNOTFIND )
    737 {
    738 SCIP_Bool success;
    739
    740 SCIPdebugMsg(scip, "Numerical trouble generating optimality cut for subproblem %d.\n", probnumber);
    741
    742 if( !nlprelaxation )
    743 {
    744 SCIPdebugMsg(scip, "Attempting to polish the LP solution to find an alternative dual extreme point.\n");
    745
    746 SCIP_CALL( polishSolution(subproblem, &success) );
    747
    748 /* only attempt to generate a cut if the solution polishing was successful */
    749 if( success )
    750 {
    751 SCIP_CALL( SCIPgenerateAndApplyBendersOptCut(scip, subproblem, benders, benderscut, sol, probnumber, cutname,
    752 SCIPbendersGetSubproblemObjval(benders, probnumber), NULL, NULL, NULL, NULL, NULL, NULL, type, addcut,
    753 FALSE, result) );
    754 }
    755 }
    756 else
    757 {
    758 SCIP_Real multiplier = 0.01;
    759
    760 SCIPdebugMsg(scip, "Attempting to resolve the NLP with a tighter feasibility tolerance to find an "
    761 "alternative dual extreme point.\n");
    762
    763 while( multiplier > 1e-06 && (*result) == SCIP_DIDNOTFIND )
    764 {
    765 SCIP_CALL( resolveNLPWithTighterFeastol(subproblem, benders, multiplier, &success) );
    766
    767 if( success )
    768 {
    769 SCIP_CALL( SCIPgenerateAndApplyBendersOptCut(scip, subproblem, benders, benderscut, sol, probnumber, cutname,
    770 SCIPbendersGetSubproblemObjval(benders, probnumber), NULL, NULL, NULL, NULL, NULL, NULL, type, addcut,
    771 FALSE, result) );
    772 }
    773
    774 multiplier *= 0.1;
    775 }
    776 }
    777 }
    778 }
    779
    780 return SCIP_OKAY;
    781}
    782
    783
    784/*
    785 * Benders' decomposition cuts specific interface methods
    786 */
    787
    788/** creates the opt Benders' decomposition cuts and includes it in SCIP */
    790 SCIP* scip, /**< SCIP data structure */
    791 SCIP_BENDERS* benders /**< Benders' decomposition */
    792 )
    793{
    794 SCIP_BENDERSCUTDATA* benderscutdata;
    795 SCIP_BENDERSCUT* benderscut;
    797
    798 assert(benders != NULL);
    799
    800 /* create opt Benders' decomposition cuts data */
    801 SCIP_CALL( SCIPallocBlockMemory(scip, &benderscutdata) );
    802
    803 benderscut = NULL;
    804
    805 /* include Benders' decomposition cuts */
    807 BENDERSCUT_PRIORITY, BENDERSCUT_LPCUT, benderscutExecOpt, benderscutdata) );
    808
    809 assert(benderscut != NULL);
    810
    811 /* setting the non fundamental callbacks via setter functions */
    812 SCIP_CALL( SCIPsetBenderscutFree(scip, benderscut, benderscutFreeOpt) );
    813
    814 /* add opt Benders' decomposition cuts parameters */
    815 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/addcuts",
    818 "should cuts be generated and added to the cutpool instead of global constraints directly added to the problem.",
    819 &benderscutdata->addcuts, FALSE, SCIP_DEFAULT_ADDCUTS, NULL, NULL) );
    820
    821 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/mir",
    824 "should the mixed integer rounding procedure be applied to cuts",
    825 &benderscutdata->calcmir, FALSE, SCIP_DEFAULT_CALCMIR, NULL, NULL) );
    826
    827 return SCIP_OKAY;
    828}
    829
    830/** Generates a classical Benders' optimality cut using the dual solutions from the subproblem or the input arrays. If
    831 * the dual solutions are input as arrays, then a mapping between the array indices and the rows/variables is required.
    832 * As a cut strengthening approach, when an optimality cut is being generated (i.e. not for feasibility cuts) a MIR
    833 * procedure is performed on the row. This procedure attempts to find a stronger constraint, if this doesn't happen,
    834 * then the original constraint is added to SCIP.
    835 *
    836 * This method can also be used to generate a feasibility cut, if a problem to minimise the infeasibilities has been solved
    837 * to generate the dual solutions
    838 */
    840 SCIP* masterprob, /**< the SCIP instance of the master problem */
    841 SCIP* subproblem, /**< the SCIP instance of the pricing problem */
    842 SCIP_BENDERS* benders, /**< the benders' decomposition */
    843 SCIP_BENDERSCUT* benderscut, /**< the benders' decomposition cut method */
    844 SCIP_SOL* sol, /**< primal CIP solution */
    845 int probnumber, /**< the number of the pricing problem */
    846 char* cutname, /**< the name for the cut to be generated */
    847 SCIP_Real objective, /**< the objective function of the subproblem */
    848 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
    849 SCIP_Real* consdualvals, /**< dual variables for the constraints, can be NULL */
    850 SCIP_Real* varlbdualvals, /**< the dual variables for the variable lower bounds, can be NULL */
    851 SCIP_Real* varubdualvals, /**< the dual variables for the variable upper bounds, can be NULL */
    852 SCIP_HASHMAP* row2idx, /**< mapping between the row in the subproblem to the index in the dual array, can be NULL */
    853 SCIP_HASHMAP* var2idx, /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
    854 SCIP_BENDERSENFOTYPE type, /**< the enforcement type calling this function */
    855 SCIP_Bool addcut, /**< should the Benders' cut be added as a cut or constraint */
    856 SCIP_Bool feasibilitycut, /**< is this called for the generation of a feasibility cut */
    857 SCIP_RESULT* result /**< the result from solving the subproblems */
    858 )
    859{
    860 SCIP_CONSHDLR* consbenders;
    861 SCIP_CONS* cons;
    862 SCIP_ROW* row;
    863 SCIP_VAR** vars;
    864 SCIP_Real* vals;
    865 SCIP_Real lhs;
    866 SCIP_Real rhs;
    867 int nvars;
    868 int varssize;
    869 int nmastervars;
    870 SCIP_Bool calcmir;
    871 SCIP_Bool optimal;
    872 SCIP_Bool success;
    873 SCIP_Bool mirsuccess;
    874
    875 SCIP_Real checkobj;
    876 SCIP_Real verifyobj;
    877
    878 assert(masterprob != NULL);
    879 assert(subproblem != NULL);
    880 assert(benders != NULL);
    881 assert(benderscut != NULL);
    882 assert(result != NULL);
    883 assert((primalvals == NULL && consdualvals == NULL && varlbdualvals == NULL && varubdualvals == NULL
    884 && row2idx == NULL && var2idx == NULL)
    885 || (primalvals != NULL && consdualvals != NULL && varlbdualvals != NULL && varubdualvals != NULL
    886 && row2idx != NULL && var2idx != NULL));
    887
    888 row = NULL;
    889 cons = NULL;
    890
    891 calcmir = SCIPbenderscutGetData(benderscut)->calcmir && SCIPgetStage(masterprob) >= SCIP_STAGE_INITSOLVE && SCIPgetSubscipDepth(masterprob) == 0;
    892 success = FALSE;
    893 mirsuccess = FALSE;
    894
    895 /* retrieving the Benders' decomposition constraint handler */
    896 consbenders = SCIPfindConshdlr(masterprob, "benders");
    897
    898 /* checking the optimality of the original problem with a comparison between the auxiliary variable and the
    899 * objective value of the subproblem */
    900 if( feasibilitycut )
    901 optimal = FALSE;
    902 else
    903 {
    904 SCIP_CALL( SCIPcheckBendersSubproblemOptimality(masterprob, benders, sol, probnumber, &optimal) );
    905 }
    906
    907 if( optimal )
    908 {
    909 (*result) = SCIP_FEASIBLE;
    910 SCIPdebugMsg(masterprob, "No cut added for subproblem %d\n", probnumber);
    911 return SCIP_OKAY;
    912 }
    913
    914 /* allocating memory for the variable and values arrays */
    915 nmastervars = SCIPgetNVars(masterprob) + SCIPgetNFixedVars(masterprob);
    916 SCIP_CALL( SCIPallocClearBufferArray(masterprob, &vars, nmastervars) );
    917 SCIP_CALL( SCIPallocClearBufferArray(masterprob, &vals, nmastervars) );
    918 lhs = 0.0;
    919 rhs = SCIPinfinity(masterprob);
    920 nvars = 0;
    921 varssize = nmastervars;
    922
    923 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) )
    924 {
    925 /* computing the coefficients of the optimality cut */
    926 SCIP_CALL( computeStandardNLPOptimalityCut(masterprob, subproblem, benders, &vars, &vals, &lhs, &rhs, &nvars,
    927 &varssize, objective, primalvals, consdualvals, varlbdualvals, varubdualvals, row2idx,
    928 var2idx, &checkobj, &success) );
    929 }
    930 else
    931 {
    932 /* computing the coefficients of the optimality cut */
    933 SCIP_CALL( computeStandardLPOptimalityCut(masterprob, subproblem, benders, &vars, &vals, &lhs, &rhs, &nvars,
    934 &varssize, &checkobj, &success) );
    935 }
    936
    937 /* if success is FALSE, then there was an error in generating the optimality cut. No cut will be added to the master
    938 * problem. Otherwise, the constraint is added to the master problem.
    939 */
    940 if( !success )
    941 {
    942 (*result) = SCIP_DIDNOTFIND;
    943 SCIPdebugMsg(masterprob, "Error in generating Benders' optimality cut for problem %d.\n", probnumber);
    944 }
    945 else
    946 {
    947 /* initially a row/constraint is created for the optimality cut using the master variables and coefficients
    948 * computed in computeStandardLPOptimalityCut. At this stage, the auxiliary variable is not added since the
    949 * activity of the row/constraint in its current form is used to determine the validity of the optimality cut.
    950 */
    951 if( addcut )
    952 {
    953 SCIP_CALL( SCIPcreateEmptyRowConshdlr(masterprob, &row, consbenders, cutname, lhs, rhs, FALSE, FALSE, TRUE) );
    954 SCIP_CALL( SCIPaddVarsToRow(masterprob, row, nvars, vars, vals) );
    955 }
    956 else
    957 {
    958 SCIP_CALL( SCIPcreateConsBasicLinear(masterprob, &cons, cutname, nvars, vars, vals, lhs, rhs) );
    959 SCIP_CALL( SCIPsetConsDynamic(masterprob, cons, TRUE) );
    960 SCIP_CALL( SCIPsetConsRemovable(masterprob, cons, TRUE) );
    961 }
    962
    963 /* computing the objective function from the cut activity to verify the accuracy of the constraint */
    964 verifyobj = 0.0;
    965 if( addcut )
    966 {
    967 verifyobj += SCIProwGetLhs(row) - SCIPgetRowSolActivity(masterprob, row, sol);
    968 }
    969 else
    970 {
    971 verifyobj += SCIPgetLhsLinear(masterprob, cons) - SCIPgetActivityLinear(masterprob, cons, sol);
    972 }
    973
    974 if( feasibilitycut && verifyobj < SCIPfeastol(masterprob) )
    975 {
    976 success = FALSE;
    977 SCIPdebugMsg(masterprob, "The violation of the feasibility cut (%g) is too small. Skipping feasibility cut.\n", verifyobj);
    978 }
    979
    980 /* it is possible that numerics will cause the generated cut to be invalid. This cut should not be added to the
    981 * master problem, since its addition could cut off feasible solutions. The success flag is set of false, indicating
    982 * that the Benders' cut could not find a valid cut.
    983 */
    984 if( !feasibilitycut && !SCIPisFeasEQ(masterprob, checkobj, verifyobj) )
    985 {
    986 SCIP_Bool valid;
    987
    988 /* the difference in the checkobj and verifyobj could be due to the setup tolerances. This is checked, and if
    989 * so, then the generated cut is still valid
    990 */
    991 SCIP_CALL( checkSetupTolerances(masterprob, sol, vars, vals, lhs, checkobj, nvars, &valid) );
    992
    993 if( !valid )
    994 {
    995 success = FALSE;
    996 SCIPdebugMsg(masterprob, "The objective function and cut activity are not equal (%g != %g).\n", checkobj,
    997 verifyobj);
    998
    999#ifdef SCIP_DEBUG
    1000 /* we only need to abort if cut strengthen is not used. If cut strengthen has been used in this round and the
    1001 * cut could not be generated, then another subproblem solving round will be executed
    1002 */
    1003 if( !SCIPbendersInStrengthenRound(benders) )
    1004 {
    1005#ifdef SCIP_MOREDEBUG
    1006 int i;
    1007
    1008 for( i = 0; i < nvars; i++ )
    1009 printf("<%s> %g %g\n", SCIPvarGetName(vars[i]), vals[i], SCIPgetSolVal(masterprob, sol, vars[i]));
    1010#endif
    1011 SCIPABORT();
    1012 }
    1013#endif
    1014 }
    1015 }
    1016
    1017 if( success )
    1018 {
    1019 /* adding the auxiliary variable to the optimality cut. The auxiliary variable is added to the vars and vals
    1020 * arrays prior to the execution of the MIR procedure. This is necessary because the MIR procedure must be
    1021 * executed on the complete cut, not just the row/constraint without the auxiliary variable.
    1022 */
    1023 if( !feasibilitycut )
    1024 {
    1025 SCIP_CALL( addAuxiliaryVariableToCut(masterprob, benders, vars, vals, &nvars, probnumber) );
    1026 }
    1027
    1028 /* performing the MIR procedure. If the procedure is successful, then the vars and vals arrays are no longer
    1029 * needed for creating the optimality cut. These are superseeded with the cutcoefs and cutinds arrays. In the
    1030 * case that the MIR procedure is successful, the row/constraint that has been created previously is destroyed
    1031 * and the MIR cut is added in its place
    1032 */
    1033 if( calcmir )
    1034 {
    1035 SCIP_Real* cutcoefs;
    1036 int* cutinds;
    1037 SCIP_Real cutrhs;
    1038 int cutnnz;
    1039
    1040 /* allocating memory to compute the MIR cut */
    1041 SCIP_CALL( SCIPallocBufferArray(masterprob, &cutcoefs, nvars) );
    1042 SCIP_CALL( SCIPallocBufferArray(masterprob, &cutinds, nvars) );
    1043
    1044 SCIP_CALL( computeMIRForOptimalityCut(masterprob, sol, vars, vals, lhs, rhs, nvars, cutcoefs,
    1045 cutinds, &cutrhs, &cutnnz, &mirsuccess) );
    1046
    1047 /* if the MIR cut was computed successfully, then the current row/constraint needs to be destroyed and
    1048 * replaced with the updated coefficients
    1049 */
    1050 if( mirsuccess )
    1051 {
    1052 SCIP_VAR** mastervars;
    1053 int i;
    1054
    1055 mastervars = SCIPgetVars(masterprob);
    1056
    1057 if( addcut )
    1058 {
    1059 SCIP_CALL( SCIPreleaseRow(masterprob, &row) );
    1060
    1061 SCIP_CALL( SCIPcreateEmptyRowConshdlr(masterprob, &row, consbenders, cutname,
    1062 -SCIPinfinity(masterprob), cutrhs, FALSE, FALSE, TRUE) );
    1063
    1064 for( i = 0; i < cutnnz; i++)
    1065 {
    1066 SCIP_CALL( SCIPaddVarToRow(masterprob, row, mastervars[cutinds[i]], cutcoefs[i]) );
    1067 }
    1068 }
    1069 else
    1070 {
    1071 SCIP_CALL( SCIPreleaseCons(masterprob, &cons) );
    1072
    1073 SCIP_CALL( SCIPcreateConsBasicLinear(masterprob, &cons, cutname, 0, NULL, NULL,
    1074 -SCIPinfinity(masterprob), cutrhs) );
    1075 SCIP_CALL( SCIPsetConsDynamic(masterprob, cons, TRUE) );
    1076 SCIP_CALL( SCIPsetConsRemovable(masterprob, cons, TRUE) );
    1077
    1078 for( i = 0; i < cutnnz; i++ )
    1079 {
    1080 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, mastervars[cutinds[i]], cutcoefs[i]) );
    1081 }
    1082 }
    1083 }
    1084
    1085 /* freeing the memory required to compute the MIR cut */
    1086 SCIPfreeBufferArray(masterprob, &cutinds);
    1087 SCIPfreeBufferArray(masterprob, &cutcoefs);
    1088 }
    1089
    1090 /* adding the constraint to the master problem */
    1091 if( addcut )
    1092 {
    1093 SCIP_Bool infeasible;
    1094
    1095 /* adding the auxiliary variable coefficient to the row. This is only added if the MIR procedure is not
    1096 * successful. If the MIR procedure was successful, then the auxiliary variable is already included in the
    1097 * row
    1098 */
    1099 if( !feasibilitycut && !mirsuccess )
    1100 {
    1101 SCIP_CALL( SCIPaddVarToRow(masterprob, row, vars[nvars - 1], vals[nvars - 1]) );
    1102 }
    1103
    1105 {
    1106 SCIP_CALL( SCIPaddRow(masterprob, row, FALSE, &infeasible) );
    1107 assert(!infeasible);
    1108 }
    1109 else
    1110 {
    1112 SCIP_CALL( SCIPaddPoolCut(masterprob, row) );
    1113 }
    1114
    1115 (*result) = SCIP_SEPARATED;
    1116 }
    1117 else
    1118 {
    1119 /* adding the auxiliary variable coefficient to the row. This is only added if the MIR procedure is not
    1120 * successful. If the MIR procedure was successful, then the auxiliary variable is already included in the
    1121 * constraint.
    1122 */
    1123 if( !feasibilitycut && !mirsuccess )
    1124 {
    1125 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, vars[nvars - 1], vals[nvars - 1]) );
    1126 }
    1127
    1128 SCIPdebugPrintCons(masterprob, cons, NULL);
    1129
    1130 SCIP_CALL( SCIPaddCons(masterprob, cons) );
    1131
    1132 (*result) = SCIP_CONSADDED;
    1133 }
    1134
    1135 /* storing the data that is used to create the cut */
    1136 SCIP_CALL( SCIPstoreBendersCut(masterprob, benders, vars, vals, lhs, rhs, nvars) );
    1137 }
    1138 else
    1139 {
    1140 (*result) = SCIP_DIDNOTFIND;
    1141 SCIPdebugMsg(masterprob, "Error in generating Benders' %s cut for problem %d.\n", feasibilitycut ? "feasibility" : "optimality", probnumber);
    1142 }
    1143
    1144 /* releasing the row or constraint */
    1145 if( addcut )
    1146 {
    1147 /* release the row */
    1148 SCIP_CALL( SCIPreleaseRow(masterprob, &row) );
    1149 }
    1150 else
    1151 {
    1152 /* release the constraint */
    1153 SCIP_CALL( SCIPreleaseCons(masterprob, &cons) );
    1154 }
    1155 }
    1156
    1157 SCIPfreeBufferArray(masterprob, &vals);
    1158 SCIPfreeBufferArray(masterprob, &vars);
    1159
    1160 return SCIP_OKAY;
    1161}
    1162
    1163
    1164/** 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
    1165 *
    1166 * Only computes gradient w.r.t. master problem variables.
    1167 * Computes also the directional derivative, that is, mult times gradient times solution.
    1168 */
    1170 SCIP* masterprob, /**< the SCIP instance of the master problem */
    1171 SCIP* subproblem, /**< the SCIP instance of the subproblem */
    1172 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    1173 SCIP_NLROW* nlrow, /**< nonlinear row */
    1174 SCIP_Real mult, /**< multiplier */
    1175 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
    1176 SCIP_HASHMAP* var2idx, /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
    1177 SCIP_Real* dirderiv, /**< storage to add directional derivative */
    1178 SCIP_VAR*** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
    1179 SCIP_Real** vals, /**< pointer to array of coefficients of the variables in the generated cut */
    1180 int* nvars, /**< the number of variables in the cut */
    1181 int* varssize /**< the number of variables in the array */
    1182 )
    1183{
    1184 SCIP_EXPR* expr;
    1185 SCIP_VAR* var;
    1186 SCIP_VAR* mastervar;
    1187 SCIP_Real coef;
    1188 int i;
    1189
    1190 assert(masterprob != NULL);
    1191 assert(subproblem != NULL);
    1192 assert(benders != NULL);
    1193 assert(nlrow != NULL);
    1194 assert((primalvals == NULL && var2idx == NULL) || (primalvals != NULL && var2idx != NULL));
    1195 assert(mult != 0.0);
    1196 assert(dirderiv != NULL);
    1197 assert(vars != NULL);
    1198 assert(vals != NULL);
    1199
    1200 /* linear part */
    1201 for( i = 0; i < SCIPnlrowGetNLinearVars(nlrow); i++ )
    1202 {
    1203 var = SCIPnlrowGetLinearVars(nlrow)[i];
    1204 assert(var != NULL);
    1205
    1206 /* retrieving the master problem variable for the given subproblem variable. */
    1207 SCIP_CALL( SCIPgetBendersMasterVar(masterprob, benders, var, &mastervar) );
    1208 if( mastervar == NULL )
    1209 continue;
    1210
    1211 coef = mult * SCIPnlrowGetLinearCoefs(nlrow)[i];
    1212
    1213 /* adding the variable to the storage */
    1214 SCIP_CALL( addVariableToArray(masterprob, vars, vals, mastervar, coef, nvars, varssize) );
    1215
    1216 *dirderiv += coef * getNlpVarSol(var, primalvals, var2idx);
    1217 }
    1218
    1219 /* expression part */
    1220 expr = SCIPnlrowGetExpr(nlrow);
    1221 if( expr != NULL )
    1222 {
    1223 SCIP_SOL* primalsol;
    1224 SCIP_EXPRITER* it;
    1225
    1226 /* create primalsol, either from primalvals, or pointing to NLP solution */
    1227 if( primalvals != NULL )
    1228 {
    1229 SCIP_CALL( SCIPcreateSol(subproblem, &primalsol, NULL) );
    1230
    1231 /* 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 */
    1232 for( i = 0; i < SCIPhashmapGetNEntries(var2idx); ++i )
    1233 {
    1234 SCIP_HASHMAPENTRY* entry;
    1235 entry = SCIPhashmapGetEntry(var2idx, i);
    1236 if( entry == NULL )
    1237 continue;
    1238 SCIP_CALL( SCIPsetSolVal(subproblem, primalsol, (SCIP_VAR*) SCIPhashmapEntryGetOrigin(entry), primalvals[SCIPhashmapEntryGetImageInt(entry)]) );
    1239 }
    1240 }
    1241 else
    1242 {
    1243 SCIP_CALL( SCIPcreateNLPSol(subproblem, &primalsol, NULL) );
    1244 }
    1245
    1246 /* eval gradient */
    1247 SCIP_CALL( SCIPevalExprGradient(subproblem, expr, primalsol, 0L) );
    1248
    1249 assert(SCIPexprGetDerivative(expr) != SCIP_INVALID); /* TODO this should be a proper check&abort */ /*lint !e777*/
    1250
    1251 SCIP_CALL( SCIPfreeSol(subproblem, &primalsol) );
    1252
    1253 /* update corresponding gradient entry */
    1254 SCIP_CALL( SCIPcreateExpriter(subproblem, &it) );
    1256 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) ) /*lint !e441*/ /*lint !e440*/
    1257 {
    1258 if( !SCIPisExprVar(subproblem, expr) )
    1259 continue;
    1260
    1261 var = SCIPgetVarExprVar(expr);
    1262 assert(var != NULL);
    1263
    1264 /* retrieving the master problem variable for the given subproblem variable. */
    1265 SCIP_CALL( SCIPgetBendersMasterVar(masterprob, benders, var, &mastervar) );
    1266 if( mastervar == NULL )
    1267 continue;
    1268
    1269 assert(SCIPexprGetDerivative(expr) != SCIP_INVALID); /*lint !e777*/
    1270 coef = mult * SCIPexprGetDerivative(expr);
    1271
    1272 /* adding the variable to the storage */
    1273 SCIP_CALL( addVariableToArray(masterprob, vars, vals, mastervar, coef, nvars, varssize) );
    1274
    1275 *dirderiv += coef * getNlpVarSol(var, primalvals, var2idx);
    1276 }
    1277 SCIPfreeExpriter(&it);
    1278 }
    1279
    1280 return SCIP_OKAY;
    1281}
    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)
    static SCIP_RETCODE computeStandardLPOptimalityCut(SCIP *masterprob, SCIP *subproblem, SCIP_BENDERS *benders, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_Real *lhs, SCIP_Real *rhs, int *nvars, int *varssize, SCIP_Real *checkobj, SCIP_Bool *success)
    #define BENDERSCUT_LPCUT
    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_RETCODE computeStandardNLPOptimalityCut(SCIP *masterprob, SCIP *subproblem, SCIP_BENDERS *benders, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_Real *lhs, SCIP_Real *rhs, 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_DECL_BENDERSCUTEXEC(benderscutExecOpt)
    static SCIP_Real getNlpVarSol(SCIP_VAR *var, SCIP_Real *primalvals, SCIP_HASHMAP *var2idx)
    #define BENDERSCUT_PRIORITY
    #define BENDERSCUT_DESC
    #define BENDERSCUT_NAME
    static SCIP_RETCODE computeMIRForOptimalityCut(SCIP *masterprob, SCIP_SOL *sol, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, int nvars, SCIP_Real *cutcoefs, int *cutinds, SCIP_Real *cutrhs, int *cutnnz, SCIP_Bool *success)
    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:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_Bool
    Definition: def.h:91
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIPABORT()
    Definition: def.h:327
    #define REALABS(x)
    Definition: def.h:182
    #define SCIP_CALL(x)
    Definition: def.h:355
    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:2588
    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:6213
    SCIP_NLPPARAM SCIPbendersGetNLPParam(SCIP_BENDERS *benders)
    Definition: benders.c:5047
    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:5967
    int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6011
    SCIP * SCIPbendersSubproblem(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6021
    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:6302
    SCIP_Bool SCIPbendersInStrengthenRound(SCIP_BENDERS *benders)
    Definition: benders.c:6550
    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:7923
    SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
    Definition: cuts.c:2466
    SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2668
    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:3143
    void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2700
    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:11645
    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:424
    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:516
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1252
    SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
    Definition: scip_sol.c:2349
    SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:664
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1571
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Real 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:19007
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23900
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23662
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24234
    SCIP_Real SCIPgetVarRedcost(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:2608
    SCIP_Real SCIPvarGetNLPSol(SCIP_VAR *var)
    Definition: var.c:24691
    SCIP_Real SCIPvarGetUnchangedObj(SCIP_VAR *var)
    Definition: var.c:23932
    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_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