SCIP

    Solving Constraint Integer Programs

    heur_crossover.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_crossover.c
    26 * @ingroup DEFPLUGINS_HEUR
    27 * @brief crossover primal heuristic
    28 * @author Timo Berthold
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    34#include "scip/heur_crossover.h"
    35#include "scip/heuristics.h"
    36#include "scip/pub_event.h"
    37#include "scip/pub_heur.h"
    38#include "scip/pub_message.h"
    39#include "scip/pub_misc.h"
    40#include "scip/pub_sol.h"
    41#include "scip/pub_var.h"
    42#include "scip/scip_branch.h"
    43#include "scip/scip_cons.h"
    44#include "scip/scip_copy.h"
    45#include "scip/scip_event.h"
    46#include "scip/scip_general.h"
    47#include "scip/scip_heur.h"
    48#include "scip/scip_mem.h"
    49#include "scip/scip_message.h"
    50#include "scip/scip_nodesel.h"
    51#include "scip/scip_numerics.h"
    52#include "scip/scip_param.h"
    53#include "scip/scip_prob.h"
    55#include "scip/scip_sol.h"
    56#include "scip/scip_solve.h"
    58#include "scip/scip_tree.h"
    59#include "scip/scip_var.h"
    60
    61
    62#define HEUR_NAME "crossover"
    63#define HEUR_DESC "LNS heuristic that fixes all variables that are identic in a couple of solutions"
    64#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_LNS
    65#define HEUR_PRIORITY -1104000
    66#define HEUR_FREQ 15
    67#define HEUR_FREQOFS 0
    68#define HEUR_MAXDEPTH -1
    69#define HEUR_TIMING SCIP_HEURTIMING_AFTERNODE
    70#define HEUR_USESSUBSCIP TRUE /**< does the heuristic use a secondary SCIP instance? */
    71
    72#define DEFAULT_MAXNODES 5000LL /* maximum number of nodes to regard in the subproblem */
    73#define DEFAULT_MINIMPROVE 0.01 /* factor by which Crossover should at least improve the incumbent */
    74#define DEFAULT_MINNODES 50LL /* minimum number of nodes to regard in the subproblem */
    75#define DEFAULT_MINFIXINGRATE 0.666 /* minimum percentage of integer variables that have to be fixed */
    76#define DEFAULT_NODESOFS 500LL /* number of nodes added to the contingent of the total nodes */
    77#define DEFAULT_NODESQUOT 0.1 /* subproblem nodes in relation to nodes of the original problem */
    78#define DEFAULT_LPLIMFAC 2.0 /* factor by which the limit on the number of LP depends on the node limit */
    79#define DEFAULT_NUSEDSOLS 3 /* number of solutions that will be taken into account */
    80#define DEFAULT_NWAITINGNODES 200LL /* number of nodes without incumbent change heuristic should wait */
    81#define DEFAULT_RANDOMIZATION TRUE /* should the choice which sols to take be randomized? */
    82#define DEFAULT_DONTWAITATROOT FALSE /* should the nwaitingnodes parameter be ignored at the root node? */
    83#define DEFAULT_USELPROWS FALSE /* should subproblem be created out of the rows in the LP rows,
    84 * otherwise, the copy constructors of the constraints handlers are used */
    85#define DEFAULT_COPYCUTS TRUE /* if DEFAULT_USELPROWS is FALSE, then should all active cuts from the
    86 * cutpool of the original scip be copied to constraints of the subscip
    87 */
    88#define DEFAULT_PERMUTE FALSE /* should the subproblem be permuted to increase diversification? */
    89#define HASHSIZE_SOLS 500 /* size of hash table for solution tuples in crossover heuristic */
    90#define DEFAULT_BESTSOLLIMIT -1 /* limit on number of improving incumbent solutions in sub-CIP */
    91#define DEFAULT_USEUCT FALSE /* should uct node selection be used at the beginning of the search? */
    92#define DEFAULT_RANDSEED 7 /* initial random seed */
    94/* event handler properties */
    95#define EVENTHDLR_NAME "Crossover"
    96#define EVENTHDLR_DESC "LP event handler for " HEUR_NAME " heuristic"
    97
    98/*
    99 * Data structures
    100 */
    101
    102typedef struct SolTuple SOLTUPLE;
    103
    104/** primal heuristic data */
    105struct SCIP_HeurData
    106{
    107 SCIP_SOL* prevlastsol; /**< worst solution taken into account during the previous run */
    108 SCIP_SOL* prevbestsol; /**< best solution during the previous run */
    109 int prevnsols; /**< number of all solutions during the previous run */
    110
    111 SCIP_Longint maxnodes; /**< maximum number of nodes to regard in the subproblem */
    112 SCIP_Longint minnodes; /**< minimum number of nodes to regard in the subproblem */
    113 SCIP_Longint nodesofs; /**< number of nodes added to the contingent of the total nodes */
    114 SCIP_Longint usednodes; /**< nodes already used by crossover in earlier calls */
    115 SCIP_Real nodesquot; /**< subproblem nodes in relation to nodes of the original problem */
    116
    117 int nusedsols; /**< number of solutions that will be taken into account */
    118 SCIP_Longint nwaitingnodes; /**< number of nodes without incumbent change heuristic should wait */
    119 unsigned int nfailures; /**< number of failures since last successful call */
    120 SCIP_Longint nextnodenumber; /**< number of nodes at which crossover should be called the next time */
    121 SCIP_Real minfixingrate; /**< minimum percentage of integer variables that have to be fixed */
    122 SCIP_Real minimprove; /**< factor by which Crossover should at least improve the incumbent */
    123 SCIP_Real nodelimit; /**< the nodelimit employed in the current sub-SCIP, for the event handler*/
    124 SCIP_Real lplimfac; /**< factor by which the limit on the number of LP depends on the node limit */
    125 SCIP_Bool randomization; /**< should the choice which sols to take be randomized? */
    126 SCIP_Bool dontwaitatroot; /**< should the nwaitingnodes parameter be ignored at the root node? */
    127 SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
    128 SCIP_HASHTABLE* hashtable; /**< hashtable used to store the solution tuples already used */
    129 SOLTUPLE* lasttuple; /**< last tuple of solutions created by crossover */
    130 SCIP_Bool uselprows; /**< should subproblem be created out of the rows in the LP rows? */
    131 SCIP_Bool copycuts; /**< if uselprows == FALSE, should all active cuts from cutpool be copied
    132 * to constraints in subproblem? */
    133 SCIP_Bool permute; /**< should the subproblem be permuted to increase diversification? */
    134 int bestsollimit; /**< limit on number of improving incumbent solutions in sub-CIP */
    135 SCIP_Bool useuct; /**< should uct node selection be used at the beginning of the search? */
    136};
    137
    138/** n-tuple of solutions and their hashkey */
    139struct SolTuple
    140{
    141 int* indices; /**< sorted array of solution indices */
    142 int size; /**< size of the array (should be heurdata->nusedsols) */
    143 unsigned int key; /**< hashkey of the tuple */
    144 SOLTUPLE* prev; /**< previous solution tuple created */
    145};
    146
    147
    148/*
    149 * Local methods
    150 */
    152/** gets the hash key of a solution tuple */
    153static
    154SCIP_DECL_HASHGETKEY(hashGetKeySols)
    155{ /*lint --e{715}*/
    156 return elem;
    157}
    158
    160/** returns TRUE iff both solution tuples are identical */
    161static
    162SCIP_DECL_HASHKEYEQ(hashKeyEqSols)
    163{ /*lint --e{715}*/
    164 int i;
    165 int size;
    166
    167 int* indices1;
    168 int* indices2;
    169
    170 indices1 = ((SOLTUPLE*)key1)->indices;
    171 indices2 = ((SOLTUPLE*)key2)->indices;
    172
    173 /* there should be two nonempty arrays of the same size */
    174 assert(indices1 != NULL);
    175 assert(indices2 != NULL);
    176 assert(((SOLTUPLE*)key1)->size == ((SOLTUPLE*)key2)->size);
    177
    178 size = ((SOLTUPLE*)key1)->size;
    179
    180 /* compare arrays by components, return TRUE, iff equal */
    181 for( i = 0; i < size; i++ )
    182 {
    183 if( indices1[i] != indices2[i] )
    184 return FALSE;
    185 }
    186
    187 return TRUE;
    188}
    189
    191/** returns hashkey of a solution tuple */
    192static
    193SCIP_DECL_HASHKEYVAL(hashKeyValSols)
    194{ /*lint --e{715}*/
    195 return ((SOLTUPLE*)key)->key;
    196}
    197
    199/** calculates a hash key for a given tuple of solution indices */
    200static
    201unsigned int calculateHashKey(
    202 int* indices, /**< indices of solutions */
    203 int size /**< number of solutions */
    204 )
    205{
    206 int i;
    207 unsigned int hashkey;
    208
    209 /* hashkey should be (x1+1) * (x2+1) * ... * (xn+1) + x1 + x2 + ... + xn */
    210 hashkey = 1;
    211 for( i = 0; i < size; i++ )
    212 hashkey *= (unsigned) indices[i] + 1;
    213 for( i = 0; i < size; i++ )
    214 hashkey += (unsigned) indices[i];
    215
    216 return hashkey;
    217}
    219
    220/** insertion sort for a small int array */
    221static void sortArray(
    222 int* a, /**< array to be sorted */
    223 int size /**< size of array */
    224 )
    225{
    226 int i;
    227 int j;
    228 int tmp;
    229
    230 /* simple insertion sort algorithm */
    231 for( i = 1; i < size; i++ )
    232 {
    233 tmp = a[i];
    234 j = i-1;
    235 while( j >= 0 && a[j] > tmp )
    236 {
    237 a[j+1] = a[j]; /*lint !e679*/
    238 j = j-1;
    239 }
    240 a[j+1] = tmp; /*lint !e679*/
    241 }
    242}
    243
    245/** creates a new tuple of solutions */
    246static
    248 SCIP* scip, /**< original SCIP data structure */
    249 SOLTUPLE** elem, /**< tuple of solutions which should be created */
    250 int* indices, /**< indices of solutions */
    251 int size, /**< number of solutions */
    252 SCIP_HEURDATA* heurdata /**< primal heuristic data */
    253 )
    254{
    255 /* memory allocation */
    257 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*elem)->indices, size) );
    258 BMScopyMemoryArray((*elem)->indices, indices, size);
    259
    260 /* data input */
    261 sortArray(indices,size);
    262 (*elem)->size = size;
    263 (*elem)->key = calculateHashKey((*elem)->indices, (*elem)->size);
    264 (*elem)->prev = heurdata->lasttuple;
    265
    266 /* update heurdata */
    267 heurdata->lasttuple = *elem;
    268 return SCIP_OKAY;
    269}
    270
    272/** checks whether the new solution was found at the same node by the same heuristic as an already selected one */
    273static
    275 SCIP_SOL** sols, /**< feasible SCIP solutions */
    276 int* selection, /**< pool of solutions crossover uses */
    277 int selectionsize, /**< size of solution pool */
    278 int newsol /**< candidate solution */
    279 )
    280{
    281 int i;
    282
    283 for( i = 0; i < selectionsize; i++ )
    284 {
    285 if( SCIPsolGetHeur(sols[selection[i]]) == SCIPsolGetHeur(sols[newsol])
    286 && SCIPsolGetNodenum(sols[selection[i]]) == SCIPsolGetNodenum(sols[newsol]) )
    287 return FALSE;
    288 }
    289
    290 return TRUE;
    291}
    293/** randomly selects the solutions crossover will use from the pool of all solutions found so far */
    294static
    296 SCIP* scip, /**< original SCIP data structure */
    297 int* selection, /**< pool of solutions crossover uses */
    298 SCIP_HEURDATA* heurdata, /**< primal heuristic data */
    299 SCIP_Bool* success /**< pointer to store whether the process was successful */
    300 )
    301{
    302 int i;
    303 int j;
    304 int lastsol; /* the worst solution possible to choose */
    305 int nusedsols; /* number of solutions which will be chosen */
    306
    307 SOLTUPLE* elem;
    308 SCIP_SOL** sols;
    309
    310 assert( success != NULL );
    311
    312 /* initialization */
    313 nusedsols = heurdata->nusedsols;
    314 lastsol = SCIPgetNSols(scip);
    315 sols = SCIPgetSols(scip);
    316 assert(nusedsols < lastsol);
    317
    318 i = 0;
    319 *success = FALSE;
    320
    321 /* perform at maximum 10 restarts and stop as soon as a new set of solutions is found */
    322 while( !*success && i < 10 )
    323 {
    324 SCIP_Bool validtuple;
    325
    326 validtuple = TRUE;
    327 for( j = 0; j < nusedsols && validtuple; j++ )
    328 {
    329 int k;
    330 k = SCIPrandomGetInt(heurdata->randnumgen, nusedsols-j-1, lastsol-1);
    331
    332 /* ensure that the solution does not have a similar source as the others */
    333 while( k >= nusedsols-j-1 && !solHasNewSource(sols, selection, j, k) )
    334 k--;
    335
    336 validtuple = (k >= nusedsols-j-1);
    337 selection[j] = k;
    338 lastsol = k;
    339 }
    340
    341 if( validtuple )
    342 {
    343 /* creates an object ready to be inserted into the hashtable */
    344 SCIP_CALL( createSolTuple(scip, &elem, selection, nusedsols, heurdata) );
    345
    346 /* check whether the randomized set is already in the hashtable, if not, insert it */
    347 if( !SCIPhashtableExists(heurdata->hashtable, elem) )
    348 {
    349 SCIP_CALL( SCIPhashtableInsert(heurdata->hashtable, elem) );
    350 *success = TRUE;
    351 }
    352 }
    353 i++;
    354 }
    355
    356 return SCIP_OKAY;
    357}
    358
    360/** determines the fixings for the CROSSOVER subproblem and checks whether enough fixings were found */
    361static
    363 SCIP* scip, /**< original SCIP data structure */
    364 SCIP_VAR** fixedvars, /**< array to store source SCIP variables whose copies should be fixed in the sub-SCIP */
    365 SCIP_Real* fixedvals, /**< array to store solution values for variable fixing */
    366 int* nfixedvars, /**< pointer to store the number of fixed variables */
    367 int fixedvarssize, /**< size of the arrays to store fixing variables */
    368 int* selection, /**< pool of solutions crossover will use */
    369 SCIP_HEURDATA* heurdata, /**< primal heuristic data */
    370 SCIP_Bool* success /**< pointer to store whether the problem was created successfully */
    371 )
    372{
    373 SCIP_VAR** vars; /* original scip variables */
    374 SCIP_SOL** sols; /* pool of solutions */
    375 SCIP_Real fixingrate; /* percentage of variables that are fixed */
    376
    377 int nvars;
    378 int nbinvars;
    379 int nintvars;
    380
    381 int i;
    382 int j;
    383
    384 sols = SCIPgetSols(scip);
    385 assert(sols != NULL);
    386 assert(fixedvars != NULL);
    387 assert(fixedvals != NULL);
    388
    389 /* get required data of the original problem */
    390 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
    391 assert(fixedvarssize >= nbinvars + nintvars);
    392
    393 *nfixedvars = 0;
    394
    395 /* go through discrete variables and collect potential fixings */
    396 for( i = 0; i < nbinvars + nintvars; i++ )
    397 {
    398 SCIP_Real solval;
    399 SCIP_Bool fixable;
    400
    401 fixable = TRUE;
    402 solval = SCIPgetSolVal(scip, sols[selection[0]], vars[i]);
    403
    404 /* check, whether variable's value is identical for each selected solution */
    405 for( j = 1; j < heurdata->nusedsols; j++ )
    406 {
    407 SCIP_Real varsolval;
    408 varsolval = SCIPgetSolVal(scip, sols[selection[j]], vars[i]);
    409 if( REALABS(solval - varsolval) > 0.5 )
    410 {
    411 fixable = FALSE;
    412 break;
    413 }
    414 }
    415
    416 /* original solval can be outside transformed global bounds */
    417 fixable = fixable && SCIPvarGetLbGlobal(vars[i]) <= solval && solval <= SCIPvarGetUbGlobal(vars[i]);
    418
    419 /* if solutions' values are equal, variable should be fixed in the subproblem */
    420 if( fixable )
    421 {
    422 fixedvars[(*nfixedvars)] = vars[i];
    423 fixedvals[(*nfixedvars)] = solval;
    424 (*nfixedvars)++;
    425 }
    426 }
    427
    428 fixingrate = (SCIP_Real)(*nfixedvars) / (SCIP_Real)(MAX(nbinvars + nintvars, 1));
    429
    430 /* if all variables would be fixed or amount of fixed variables is insufficient,
    431 * skip subproblem creation and abort immediately
    432 */
    433 *success = (*nfixedvars) < nbinvars + nintvars && fixingrate >= heurdata->minfixingrate;
    434
    435 return SCIP_OKAY;
    436}
    438/** creates a subproblem for subscip by fixing a number of variables */
    439static
    441 SCIP* scip, /**< original SCIP data structure */
    442 SCIP_VAR** fixedvars, /**< array to store source SCIP variables whose copies should be fixed in the sub-SCIP */
    443 SCIP_Real* fixedvals, /**< array to store solution values for variable fixing */
    444 int* nfixedvars, /**< pointer to store the number of fixed variables */
    445 int fixedvarssize, /**< size of the arrays to store fixing variables */
    446 int* selection, /**< pool of solutions crossover will use */
    447 SCIP_HEURDATA* heurdata, /**< primal heuristic data */
    448 SCIP_Bool* success /**< pointer to store whether the problem was created successfully */
    449 )
    450{
    451 SCIP_SOL** sols; /* array of all solutions found so far */
    452 int nsols; /* number of all solutions found so far */
    453 int nusedsols; /* number of solutions to use in crossover */
    454 int i;
    455
    456 /* get solutions' data */
    457 nsols = SCIPgetNSols(scip);
    458 sols = SCIPgetSols(scip);
    459 nusedsols = heurdata->nusedsols;
    460
    461 assert(nusedsols > 1);
    462 assert(nsols >= nusedsols);
    463
    464 /* use nusedsols best solutions if randomization is deactivated or there are only nusedsols solutions at hand
    465 * or a good new solution was found since last call */
    466 if( !heurdata->randomization || nsols == nusedsols || heurdata->prevlastsol != sols[nusedsols-1] )
    467 {
    468 SOLTUPLE* elem;
    469 SCIP_HEUR* solheur;
    470 SCIP_Longint solnodenum;
    471 SCIP_Bool allsame;
    472
    473 for( i = 0; i < nusedsols; i++ )
    474 selection[i] = i;
    475 SCIP_CALL( createSolTuple(scip, &elem, selection, nusedsols, heurdata) );
    476
    477 solheur = SCIPsolGetHeur(sols[0]);
    478 solnodenum = SCIPsolGetNodenum(sols[0]);
    479 allsame = TRUE;
    480
    481 /* check, whether all solutions have been found by the same heuristic at the same node; in this case we do not run
    482 * crossover, since it would probably just optimize over the same space as the other heuristic
    483 */
    484 for( i = 1; i < nusedsols; i++ )
    485 {
    486 if( SCIPsolGetHeur(sols[i]) != solheur || SCIPsolGetNodenum(sols[i]) != solnodenum )
    487 allsame = FALSE;
    488 }
    489 *success = !allsame && !SCIPhashtableExists(heurdata->hashtable, elem);
    490
    491 /* check, whether solution tuple has already been tried */
    492 if( !SCIPhashtableExists(heurdata->hashtable, elem) )
    493 {
    494 SCIP_CALL( SCIPhashtableInsert(heurdata->hashtable, elem) );
    495 }
    496
    497 /* if solution tuple has already been tried, randomization is allowed and enough solutions are at hand, try
    498 * to randomize another tuple. E.g., this can happen if the last crossover solution was among the best ones */
    499 if( !(*success) && heurdata->randomization && nsols > nusedsols )
    500 {
    501 SCIP_CALL( selectSolsRandomized(scip, selection, heurdata, success) );
    502 }
    503 }
    504 /* otherwise randomize the set of solutions */
    505 else
    506 {
    507 SCIP_CALL( selectSolsRandomized(scip, selection, heurdata, success) );
    508 }
    509
    510 /* no acceptable solution tuple could be created */
    511 if( !(*success) )
    512 return SCIP_OKAY;
    513
    514 /* set up the variables of the subproblem */
    515 SCIP_CALL( fixVariables(scip, fixedvars, fixedvals, nfixedvars, fixedvarssize, selection, heurdata, success) );
    516
    517 return SCIP_OKAY;
    518}
    520/** updates heurdata after a run of crossover */
    521static
    523 SCIP* scip, /**< original SCIP data structure */
    524 SCIP_HEURDATA* heurdata /**< primal heuristic data */
    525 )
    526{
    527 /* increase number of failures, calculate next node at which crossover should be called and update actual solutions */
    528 heurdata->nfailures++;
    529 heurdata->nextnodenumber = (heurdata->nfailures <= 25
    530 ? SCIPgetNNodes(scip) + 100*(2LL << heurdata->nfailures) /*lint !e703*/
    532}
    533
    534/* ---------------- Callback methods of event handler ---------------- */
    535
    536/* exec the event handler
    537 *
    538 * we interrupt the solution process
    539 */
    540static
    541SCIP_DECL_EVENTEXEC(eventExecCrossover)
    542{
    543 SCIP_HEURDATA* heurdata;
    544
    545 assert(eventhdlr != NULL);
    546 assert(eventdata != NULL);
    547 assert(event != NULL);
    549
    551
    552 heurdata = (SCIP_HEURDATA*)eventdata;
    553 assert(heurdata != NULL);
    554
    555 /* interrupt solution process of sub-SCIP */
    556 if( SCIPgetNLPs(scip) > heurdata->lplimfac * heurdata->nodelimit )
    557 {
    558 SCIPdebugMsg(scip, "interrupt after %" SCIP_LONGINT_FORMAT " LPs\n", SCIPgetNLPs(scip));
    560 }
    561
    562 return SCIP_OKAY;
    563}
    564
    565/*
    566 * Callback methods of primal heuristic
    567 */
    569/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    570static
    571SCIP_DECL_HEURCOPY(heurCopyCrossover)
    572{ /*lint --e{715}*/
    573 assert(scip != NULL);
    574 assert(heur != NULL);
    575
    577
    578 /* call inclusion method of primal heuristic */
    580
    581 return SCIP_OKAY;
    582}
    584/** setup and solve the subproblem and catch the return code */
    585static
    587 SCIP* scip, /**< SCIP data structure */
    588 SCIP* subscip, /**< sub-SCIP data structure */
    589 SCIP_HEUR* heur, /**< mutation heuristic */
    590 SCIP_HEURDATA* heurdata, /**< heuristics data */
    591 SCIP_VAR** vars, /**< SCIP variables */
    592 SCIP_VAR** fixedvars, /**< array to store the variables that should be fixed in the subproblem */
    593 SCIP_Real* fixedvals, /**< array to store the fixing values to fix variables in the subproblem */
    594 SCIP_Longint nstallnodes, /**< node limit for the subproblem */
    595 SCIP_RESULT* result, /**< pointer to store the result */
    596 int* selection, /**< pool of solutions crossover uses */
    597 int nvars, /**< number of original problem's variables */
    598 int nfixedvars, /**< the number of variables that should be fixed */
    599 int nusedsols /**< number of solutions which will be chosen */
    600 )
    601{
    602 SCIP_EVENTHDLR* eventhdlr; /* event handler for LP events */
    603 SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */
    604 SCIP_VAR** subvars; /* subproblem's variables */
    605 SCIP_Real cutoff; /* objective cutoff for the subproblem */
    606 SCIP_Real upperbound;
    607 SCIP_Bool success;
    608 int i;
    609
    610 assert(scip != NULL);
    611 assert(subscip != NULL);
    612 assert(heur != NULL);
    613 assert(heurdata != NULL);
    614
    615 /* create the variable mapping hash map */
    616 SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), nvars) );
    617 success = FALSE;
    618
    619 /* create a copy of the transformed problem to be used by the heuristic */
    620 SCIP_CALL( SCIPcopyLargeNeighborhoodSearch(scip, subscip, varmapfw, "crossover", fixedvars, fixedvals, nfixedvars,
    621 heurdata->uselprows, heurdata->copycuts, &success, NULL) );
    622
    623 eventhdlr = NULL;
    624 /* create event handler for LP events */
    625 SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCrossover, NULL) );
    626 if( eventhdlr == NULL )
    627 {
    628 SCIPerrorMessage("event handler for " HEUR_NAME " heuristic not found.\n");
    629 return SCIP_PLUGINNOTFOUND;
    630 }
    631
    632 /* store copied variables in the order in which they appear in the main SCIP */
    633 SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) );
    634 for( i = 0; i < nvars; i++ )
    635 subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]);
    636
    637 /* free hash map */
    638 SCIPhashmapFree(&varmapfw);
    639
    640 /* do not abort subproblem on CTRL-C */
    641 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
    642
    643#ifdef SCIP_DEBUG
    644 /* for debugging, enable full output */
    645 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) );
    646 SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 100000000) );
    647#else
    648 /* disable statistic timing inside sub SCIP and output to console */
    649 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
    650 SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", FALSE) );
    651#endif
    652
    653 /* check whether there is enough time and memory left */
    654 SCIP_CALL( SCIPsetIntParam(subscip, "limits/bestsol", heurdata->bestsollimit) );
    655
    656 /* set limits for the subproblem */
    657 SCIP_CALL( SCIPcopyLimits(scip, subscip) );
    658 heurdata->nodelimit = nstallnodes;
    659 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nstallnodes) );
    660
    661 /* forbid recursive call of heuristics and separators solving subMIPs */
    662 SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
    663
    664 /* disable cutting plane separation */
    666
    667 /* disable expensive presolving */
    669
    670 /* use best estimate node selection */
    671 if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") )
    672 {
    673 SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) );
    674 }
    675
    676 /* activate uct node selection at the top of the tree */
    677 if( heurdata->useuct && SCIPfindNodesel(subscip, "uct") != NULL && !SCIPisParamFixed(subscip, "nodeselection/uct/stdpriority") )
    678 {
    679 SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/uct/stdpriority", INT_MAX/2) );
    680 }
    681
    682 /* use inference branching */
    683 if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") )
    684 {
    685 SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) );
    686 }
    687
    688 /* enable conflict analysis, disable analysis of boundexceeding LPs, and restrict conflict pool */
    689 if( !SCIPisParamFixed(subscip, "conflict/enable") )
    690 {
    691 SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/enable", TRUE) );
    692 }
    693 if( !SCIPisParamFixed(subscip, "conflict/useboundlp") )
    694 {
    695 SCIP_CALL( SCIPsetCharParam(subscip, "conflict/useboundlp", 'o') );
    696 }
    697 if( !SCIPisParamFixed(subscip, "conflict/maxstoresize") )
    698 {
    699 SCIP_CALL( SCIPsetIntParam(subscip, "conflict/maxstoresize", 100) );
    700 }
    701
    702 /* speed up sub-SCIP by not checking dual LP feasibility */
    703 SCIP_CALL( SCIPsetBoolParam(subscip, "lp/checkdualfeas", FALSE) );
    704
    705 /* add an objective cutoff */
    707
    708 upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip);
    710 {
    711 cutoff = (1-heurdata->minimprove)*SCIPgetUpperbound(scip) + heurdata->minimprove*SCIPgetLowerbound(scip);
    712 }
    713 else
    714 {
    715 if( SCIPgetUpperbound ( scip ) >= 0 )
    716 cutoff = ( 1 - heurdata->minimprove ) * SCIPgetUpperbound ( scip );
    717 else
    718 cutoff = ( 1 + heurdata->minimprove ) * SCIPgetUpperbound ( scip );
    719 }
    720 cutoff = MIN(upperbound, cutoff );
    721 SCIP_CALL( SCIPsetObjlimit(subscip, cutoff) );
    722
    723 /* permute the subproblem to increase diversification */
    724 if( heurdata->permute )
    725 {
    727 TRUE, TRUE, TRUE, TRUE, TRUE, TRUE) );
    728 }
    729
    730 /* catch LP events of sub-SCIP */
    731 SCIP_CALL( SCIPtransformProb(subscip) );
    732 SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, NULL) );
    733
    734 /* this code can be enabled whenever the subproblem should be written out */
    735#ifdef SCIP_DISABLED_CODE
    736 SCIPdebug( SCIP_CALL( SCIPwriteOrigProblem(subscip, "crossoverprob.cip", "cip", FALSE) ) );
    737#endif
    738 /* solve the subproblem */
    739 SCIPdebugMsg(scip, "Solve Crossover subMIP\n");
    740
    741 /* Errors in solving the subproblem should not kill the overall solving process.
    742 * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */
    743 SCIP_CALL_ABORT( SCIPsolve(subscip) );
    744
    745 /* drop LP events of sub-SCIP */
    746 SCIP_CALL( SCIPdropEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, -1) );
    747
    748 /* print solving statistics of subproblem if we are in SCIP's debug mode */
    750
    751 heurdata->usednodes += SCIPgetNNodes(subscip);
    752
    753 /* merge histories of the subscip-variables to the SCIP variables. */
    754 SCIP_CALL( SCIPmergeVariableStatistics(subscip, scip, subvars, vars, nvars) );
    755 SCIPdebugMsg(scip, "Transferring variable histories complete\n");
    756
    757 /* check, whether a solution was found */
    758 if( SCIPgetNSols(subscip) > 0 )
    759 {
    760 int solindex; /* index of the solution created by crossover */
    761
    762 /* check, whether a solution was found;
    763 * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */
    764 success = FALSE;
    765 solindex = -1;
    766 SCIP_CALL( SCIPtranslateSubSols(scip, subscip, heur, subvars, &success, &solindex) );
    767
    768 if( success )
    769 {
    770 int tmp;
    771
    772 assert(solindex != -1);
    773
    774 *result = SCIP_FOUNDSOL;
    775
    776 /* insert all crossings of the new solution and (nusedsols-1) of its parents into the hashtable
    777 * in order to avoid incest ;)
    778 */
    779 for( i = 0; i < nusedsols; i++ )
    780 {
    781 SOLTUPLE* elem;
    782 tmp = selection[i];
    783 selection[i] = solindex;
    784
    785 SCIP_CALL( createSolTuple(scip, &elem, selection, nusedsols, heurdata) );
    786 SCIP_CALL( SCIPhashtableInsert(heurdata->hashtable, elem) );
    787 selection[i] = tmp;
    788 }
    789
    790 /* if solution was among the best ones, crossover should not be called until another good solution was found */
    791 if( !heurdata->randomization )
    792 {
    793 heurdata->prevbestsol = SCIPgetBestSol(scip);
    794 heurdata->prevlastsol = SCIPgetSols(scip)[heurdata->nusedsols-1];
    795 }
    796 }
    797
    798 /* if solution is not better than incumbent or could not be added to problem => run is counted as a failure */
    799 if( !success || solindex != SCIPsolGetIndex(SCIPgetBestSol(scip)) )
    800 updateFailureStatistic(scip, heurdata);
    801 }
    802 else
    803 {
    804 /* if no new solution was found, run was a failure */
    805 updateFailureStatistic(scip, heurdata);
    806 }
    807
    808 SCIPfreeBufferArray(scip, &subvars);
    809
    810 return SCIP_OKAY;
    811}
    813/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    814static
    815SCIP_DECL_HEURFREE(heurFreeCrossover)
    816{ /*lint --e{715}*/
    817 SCIP_HEURDATA* heurdata;
    818
    819 assert(heur != NULL);
    820 assert(scip != NULL);
    821
    822 /* get heuristic data */
    823 heurdata = SCIPheurGetData(heur);
    824 assert(heurdata != NULL);
    825
    826 /* free heuristic data */
    827 SCIPfreeBlockMemory(scip, &heurdata);
    828 SCIPheurSetData(heur, NULL);
    829
    830 return SCIP_OKAY;
    831}
    833/** initialization method of primal heuristic (called after problem was transformed) */
    834static
    835SCIP_DECL_HEURINIT(heurInitCrossover)
    836{ /*lint --e{715}*/
    837 SCIP_HEURDATA* heurdata;
    838
    839 assert(heur != NULL);
    840 assert(scip != NULL);
    841
    842 /* get heuristic's data */
    843 heurdata = SCIPheurGetData(heur);
    844 assert(heurdata != NULL);
    845
    846 /* initialize data */
    847 heurdata->usednodes = 0;
    848 heurdata->prevlastsol = NULL;
    849 heurdata->prevbestsol = NULL;
    850 heurdata->lasttuple = NULL;
    851 heurdata->nfailures = 0;
    852 heurdata->prevnsols = 0;
    853 heurdata->nextnodenumber = 0;
    854
    855 /* create random number generator */
    856 SCIP_CALL( SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE) );
    857
    858 /* initialize hash table */
    860 hashGetKeySols, hashKeyEqSols, hashKeyValSols, NULL) );
    861 assert(heurdata->hashtable != NULL);
    862
    863 return SCIP_OKAY;
    864}
    866/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    867static
    868SCIP_DECL_HEUREXIT(heurExitCrossover)
    869{ /*lint --e{715}*/
    870 SCIP_HEURDATA* heurdata;
    871 SOLTUPLE* soltuple;
    872
    873 assert(heur != NULL);
    874 assert(scip != NULL);
    875
    876 /* get heuristic data */
    877 heurdata = SCIPheurGetData(heur);
    878 assert(heurdata != NULL);
    879 soltuple = heurdata->lasttuple;
    880
    881 /* free all soltuples iteratively */
    882 while( soltuple != NULL )
    883 {
    884 SOLTUPLE* tmp;
    885 tmp = soltuple->prev;
    886 SCIPfreeBlockMemoryArray(scip, &soltuple->indices, soltuple->size);
    887 SCIPfreeBlockMemory(scip, &soltuple);
    888 soltuple = tmp;
    889 }
    890
    891 /* free random number generator */
    892 SCIPfreeRandom(scip, &heurdata->randnumgen);
    893
    894 /* free hash table */
    895 assert(heurdata->hashtable != NULL);
    896 SCIPhashtableFree(&heurdata->hashtable);
    897
    898 return SCIP_OKAY;
    899}
    901/** execution method of primal heuristic */
    902static
    903SCIP_DECL_HEUREXEC(heurExecCrossover)
    904{ /*lint --e{715}*/
    905 SCIP* subscip; /* the subproblem created by crossover */
    906 SCIP_HEURDATA* heurdata; /* primal heuristic data */
    907 SCIP_VAR** vars; /* original problem's variables */
    908 SCIP_VAR** fixedvars;
    909 SCIP_SOL** sols;
    910 SCIP_RETCODE retcode;
    911 SCIP_Longint nstallnodes; /* node limit for the subproblem */
    912 SCIP_Bool success;
    913 SCIP_Real* fixedvals;
    914 int* selection; /* pool of solutions crossover uses */
    915 int nvars; /* number of original problem's variables */
    916 int nbinvars;
    917 int nintvars;
    918 int nusedsols;
    919 int nfixedvars;
    920
    921 assert(heur != NULL);
    922 assert(scip != NULL);
    923 assert(result != NULL);
    924
    925 /* get heuristic's data */
    926 heurdata = SCIPheurGetData(heur);
    927 assert(heurdata != NULL);
    928 nusedsols = heurdata->nusedsols;
    929
    930 *result = SCIP_DELAYED;
    931
    932 /* only call heuristic, if enough solutions are at hand */
    933 if( SCIPgetNSols(scip) < nusedsols )
    934 return SCIP_OKAY;
    935
    936 sols = SCIPgetSols(scip);
    937 assert(sols != NULL);
    938
    939 /* if one good solution was found, heuristic should not be delayed any longer */
    940 if( sols[nusedsols-1] != heurdata->prevlastsol )
    941 {
    942 heurdata->nextnodenumber = SCIPgetNNodes(scip);
    943 if( sols[0] != heurdata->prevbestsol )
    944 heurdata->nfailures = 0;
    945 }
    946 /* in nonrandomized mode: only recall heuristic, if at least one new good solution was found in the meantime */
    947 else if( !heurdata->randomization )
    948 return SCIP_OKAY;
    949
    950 /* if heuristic should be delayed, wait until certain number of nodes is reached */
    951 if( SCIPgetNNodes(scip) < heurdata->nextnodenumber )
    952 return SCIP_OKAY;
    953
    954 /* only call heuristic, if enough nodes were processed since last incumbent */
    955 if( SCIPgetNNodes(scip) - SCIPgetSolNodenum(scip, SCIPgetBestSol(scip)) < heurdata->nwaitingnodes
    956 && (SCIPgetDepth(scip) > 0 || !heurdata->dontwaitatroot) )
    957 return SCIP_OKAY;
    958
    959 *result = SCIP_DIDNOTRUN;
    960
    961 /* calculate the maximal number of branching nodes until heuristic is aborted */
    962 nstallnodes = (SCIP_Longint)(heurdata->nodesquot * SCIPgetNNodes(scip));
    963
    964 /* reward Crossover if it succeeded often */
    965 nstallnodes = (SCIP_Longint)
    966 (nstallnodes * (1.0 + 2.0*(SCIPheurGetNBestSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur)+1.0)));
    967
    968 /* count the setup costs for the sub-MIP as 100 nodes */
    969 nstallnodes -= 100 * SCIPheurGetNCalls(heur);
    970 nstallnodes += heurdata->nodesofs;
    971
    972 /* determine the node limit for the current process */
    973 nstallnodes -= heurdata->usednodes;
    974 nstallnodes = MIN(nstallnodes, heurdata->maxnodes);
    975
    976 /* check whether we have enough nodes left to call subproblem solving */
    977 if( nstallnodes < heurdata->minnodes )
    978 return SCIP_OKAY;
    979
    980 /* consider time and memory limits of the main SCIP */
    981 SCIP_CALL( SCIPcheckCopyLimits(scip, &success) );
    982
    983 if( !success )
    984 return SCIP_OKAY;
    985
    986 if( SCIPisStopped(scip) )
    987 return SCIP_OKAY;
    988
    989 /* get variable information */
    990 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
    991 assert(nvars > 0);
    992
    993 /* check whether discrete variables are available */
    994 if( nbinvars == 0 && nintvars == 0 )
    995 return SCIP_OKAY;
    996
    997 /* allocate necessary buffer storage for selection of variable fixings */
    998 SCIP_CALL( SCIPallocBufferArray(scip, &selection, nusedsols) );
    999 SCIP_CALL( SCIPallocBufferArray(scip, &fixedvars, nbinvars + nintvars) );
    1000 SCIP_CALL( SCIPallocBufferArray(scip, &fixedvals, nbinvars + nintvars) );
    1001
    1002 success = FALSE;
    1003 nfixedvars = 0;
    1004 /* determine fixings of variables with same value in a certain set of solutions */
    1005 SCIP_CALL( determineVariableFixings(scip, fixedvars, fixedvals, &nfixedvars, nbinvars + nintvars, selection, heurdata, &success) );
    1006
    1007 heurdata->prevbestsol = SCIPgetBestSol(scip);
    1008 heurdata->prevlastsol = sols[heurdata->nusedsols-1];
    1009
    1010 /* if creation of sub-SCIP was aborted (e.g. due to number of fixings), free sub-SCIP and abort */
    1011 if( !success )
    1012 {
    1013 /* this run will be counted as a failure since no new solution tuple could be generated or the neighborhood of the
    1014 * solution was not fruitful in the sense that it was too big
    1015 */
    1016 updateFailureStatistic(scip, heurdata);
    1017
    1018 goto TERMINATE;
    1019 }
    1020
    1021 *result = SCIP_DIDNOTFIND;
    1022 /* initializing the subproblem */
    1023 SCIP_CALL( SCIPcreate(&subscip) );
    1024
    1025 /* setup and solve the subproblem and catch the return code */
    1026 retcode = setupAndSolveSubscipCrossover(scip, subscip, heur, heurdata, vars,
    1027 fixedvars, fixedvals, nstallnodes, result, selection, nvars, nfixedvars, nusedsols);
    1028
    1029 /* free the subscip in any case */
    1030 SCIP_CALL( SCIPfree(&subscip) );
    1031 SCIP_CALL( retcode );
    1032
    1033TERMINATE:
    1034 /* free buffer storage for variable fixings */
    1035 SCIPfreeBufferArray(scip, &fixedvals);
    1036 SCIPfreeBufferArray(scip, &fixedvars);
    1037 SCIPfreeBufferArray(scip, &selection);
    1038
    1039 return SCIP_OKAY;
    1040}
    1041
    1042/*
    1043 * primal heuristic specific interface methods
    1045
    1046/** creates the crossover primal heuristic and includes it in SCIP */
    1048 SCIP* scip /**< SCIP data structure */
    1049 )
    1050{
    1051 SCIP_HEURDATA* heurdata;
    1052 SCIP_HEUR* heur;
    1053
    1054 /* create Crossover primal heuristic data */
    1055 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    1056
    1057 /* include primal heuristic */
    1060 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecCrossover, heurdata) );
    1061
    1062 assert(heur != NULL);
    1063
    1064 /* primal heuristic is safe to use in exact solving mode */
    1065 SCIPheurMarkExact(heur);
    1066
    1067 /* set non-NULL pointers to callback methods */
    1068 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyCrossover) );
    1069 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeCrossover) );
    1070 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitCrossover) );
    1071 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitCrossover) );
    1072
    1073 /* add crossover primal heuristic parameters */
    1074
    1075 SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/nodesofs",
    1076 "number of nodes added to the contingent of the total nodes",
    1077 &heurdata->nodesofs, FALSE, DEFAULT_NODESOFS, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
    1078
    1079 SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/maxnodes",
    1080 "maximum number of nodes to regard in the subproblem",
    1081 &heurdata->maxnodes, TRUE, DEFAULT_MAXNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
    1082
    1083 SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/minnodes",
    1084 "minimum number of nodes required to start the subproblem",
    1085 &heurdata->minnodes, TRUE, DEFAULT_MINNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
    1086
    1087 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/nusedsols",
    1088 "number of solutions to be taken into account",
    1089 &heurdata->nusedsols, FALSE, DEFAULT_NUSEDSOLS, 2, INT_MAX, NULL, NULL) );
    1090
    1091 SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/nwaitingnodes",
    1092 "number of nodes without incumbent change that heuristic should wait",
    1093 &heurdata->nwaitingnodes, TRUE, DEFAULT_NWAITINGNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
    1094
    1095 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/nodesquot",
    1096 "contingent of sub problem nodes in relation to the number of nodes of the original problem",
    1097 &heurdata->nodesquot, FALSE, DEFAULT_NODESQUOT, 0.0, 1.0, NULL, NULL) );
    1098
    1099 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/minfixingrate",
    1100 "minimum percentage of integer variables that have to be fixed",
    1101 &heurdata->minfixingrate, FALSE, DEFAULT_MINFIXINGRATE, 0.0, 1.0, NULL, NULL) );
    1102
    1103 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/minimprove",
    1104 "factor by which Crossover should at least improve the incumbent",
    1105 &heurdata->minimprove, TRUE, DEFAULT_MINIMPROVE, 0.0, 1.0, NULL, NULL) );
    1106
    1107 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/lplimfac",
    1108 "factor by which the limit on the number of LP depends on the node limit",
    1109 &heurdata->lplimfac, TRUE, DEFAULT_LPLIMFAC, 1.0, SCIP_REAL_MAX, NULL, NULL) );
    1110
    1111 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/randomization",
    1112 "should the choice which sols to take be randomized?",
    1113 &heurdata->randomization, TRUE, DEFAULT_RANDOMIZATION, NULL, NULL) );
    1114
    1115 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/dontwaitatroot",
    1116 "should the nwaitingnodes parameter be ignored at the root node?",
    1117 &heurdata->dontwaitatroot, TRUE, DEFAULT_DONTWAITATROOT, NULL, NULL) );
    1118
    1119 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/uselprows",
    1120 "should subproblem be created out of the rows in the LP rows?",
    1121 &heurdata->uselprows, TRUE, DEFAULT_USELPROWS, NULL, NULL) );
    1122
    1123 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/copycuts",
    1124 "if uselprows == FALSE, should all active cuts from cutpool be copied to constraints in subproblem?",
    1125 &heurdata->copycuts, TRUE, DEFAULT_COPYCUTS, NULL, NULL) );
    1126
    1127 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/permute",
    1128 "should the subproblem be permuted to increase diversification?",
    1129 &heurdata->permute, TRUE, DEFAULT_PERMUTE, NULL, NULL) );
    1130
    1131 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/bestsollimit",
    1132 "limit on number of improving incumbent solutions in sub-CIP",
    1133 &heurdata->bestsollimit, FALSE, DEFAULT_BESTSOLLIMIT, -1, INT_MAX, NULL, NULL) );
    1134
    1135 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/useuct",
    1136 "should uct node selection be used at the beginning of the search?",
    1137 &heurdata->useuct, TRUE, DEFAULT_USEUCT, NULL, NULL) );
    1138 return SCIP_OKAY;
    1139}
    SCIP_VAR * a
    Definition: circlepacking.c:66
    #define NULL
    Definition: def.h:257
    #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 REALABS(x)
    Definition: def.h:191
    #define SCIP_LONGINT_MAX
    Definition: def.h:151
    #define SCIP_CALL(x)
    Definition: def.h:364
    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 SCIPcheckCopyLimits(SCIP *sourcescip, SCIP_Bool *success)
    Definition: scip_copy.c:3250
    SCIP_RETCODE SCIPmergeVariableStatistics(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR **sourcevars, SCIP_VAR **targetvars, int nvars)
    Definition: scip_copy.c:1255
    SCIP_RETCODE SCIPcopyLimits(SCIP *sourcescip, SCIP *targetscip)
    Definition: scip_copy.c:3293
    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_RETCODE SCIPpermuteProb(SCIP *scip, unsigned int randseed, SCIP_Bool permuteconss, SCIP_Bool permutebinvars, SCIP_Bool permuteintvars, SCIP_Bool permutebinimplvars, SCIP_Bool permuteintimplvars, SCIP_Bool permutecontimplvars, SCIP_Bool permutecontvars)
    Definition: scip_prob.c:922
    SCIP_RETCODE SCIPwriteOrigProblem(SCIP *scip, const char *filename, const char *extension, SCIP_Bool genericnames)
    Definition: scip_prob.c:742
    SCIP_RETCODE SCIPsetObjlimit(SCIP *scip, SCIP_Real objlimit)
    Definition: scip_prob.c:1661
    SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
    Definition: scip_prob.c:2115
    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
    void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
    Definition: misc.c:2348
    SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
    Definition: misc.c:2647
    SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
    Definition: misc.c:2298
    SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
    Definition: misc.c:2535
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:111
    SCIP_Bool SCIPisParamFixed(SCIP *scip, const char *name)
    Definition: scip_param.c:219
    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 SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
    Definition: scip_param.c:545
    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 SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
    Definition: scip_param.c:904
    SCIP_RETCODE SCIPsetPresolving(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
    Definition: scip_param.c:956
    SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
    Definition: scip_param.c:661
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
    Definition: scip_param.c:429
    SCIP_RETCODE SCIPsetSeparating(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
    Definition: scip_param.c:985
    SCIP_RETCODE SCIPincludeHeurCrossover(SCIP *scip)
    SCIP_BRANCHRULE * SCIPfindBranchrule(SCIP *scip, const char *name)
    Definition: scip_branch.c:304
    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_RETCODE SCIPsetHeurExit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXIT((*heurexit)))
    Definition: scip_heur.c:215
    SCIP_Longint SCIPheurGetNBestSolsFound(SCIP_HEUR *heur)
    Definition: heur.c:1613
    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
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    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 SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_NODESEL * SCIPfindNodesel(SCIP *scip, const char *name)
    Definition: scip_nodesel.c:242
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2986
    SCIP_Longint SCIPsolGetNodenum(SCIP_SOL *sol)
    Definition: sol.c:4254
    int SCIPgetNSols(SCIP *scip)
    Definition: scip_sol.c:2887
    SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
    Definition: sol.c:4274
    int SCIPsolGetIndex(SCIP_SOL *sol)
    Definition: sol.c:4305
    SCIP_Longint SCIPgetSolNodenum(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:2221
    SCIP_SOL ** SCIPgetSols(SCIP *scip)
    Definition: scip_sol.c:2936
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    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_Real SCIPgetUpperbound(SCIP *scip)
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_RETCODE SCIPprintStatistics(SCIP *scip, FILE *file)
    SCIP_Real SCIPgetLowerbound(SCIP *scip)
    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_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPsumepsilon(SCIP *scip)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
    unsigned int SCIPinitializeRandomSeed(SCIP *scip, unsigned int initialseedvalue)
    SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
    int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
    Definition: misc.c:10223
    #define DEFAULT_NODESQUOT
    #define DEFAULT_NWAITINGNODES
    static SCIP_DECL_HEURFREE(heurFreeCrossover)
    #define DEFAULT_NODESOFS
    #define DEFAULT_COPYCUTS
    #define DEFAULT_MAXNODES
    static SCIP_DECL_HEUREXIT(heurExitCrossover)
    #define HEUR_TIMING
    #define DEFAULT_MINNODES
    #define DEFAULT_NUSEDSOLS
    struct SolTuple SOLTUPLE
    #define HEUR_FREQOFS
    #define DEFAULT_DONTWAITATROOT
    #define HEUR_DESC
    #define HASHSIZE_SOLS
    static SCIP_DECL_HASHKEYVAL(hashKeyValSols)
    #define DEFAULT_LPLIMFAC
    static SCIP_RETCODE fixVariables(SCIP *scip, SCIP_VAR **fixedvars, SCIP_Real *fixedvals, int *nfixedvars, int fixedvarssize, int *selection, SCIP_HEURDATA *heurdata, SCIP_Bool *success)
    static SCIP_RETCODE setupAndSolveSubscipCrossover(SCIP *scip, SCIP *subscip, SCIP_HEUR *heur, SCIP_HEURDATA *heurdata, SCIP_VAR **vars, SCIP_VAR **fixedvars, SCIP_Real *fixedvals, SCIP_Longint nstallnodes, SCIP_RESULT *result, int *selection, int nvars, int nfixedvars, int nusedsols)
    #define DEFAULT_MINFIXINGRATE
    #define DEFAULT_USEUCT
    #define HEUR_DISPCHAR
    #define HEUR_MAXDEPTH
    #define HEUR_PRIORITY
    static SCIP_DECL_HASHGETKEY(hashGetKeySols)
    #define DEFAULT_MINIMPROVE
    #define HEUR_NAME
    #define DEFAULT_USELPROWS
    #define DEFAULT_PERMUTE
    static SCIP_RETCODE createSolTuple(SCIP *scip, SOLTUPLE **elem, int *indices, int size, SCIP_HEURDATA *heurdata)
    static void sortArray(int *a, int size)
    #define DEFAULT_RANDOMIZATION
    static SCIP_RETCODE determineVariableFixings(SCIP *scip, SCIP_VAR **fixedvars, SCIP_Real *fixedvals, int *nfixedvars, int fixedvarssize, int *selection, SCIP_HEURDATA *heurdata, SCIP_Bool *success)
    static SCIP_Bool solHasNewSource(SCIP_SOL **sols, int *selection, int selectionsize, int newsol)
    static SCIP_RETCODE selectSolsRandomized(SCIP *scip, int *selection, SCIP_HEURDATA *heurdata, SCIP_Bool *success)
    static unsigned int calculateHashKey(int *indices, int size)
    static SCIP_DECL_HEUREXEC(heurExecCrossover)
    #define DEFAULT_BESTSOLLIMIT
    #define DEFAULT_RANDSEED
    static SCIP_DECL_EVENTEXEC(eventExecCrossover)
    #define EVENTHDLR_DESC
    static void updateFailureStatistic(SCIP *scip, SCIP_HEURDATA *heurdata)
    static SCIP_DECL_HASHKEYEQ(hashKeyEqSols)
    #define HEUR_FREQ
    static SCIP_DECL_HEURINIT(heurInitCrossover)
    #define HEUR_USESSUBSCIP
    static SCIP_DECL_HEURCOPY(heurCopyCrossover)
    #define EVENTHDLR_NAME
    LNS heuristic that tries to combine several feasible solutions.
    methods commonly used by primal heuristics
    memory allocation routines
    #define BMScopyMemoryArray(ptr, source, num)
    Definition: memory.h:134
    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 random numbers
    public methods for solutions
    public solving methods
    public methods for querying solving statistics
    public methods for the branch-and-bound tree
    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_PARAMSETTING_OFF
    Definition: type_paramset.h:63
    @ SCIP_PARAMSETTING_FAST
    Definition: type_paramset.h:62
    @ 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