SCIP

    Solving Constraint Integer Programs

    heur_trustregion.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 heur_trustregion.c
    26 * @ingroup DEFPLUGINS_HEUR
    27 * @brief Large neighborhood search heuristic for Benders' decomposition based on trust region methods
    28 * @author Stephen J. Maher
    29 *
    30 * The Trust Region heuristic draws upon trust region methods for solving optimization problems, especially in the
    31 * context of Benders' decomposition. This heuristic has been developed to improve the heuristic performance of the
    32 * Benders' decomposition algorithm within SCIP.
    33 *
    34 * The Trust Region heuristic copies the original SCIP instance and adds a constraint to penalize changes from the
    35 * incumbent solution. Consider a problem that includes a set of binary variables \f$\mathcal{B}\f$. Given a feasible
    36 * solution \f$\hat{x}\f$ to the original problem, we define the set \f$\mathcal{B}^{+}\f$ as the index set for the
    37 * binary variables that are 1 in the input solution and \f$\mathcal{B}^{-}\f$ as the index set for binary variables
    38 * that are 0. The trust region constraint, which is added to the sub-SCIP, is given by
    39 *
    40 * \f[
    41 * \sum_{i \in \mathcal{B}^{+}}(1 - x_{i}) + \sum_{i \in \mathcal{B}^{-}}x_{i} \le \theta
    42 * \f]
    43 *
    44 * The variable \f$\theta\f$ measure the distance, in terms of the binary variables, of candidate solutions to the input
    45 * solution.
    46 *
    47 * In addition, an upper bounding constraint is explicitly added to enforce a minimum improvement from the heuristic,
    48 * given by \f$f(x) \le f(\hat{x}) - \epsilon\f$. The parameter \f$\epsilon \ge 0\f$ denotes the minimum improvement
    49 * that must be achieved by the heuristic.
    50 *
    51 * The objective function is then modified to \f$f(x) + M\theta\f$, where \f$M\f$ is a parameter for penalizing the
    52 * distance of solutions from the input solution \f$\hat{x}\f$.
    53 *
    54 * If a new incumbent solution is found by this heuristic, then the Trust Region heuristic is immediately
    55 * re-executed with this new incumbent solution.
    56 */
    57
    58/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    59
    61#include "scip/cons_linear.h"
    62#include "scip/heuristics.h"
    64#include "scip/pub_event.h"
    65#include "scip/pub_heur.h"
    66#include "scip/pub_message.h"
    67#include "scip/pub_misc.h"
    68#include "scip/pub_sol.h"
    69#include "scip/pub_var.h"
    70#include "scip/scip_branch.h"
    71#include "scip/scip_cons.h"
    72#include "scip/scip_copy.h"
    73#include "scip/scip_event.h"
    74#include "scip/scip_general.h"
    75#include "scip/scip_heur.h"
    76#include "scip/scip_mem.h"
    77#include "scip/scip_message.h"
    78#include "scip/scip_nodesel.h"
    79#include "scip/scip_numerics.h"
    80#include "scip/scip_param.h"
    81#include "scip/scip_prob.h"
    82#include "scip/scip_sol.h"
    83#include "scip/scip_solve.h"
    85#include "scip/scip_var.h"
    86
    87
    88#define HEUR_NAME "trustregion"
    89#define HEUR_DESC "LNS heuristic for Benders' decomposition based on trust region methods"
    90#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_LNS
    91#define HEUR_PRIORITY -1102010
    92#define HEUR_FREQ -1
    93#define HEUR_FREQOFS 0
    94#define HEUR_MAXDEPTH -1
    95#define HEUR_TIMING SCIP_HEURTIMING_AFTERNODE
    96#define HEUR_USESSUBSCIP TRUE /**< does the heuristic use a secondary SCIP instance? */
    97
    98#define DEFAULT_MINBINVARS 10 /**< the minimum number of binary variables necessary to run the heuristic */
    99#define DEFAULT_NODESOFS 1000 /**< number of nodes added to the contingent of the total nodes */
    100#define DEFAULT_MAXNODES 10000 /**< maximum number of nodes to regard in the subproblem */
    101#define DEFAULT_MINNODES 100 /**< minimum number of nodes required to start the subproblem */
    102#define DEFAULT_NODESQUOT 0.05 /**< contingent of sub problem nodes in relation to original nodes */
    103#define DEFAULT_LPLIMFAC 1.5 /**< factor by which the limit on the number of LP depends on the node limit */
    104#define DEFAULT_NWAITINGNODES 1 /**< number of nodes without incumbent change that heuristic should wait */
    105#define DEFAULT_USELPROWS FALSE /**< should subproblem be created out of the rows in the LP rows,
    106 * otherwise, the copy constructors of the constraints handlers are used */
    107#define DEFAULT_COPYCUTS TRUE /**< if DEFAULT_USELPROWS is FALSE, then should all active cuts from the cutpool
    108 * of the original scip be copied to constraints of the subscip */
    109#define DEFAULT_BESTSOLLIMIT 3 /**< limit on number of improving incumbent solutions in sub-CIP */
    110
    111#define DEFAULT_VIOLPENALTY 100.0 /**< the penalty for violating the trust region */
    112#define DEFAULT_OBJMINIMPROVE 1e-2 /**< the minimum absolute improvement in the objective function value */
    113
    114/* event handler properties */
    115#define EVENTHDLR_NAME "Trustregion"
    116#define EVENTHDLR_DESC "LP event handler for " HEUR_NAME " heuristic"
    117
    118
    119#define EXECUTE 0
    120#define WAITFORNEWSOL 1
    121
    122
    123/*
    124 * Data structures
    125 */
    126
    127/** primal heuristic data */
    128struct SCIP_HeurData
    129{
    130 SCIP_SOL* lastsol; /**< the last incumbent trustregion used as reference point */
    131 SCIP_Longint usednodes; /**< amount of nodes trust region used during all calls */
    132 SCIP_Real nodesquot; /**< contingent of sub problem nodes in relation to original nodes */
    133 SCIP_Real nodelimit; /**< the nodelimit employed in the current sub-SCIP, for the event handler*/
    134 SCIP_Real lplimfac; /**< factor by which the limit on the number of LP depends on the node limit */
    135 SCIP_Real violpenalty; /**< the penalty for violating the trust region */
    136 SCIP_Real objminimprove; /**< the minimum absolute improvement in the objective function value */
    137 int nwaitingnodes; /**< number of nodes without incumbent change that heuristic should wait */
    138 int nodesofs; /**< number of nodes added to the contingent of the total nodes */
    139 int minnodes; /**< minimum number of nodes required to start the subproblem */
    140 int maxnodes; /**< maximum number of nodes to regard in the subproblem */
    141 int minbinvars; /**< minimum number of binary variables necessary to run the heuristic */
    142 int callstatus; /**< current status of trustregion heuristic */
    143 int curminnodes; /**< current minimal number of nodes required to start the subproblem */
    144 int bestsollimit; /**< limit on number of improving incumbent solutions in sub-CIP */
    145 SCIP_Bool uselprows; /**< should subproblem be created out of the rows in the LP rows? */
    146 SCIP_Bool copycuts; /**< if uselprows == FALSE, should all active cuts from cutpool be copied
    147 * to constraints in subproblem? */
    148};
    149
    150
    151/*
    152 * Local methods
    153 */
    154
    155/** create the extra constraint of trust region and add it to \p subscip */
    156static
    158 SCIP* scip, /**< SCIP data structure of the original problem */
    159 SCIP* subscip, /**< SCIP data structure of the subproblem */
    160 SCIP_VAR** subvars, /**< variables of the subproblem */
    161 SCIP_HEURDATA* heurdata /**< heuristic's data structure */
    162 )
    163{
    164 SCIP_CONS* cons; /* trust region constraint to create */
    165 SCIP_VAR** consvars;
    166 SCIP_VAR** vars;
    167 SCIP_SOL* bestsol;
    168
    169 int nvars;
    170 int nbinvars;
    171 int nconsvars;
    172 int i;
    173 SCIP_Real lhs;
    174 SCIP_Real rhs;
    175 SCIP_Real* consvals;
    176 char name[SCIP_MAXSTRLEN];
    177
    178 /* adding the neighborhood constraint for the trust region heuristic */
    179 SCIP_CALL( SCIPaddTrustregionNeighborhoodConstraint(scip, subscip, subvars, heurdata->violpenalty) );
    180
    181 /* get the data of the variables and the best solution */
    182 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, NULL, NULL, NULL) );
    183 bestsol = SCIPgetBestSol(scip);
    184 assert( bestsol != NULL );
    185
    186 /* memory allocation */
    187 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nvars + 1) );
    188 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nvars + 1) );
    189 nconsvars = 0;
    190
    191 /* create the upper bounding constraint. An absolute minimum improvement is used for this heuristic. This is
    192 * different to other LNS heuristics, where a relative improvement is used. The absolute improvement tries to take
    193 * into account problem specific information that is available to the user, such as a minimum step in the objective
    194 * limit if the objective function is integer
    195 */
    196 lhs = -SCIPinfinity(subscip);
    197 rhs = SCIPgetSolTransObj(scip, bestsol) - heurdata->objminimprove;
    198
    199 /* if the objective function is integer, then the floor of the RHS is taken */
    201 rhs = SCIPfeasFloor(scip, rhs);
    202
    203 /* adding the coefficients to the upper bounding constraint */
    204 for( i = 0; i < nvars; i++ )
    205 {
    206 if( subvars[i] == NULL )
    207 continue;
    208 consvals[nconsvars] = SCIPvarGetObj(subvars[i]);
    209 consvars[nconsvars] = subvars[i];
    210 ++nconsvars;
    211 }
    212
    213 /* creates trustregion constraint and adds it to subscip */
    214 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_upperboundcons", SCIPgetProbName(scip));
    215
    216 SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, name, nconsvars, consvars, consvals,
    217 lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
    218 SCIP_CALL( SCIPaddCons(subscip, cons) );
    219 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
    220
    221 /* free local memory */
    222 SCIPfreeBufferArray(scip, &consvals);
    223 SCIPfreeBufferArray(scip, &consvars);
    224
    225 return SCIP_OKAY;
    226}
    227
    228
    229/* ---------------- Callback methods of event handler ---------------- */
    230
    231/** event handler execution callback to interrupt the solution process */
    232static
    233SCIP_DECL_EVENTEXEC(eventExecTrustregion)
    234{
    235 SCIP_HEURDATA* heurdata;
    236
    237 assert(eventhdlr != NULL);
    238 assert(eventdata != NULL);
    239 assert(event != NULL);
    241
    243
    244 heurdata = (SCIP_HEURDATA*)eventdata;
    245 assert(heurdata != NULL);
    246
    247 /* interrupt solution process of sub-SCIP */
    248 if( SCIPgetNLPs(scip) > heurdata->lplimfac * heurdata->nodelimit )
    249 {
    250 SCIPdebugMsg(scip, "interrupt after %" SCIP_LONGINT_FORMAT " LPs\n",SCIPgetNLPs(scip));
    252 }
    253
    254 return SCIP_OKAY;
    255}
    256
    257
    258/*
    259 * Callback methods of primal heuristic
    260 */
    261
    262/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    263static
    264SCIP_DECL_HEURCOPY(heurCopyTrustregion)
    265{ /*lint --e{715}*/
    266 assert(scip != NULL);
    267 assert(heur != NULL);
    268
    270
    271 /* call inclusion method of primal heuristic */
    273
    274 return SCIP_OKAY;
    275}
    276
    277/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    278static
    279SCIP_DECL_HEURFREE(heurFreeTrustregion)
    280{ /*lint --e{715}*/
    281 SCIP_HEURDATA* heurdata;
    282
    283 assert( heur != NULL );
    284 assert( scip != NULL );
    285
    286 /* get heuristic data */
    287 heurdata = SCIPheurGetData(heur);
    288 assert( heurdata != NULL );
    289
    290 /* free heuristic data */
    291 SCIPfreeBlockMemory(scip, &heurdata);
    292 SCIPheurSetData(heur, NULL);
    293
    294 return SCIP_OKAY;
    295}
    296
    297
    298/** initialization method of primal heuristic (called after problem was transformed) */
    299static
    300SCIP_DECL_HEURINIT(heurInitTrustregion)
    301{ /*lint --e{715}*/
    302 SCIP_HEURDATA* heurdata;
    303
    304 assert( heur != NULL );
    305 assert( scip != NULL );
    306
    307 /* get heuristic's data */
    308 heurdata = SCIPheurGetData(heur);
    309 assert( heurdata != NULL );
    310
    311 /* with a little abuse we initialize the heurdata as if trustregion would have finished its last step regularly */
    312 heurdata->callstatus = WAITFORNEWSOL;
    313 heurdata->lastsol = NULL;
    314 heurdata->usednodes = 0;
    315 heurdata->curminnodes = heurdata->minnodes;
    316
    317 return SCIP_OKAY;
    318}
    319
    320/** sets up and solves the sub SCIP for the Trust Region heuristic */
    321static
    323 SCIP* scip, /**< SCIP data structure */
    324 SCIP* subscip, /**< the subproblem created by trustregion */
    325 SCIP_HEUR* heur, /**< trustregion heuristic */
    326 SCIP_Longint nsubnodes, /**< nodelimit for subscip */
    327 SCIP_RESULT* result /**< result pointer */
    328 )
    329{
    330 SCIP_VAR** subvars;
    331 SCIP_EVENTHDLR* eventhdlr;
    332 SCIP_HEURDATA* heurdata;
    333 SCIP_HASHMAP* varmapfw;
    334 SCIP_VAR** vars;
    335
    336 int nvars;
    337 int i;
    338
    339 SCIP_Bool success;
    340
    341 assert(scip != NULL);
    342 assert(subscip != NULL);
    343 assert(heur != NULL);
    344
    345 heurdata = SCIPheurGetData(heur);
    346 assert(heurdata != NULL);
    347
    348 /* get the data of the variables and the best solution */
    349 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    350
    351 /* create the variable mapping hash map */
    352 SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), nvars) );
    353 success = FALSE;
    354
    355 /* create a problem copy as sub SCIP */
    356 SCIP_CALL( SCIPcopyLargeNeighborhoodSearch(scip, subscip, varmapfw, "trustregion", NULL, NULL, 0, heurdata->uselprows,
    357 heurdata->copycuts, &success, NULL) );
    358
    359 SCIPdebugMsg(scip, "Copying SCIP was %s successful.\n", success ? "" : "not ");
    360
    361 /* if the subproblem could not be created, free memory and return */
    362 if( !success )
    363 {
    364 *result = SCIP_DIDNOTRUN;
    365 goto TERMINATE;
    366 }
    367
    368 /* create event handler for LP events */
    369 eventhdlr = NULL;
    370 SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecTrustregion, NULL) );
    371 if( eventhdlr == NULL )
    372 {
    373 /* free hash map */
    374 SCIPhashmapFree(&varmapfw);
    375
    376 SCIPerrorMessage("event handler for " HEUR_NAME " heuristic not found.\n");
    377 return SCIP_PLUGINNOTFOUND;
    378 }
    379
    380 SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) );
    381 for (i = 0; i < nvars; ++i)
    382 subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]);
    383
    384 /* free hash map */
    385 SCIPhashmapFree(&varmapfw);
    386
    387 heurdata->nodelimit = nsubnodes;
    388 SCIP_CALL( SCIPsetCommonSubscipParams(scip, subscip, nsubnodes, MAX(10, nsubnodes/10), heurdata->bestsollimit) );
    389
    390 SCIP_CALL( addTrustRegionConstraints(scip, subscip, subvars, heurdata) );
    391
    392 /* catch LP events of sub-SCIP */
    393 if( !heurdata->uselprows )
    394 {
    395 assert(eventhdlr != NULL);
    396
    397 SCIP_CALL( SCIPtransformProb(subscip) );
    398 SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, NULL) );
    399 }
    400
    401 /* solve the subproblem */
    402 SCIPdebugMsg(scip, "solving trust region subproblem with maxnodes %" SCIP_LONGINT_FORMAT "\n", nsubnodes);
    403
    404 SCIP_CALL( SCIPsetIntParam(subscip, "heuristics/trysol/priority", 100000) );
    405
    406 /* Errors in solving the subproblem should not kill the overall solving process
    407 * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
    408 */
    409 SCIP_CALL_ABORT( SCIPsolve(subscip) );
    410
    411 /* drop LP events of sub-SCIP */
    412 if( !heurdata->uselprows )
    413 {
    414 assert(eventhdlr != NULL);
    415
    416 SCIP_CALL( SCIPdropEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, -1) );
    417 }
    418
    419 /* print solving statistics of subproblem if we are in SCIP's debug mode */
    421
    422 heurdata->usednodes += SCIPgetNNodes(subscip);
    423 SCIPdebugMsg(scip, "trust region used %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT " nodes\n",
    424 SCIPgetNNodes(subscip), nsubnodes);
    425
    426 /* checks the solutions of the sub SCIP and adds them to the main SCIP if feasible */
    427 SCIP_CALL( SCIPtranslateSubSols(scip, subscip, heur, subvars, &success, NULL) );
    428
    429 if( success )
    430 *result = SCIP_FOUNDSOL;
    431
    432 /* checking the status of the subscip */
    433 heurdata->callstatus = WAITFORNEWSOL;
    436 {
    437 heurdata->callstatus = EXECUTE;
    438 heurdata->curminnodes *= 2;
    439 }
    440
    441 TERMINATE:
    442 /* free subproblem */
    443 SCIPfreeBufferArray(scip, &subvars);
    444
    445 return SCIP_OKAY;
    446}
    447
    448
    449/** execution method of primal heuristic */
    450static
    451SCIP_DECL_HEUREXEC(heurExecTrustregion)
    452{ /*lint --e{715}*/
    453 SCIP_Longint maxnnodes;
    454 SCIP_Longint nsubnodes;
    455
    456 SCIP_HEURDATA* heurdata;
    457 SCIP* subscip;
    458
    459 SCIP_SOL* bestsol;
    460
    461 SCIP_Bool success;
    462 SCIP_RETCODE retcode;
    463
    464 assert(heur != NULL);
    465 assert(scip != NULL);
    466 assert(result != NULL);
    467
    468 *result = SCIP_DIDNOTRUN;
    469
    470 /* get heuristic's data */
    471 heurdata = SCIPheurGetData(heur);
    472 assert( heurdata != NULL );
    473
    474 /* there should be enough binary variables that a trust region constraint makes sense */
    475 if( SCIPgetNBinVars(scip) < heurdata->minbinvars )
    476 return SCIP_OKAY;
    477
    478 *result = SCIP_DELAYED;
    479
    480 /* only call heuristic, if an IP solution is at hand */
    481 if( SCIPgetNSols(scip) <= 0 )
    482 return SCIP_OKAY;
    483
    484 bestsol = SCIPgetBestSol(scip);
    485 assert(bestsol != NULL);
    486
    487 /* only call heuristic, if the best solution comes from transformed problem */
    488 if( SCIPsolIsOriginal(bestsol) )
    489 return SCIP_OKAY;
    490
    491 /* only call heuristic, if enough nodes were processed since last incumbent */
    492 if( SCIPgetNNodes(scip) - SCIPgetSolNodenum(scip, bestsol) < heurdata->nwaitingnodes)
    493 return SCIP_OKAY;
    494
    495 /* only call heuristic, if the best solution does not come from trivial heuristic */
    496 if( SCIPsolGetHeur(bestsol) != NULL && strcmp(SCIPheurGetName(SCIPsolGetHeur(bestsol)), "trivial") == 0 )
    497 return SCIP_OKAY;
    498
    499 /* calculate the maximal number of branching nodes until heuristic is aborted */
    500 maxnnodes = (SCIP_Longint)(heurdata->nodesquot * SCIPgetNNodes(scip));
    501
    502 /* reward trust region if it found solutions often.
    503 * In this case, the trust region heuristic is designed for Benders' decomposition and solutions found may not be
    504 * added by this heuristic but by trysol. So we don't reward finding best solutions, but finding any solution. */
    505 maxnnodes = (SCIP_Longint)(maxnnodes * (1.0 + 2.0*(SCIPheurGetNSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur)+1.0)));
    506 maxnnodes -= 100 * SCIPheurGetNCalls(heur); /* count the setup costs for the sub-MIP as 100 nodes */
    507 maxnnodes += heurdata->nodesofs;
    508
    509 *result = SCIP_DIDNOTRUN;
    510
    511 /* we continue to execute the trust region heuristic until no new best solution is found */
    512 do
    513 {
    514 SCIP_RESULT heurresult;
    515
    516 /* storing the best solution again since it is needed for the execution loop */
    517 bestsol = SCIPgetBestSol(scip);
    518
    519 /* reset minnodes if new solution was found */
    520 if( heurdata->lastsol != bestsol )
    521 {
    522 heurdata->curminnodes = heurdata->minnodes;
    523 heurdata->callstatus = EXECUTE;
    524 heurdata->lastsol = bestsol;
    525 }
    526
    527 /* if no new solution was found and trust region also seems to fail, just keep on waiting */
    528 if( heurdata->callstatus == WAITFORNEWSOL )
    529 return SCIP_OKAY;
    530
    531 /* determine the node limit for the current process */
    532 nsubnodes = maxnnodes - heurdata->usednodes;
    533 nsubnodes = MIN(nsubnodes, heurdata->maxnodes);
    534
    535 /* check whether we have enough nodes left to call sub problem solving */
    536 if( nsubnodes < heurdata->curminnodes )
    537 return SCIP_OKAY;
    538
    539 if( SCIPisStopped(scip) )
    540 return SCIP_OKAY;
    541
    542 /* check whether there is enough time and memory left */
    543 SCIP_CALL( SCIPcheckCopyLimits(scip, &success) );
    544
    545 /* abort if no time is left or there is not enough memory to create a copy of SCIP */
    546 if( !success )
    547 return SCIP_OKAY;
    548
    549 heurresult = SCIP_DIDNOTFIND;
    550
    551 SCIPdebugMsg(scip, "running trust region heuristic ...\n");
    552
    553 SCIP_CALL( SCIPcreate(&subscip) );
    554
    555 retcode = setupAndSolveSubscipTrustregion(scip, subscip, heur, nsubnodes, &heurresult);
    556
    557 SCIP_CALL( SCIPfree(&subscip) );
    558
    559 /* if the result is FOUNDSOL, this means that a solution was found during a previous execution of the heuristic.
    560 * So the heuristic result should only be updated if the result is not FOUNDSOL.
    561 */
    562 if( *result != SCIP_FOUNDSOL )
    563 *result = heurresult;
    564 }
    565 while( bestsol != SCIPgetBestSol(scip) && retcode == SCIP_OKAY );
    566
    567 return retcode;
    568}
    569
    570
    571/*
    572 * primal heuristic specific interface methods
    573 */
    574
    575/** creates the trustregion primal heuristic and includes it in SCIP */
    577 SCIP* scip /**< SCIP data structure */
    578 )
    579{
    580 SCIP_HEURDATA* heurdata;
    581 SCIP_HEUR* heur;
    582
    583 /* create Trustregion primal heuristic data */
    584 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    585
    586 /* include primal heuristic */
    589 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecTrustregion, heurdata) );
    590
    591 assert(heur != NULL);
    592
    593 /* primal heuristic is safe to use in exact solving mode */
    594 SCIPheurMarkExact(heur);
    595
    596 /* set non-NULL pointers to callback methods */
    597 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyTrustregion) );
    598 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeTrustregion) );
    599 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitTrustregion) );
    600
    601 /* add trustregion primal heuristic parameters */
    602 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/nodesofs",
    603 "number of nodes added to the contingent of the total nodes",
    604 &heurdata->nodesofs, FALSE, DEFAULT_NODESOFS, 0, INT_MAX, NULL, NULL) );
    605
    606 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/minbinvars",
    607 "the number of binary variables necessary to run the heuristic",
    608 &heurdata->minbinvars, FALSE, DEFAULT_MINBINVARS, 1, INT_MAX, NULL, NULL) );
    609
    610 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/nodesquot",
    611 "contingent of sub problem nodes in relation to the number of nodes of the original problem",
    612 &heurdata->nodesquot, FALSE, DEFAULT_NODESQUOT, 0.0, 1.0, NULL, NULL) );
    613
    614 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/lplimfac",
    615 "factor by which the limit on the number of LP depends on the node limit",
    616 &heurdata->lplimfac, TRUE, DEFAULT_LPLIMFAC, 1.0, SCIP_REAL_MAX, NULL, NULL) );
    617
    618 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/minnodes",
    619 "minimum number of nodes required to start the subproblem",
    620 &heurdata->minnodes, TRUE, DEFAULT_MINNODES, 0, INT_MAX, NULL, NULL) );
    621
    622 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/maxnodes",
    623 "maximum number of nodes to regard in the subproblem",
    624 &heurdata->maxnodes, TRUE, DEFAULT_MAXNODES, 0, INT_MAX, NULL, NULL) );
    625
    626 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/nwaitingnodes",
    627 "number of nodes without incumbent change that heuristic should wait",
    628 &heurdata->nwaitingnodes, TRUE, DEFAULT_NWAITINGNODES, 0, INT_MAX, NULL, NULL) );
    629
    630 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/uselprows",
    631 "should subproblem be created out of the rows in the LP rows?",
    632 &heurdata->uselprows, TRUE, DEFAULT_USELPROWS, NULL, NULL) );
    633
    634 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/copycuts",
    635 "if uselprows == FALSE, should all active cuts from cutpool be copied to constraints in subproblem?",
    636 &heurdata->copycuts, TRUE, DEFAULT_COPYCUTS, NULL, NULL) );
    637
    638 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/bestsollimit",
    639 "limit on number of improving incumbent solutions in sub-CIP",
    640 &heurdata->bestsollimit, FALSE, DEFAULT_BESTSOLLIMIT, -1, INT_MAX, NULL, NULL) );
    641
    642 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/violpenalty",
    643 "the penalty for each change in the binary variables from the candidate solution",
    644 &heurdata->violpenalty, FALSE, DEFAULT_VIOLPENALTY, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    645
    646 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/objminimprove",
    647 "the minimum absolute improvement in the objective function value",
    648 &heurdata->objminimprove, FALSE, DEFAULT_OBJMINIMPROVE, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    649
    650 return SCIP_OKAY;
    651}
    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_Longint
    Definition: def.h:150
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:343
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    SCIP_RETCODE SCIPtranslateSubSols(SCIP *scip, SCIP *subscip, SCIP_HEUR *heur, SCIP_VAR **subvars, SCIP_Bool *success, int *solindex)
    Definition: scip_copy.c:1438
    SCIP_RETCODE SCIPsetCommonSubscipParams(SCIP *sourcescip, SCIP *subscip, SCIP_Longint nsubnodes, SCIP_Longint nstallnodes, int bestsollimit)
    Definition: scip_copy.c:3336
    SCIP_RETCODE SCIPcheckCopyLimits(SCIP *sourcescip, SCIP_Bool *success)
    Definition: scip_copy.c:3250
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:767
    SCIP_RETCODE SCIPfree(SCIP **scip)
    Definition: scip_general.c:402
    SCIP_RETCODE SCIPcreate(SCIP **scip)
    Definition: scip_general.c:370
    SCIP_STATUS SCIPgetStatus(SCIP *scip)
    Definition: scip_general.c:562
    const char * SCIPgetProbName(SCIP *scip)
    Definition: scip_prob.c:1242
    SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
    Definition: scip_prob.c:2115
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    int SCIPgetNBinVars(SCIP *scip)
    Definition: scip_prob.c:2293
    SCIP_Bool SCIPisObjIntegral(SCIP *scip)
    Definition: scip_prob.c:1801
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3284
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:83
    SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:139
    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 SCIPincludeHeurTrustregion(SCIP *scip)
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: scip_event.c:111
    const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
    Definition: event.c:396
    SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
    Definition: event.c:1194
    SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
    Definition: scip_event.c:293
    SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
    Definition: scip_event.c:333
    SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
    Definition: scip_heur.c:167
    SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
    Definition: heur.c:1368
    SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, SCIP_HEURTIMING timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
    Definition: scip_heur.c:122
    SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
    Definition: scip_heur.c:183
    SCIP_Longint SCIPheurGetNSolsFound(SCIP_HEUR *heur)
    Definition: heur.c:1603
    SCIP_Longint SCIPheurGetNCalls(SCIP_HEUR *heur)
    Definition: heur.c:1593
    void SCIPheurMarkExact(SCIP_HEUR *heur)
    Definition: heur.c:1457
    SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
    Definition: scip_heur.c:199
    const char * SCIPheurGetName(SCIP_HEUR *heur)
    Definition: heur.c:1467
    void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
    Definition: heur.c:1378
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #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
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2986
    int SCIPgetNSols(SCIP *scip)
    Definition: scip_sol.c:2887
    SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
    Definition: sol.c:4274
    SCIP_Bool SCIPsolIsOriginal(SCIP_SOL *sol)
    Definition: sol.c:4155
    SCIP_Longint SCIPgetSolNodenum(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:2221
    SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:2003
    SCIP_RETCODE SCIPtransformProb(SCIP *scip)
    Definition: scip_solve.c:232
    SCIP_RETCODE SCIPinterruptSolve(SCIP *scip)
    Definition: scip_solve.c:3561
    SCIP_RETCODE SCIPsolve(SCIP *scip)
    Definition: scip_solve.c:2611
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_RETCODE SCIPprintStatistics(SCIP *scip, FILE *file)
    SCIP_Longint SCIPgetNLPs(SCIP *scip)
    SCIP_RETCODE SCIPcopyLargeNeighborhoodSearch(SCIP *sourcescip, SCIP *subscip, SCIP_HASHMAP *varmap, const char *suffix, SCIP_VAR **fixedvars, SCIP_Real *fixedvals, int nfixedvars, SCIP_Bool uselprows, SCIP_Bool copycuts, SCIP_Bool *success, SCIP_Bool *valid)
    Definition: heuristics.c:953
    SCIP_RETCODE SCIPaddTrustregionNeighborhoodConstraint(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR **subvars, SCIP_Real violpenalty)
    Definition: heuristics.c:1042
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    #define EXECUTE
    #define DEFAULT_NODESQUOT
    static SCIP_DECL_HEURFREE(heurFreeTrustregion)
    #define DEFAULT_NWAITINGNODES
    #define DEFAULT_NODESOFS
    #define DEFAULT_COPYCUTS
    #define DEFAULT_MAXNODES
    static SCIP_RETCODE setupAndSolveSubscipTrustregion(SCIP *scip, SCIP *subscip, SCIP_HEUR *heur, SCIP_Longint nsubnodes, SCIP_RESULT *result)
    #define HEUR_TIMING
    #define DEFAULT_MINNODES
    #define HEUR_FREQOFS
    #define HEUR_DESC
    static SCIP_DECL_HEURCOPY(heurCopyTrustregion)
    #define DEFAULT_LPLIMFAC
    static SCIP_RETCODE addTrustRegionConstraints(SCIP *scip, SCIP *subscip, SCIP_VAR **subvars, SCIP_HEURDATA *heurdata)
    #define WAITFORNEWSOL
    #define DEFAULT_OBJMINIMPROVE
    #define HEUR_DISPCHAR
    #define HEUR_MAXDEPTH
    #define HEUR_PRIORITY
    #define HEUR_NAME
    #define DEFAULT_USELPROWS
    #define DEFAULT_BESTSOLLIMIT
    #define DEFAULT_VIOLPENALTY
    static SCIP_DECL_HEUREXEC(heurExecTrustregion)
    #define EVENTHDLR_DESC
    static SCIP_DECL_HEURINIT(heurInitTrustregion)
    static SCIP_DECL_EVENTEXEC(eventExecTrustregion)
    #define HEUR_FREQ
    #define HEUR_USESSUBSCIP
    #define EVENTHDLR_NAME
    #define DEFAULT_MINBINVARS
    Large neighborhood search heuristic for Benders' decomposition based on trust region methods.
    methods commonly used by primal heuristics
    memory allocation routines
    public methods for managing events
    public methods for primal heuristics
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    public data structures and miscellaneous methods
    public methods for primal CIP solutions
    public methods for problem variables
    public methods for branching rule plugins and branching
    public methods for constraint handler plugins and constraints
    public methods for problem copies
    public methods for event handler plugins and event handlers
    general public methods
    public methods for primal heuristic plugins and divesets
    public methods for memory management
    public methods for message handling
    public methods for node selector plugins
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for solutions
    public solving methods
    public methods for querying solving statistics
    public methods for SCIP variables
    struct SCIP_EventData SCIP_EVENTDATA
    Definition: type_event.h:179
    #define SCIP_EVENTTYPE_LPSOLVED
    Definition: type_event.h:102
    struct SCIP_HeurData SCIP_HEURDATA
    Definition: type_heur.h:77
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_DELAYED
    Definition: type_result.h:43
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_FOUNDSOL
    Definition: type_result.h:56
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_PLUGINNOTFOUND
    Definition: type_retcode.h:54
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STATUS_TOTALNODELIMIT
    Definition: type_stat.h:50
    @ SCIP_STATUS_STALLNODELIMIT
    Definition: type_stat.h:52
    @ SCIP_STATUS_NODELIMIT
    Definition: type_stat.h:49