SCIP

    Solving Constraint Integer Programs

    heur_indicatordiving.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_indicatordiving.c
    26 * @ingroup DEFPLUGINS_HEUR
    27 * @brief LP diving heuristic that fixes indicator variables controlling semicontinuous variables
    28 * @author Katrin Halbig
    29 * @author Alexander Hoen
    30 *
    31 * A diving heuristic iteratively rounds some fractional variables or variables determined by constraint handlers,
    32 * and resolves the LP relaxation. Thereby simulating a depth-first-search in the tree.
    33 *
    34 * Indicatordiving focuses on indicator variables, which control semicontinuous variables.
    35 * If the semicontinuous variable is unbounded, the indicator constraint is not part of the LP and,
    36 * therefore, the indicator variable is not set to an useful value in the LP solution.
    37 *
    38 * For these indicator variables the score depends on the LP value and the bounds of the corresponding semicontinuous variable.
    39 * If parameter usevarbounds=TRUE, also varbound constraints modeling semicontinuous variables are considered.
    40 * For all other variables the Farkas score (scaled) is returned.
    41 */
    42
    43/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    44
    45#include "scip/cons_indicator.h"
    46#include "scip/cons_varbound.h"
    48#include "scip/heuristics.h"
    49#include "scip/pub_cons.h"
    50#include "scip/pub_heur.h"
    51#include "scip/pub_message.h"
    52#include "scip/pub_misc.h"
    53#include "scip/pub_var.h"
    54#include "scip/scip_cons.h"
    55#include "scip/scip_heur.h"
    56#include "scip/scip_mem.h"
    57#include "scip/scip_numerics.h"
    58#include "scip/scip_param.h"
    59#include "scip/scip_probing.h"
    60#include "scip/scip_sol.h"
    61#include "scip/scip_tree.h"
    62#include "scip/scip_prob.h"
    63#include "scip/scip_message.h"
    64
    65#define HEUR_NAME "indicatordiving"
    66#define HEUR_DESC "LP diving heuristic that fixes indicator variables controlling semicontinuous variables"
    67#define HEUR_DISPCHAR 'I'
    68#define HEUR_PRIORITY -150000
    69#define HEUR_FREQ 0
    70#define HEUR_FREQOFS 0
    71#define HEUR_MAXDEPTH -1
    72#define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
    73#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
    74#define DIVESET_DIVETYPES SCIP_DIVETYPE_INTEGRALITY /**< bit mask that represents all supported dive types */
    75#define DIVESET_ISPUBLIC FALSE /**< is this dive set publicly available (ie., can be used by other primal heuristics?) */
    76
    77
    78/*
    79 * Default parameter settings
    80 */
    81
    82#define DEFAULT_MINRELDEPTH 0.0 /**< minimal relative depth to start diving */
    83#define DEFAULT_MAXRELDEPTH 1.0 /**< maximal relative depth to start diving */
    84#define DEFAULT_MAXLPITERQUOT 0.05 /**< maximal fraction of diving LP iterations compared to node LP iterations */
    85#define DEFAULT_MAXLPITEROFS 1000 /**< additional number of allowed LP iterations */
    86#define DEFAULT_MAXDIVEUBQUOT 0.8 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
    87 * where diving is performed (0.0: no limit) */
    88#define DEFAULT_MAXDIVEAVGQUOT 0.0 /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
    89 * where diving is performed (0.0: no limit) */
    90#define DEFAULT_MAXDIVEUBQUOTNOSOL 0.1 /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
    91#define DEFAULT_MAXDIVEAVGQUOTNOSOL 0.0 /**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
    92#define DEFAULT_BACKTRACK TRUE /**< use one level of backtracking if infeasibility is encountered? */
    93#define DEFAULT_LPRESOLVEDOMCHGQUOT 0.15 /**< percentage of immediate domain changes during probing to trigger LP resolve */
    94#define DEFAULT_LPSOLVEFREQ 30 /**< LP solve frequency for diving heuristics */
    95#define DEFAULT_ONLYLPBRANCHCANDS FALSE /**< should only LP branching candidates be considered instead of the slower but
    96 * more general constraint handler diving variable selection? */
    97#define DEFAULT_RANDSEED 11 /**< initial seed for random number generation */
    98
    99/*
    100 * Heuristic specific parameters
    101 */
    102#define DEFAULT_ROUNDINGFRAC 0.5 /**< default setting for parameter roundingfrac */
    103#define DEFAULT_ROUNDINGMODE 0 /**< default setting for parameter roundingmode */
    104#define DEFAULT_SEMICONTSCOREMODE 0 /**< default setting for parameter semicontscoremode */
    105#define DEFAULT_USEVARBOUNDS TRUE /**< default setting for parameter usevarbounds */
    106#define DEFAULT_RUNWITHOUTSCINDS FALSE /**< default setting for parameter runwithoutscinds */
    107
    109{
    114
    115/** data structure to store information of a semicontinuous variable
    116 *
    117 * For a variable x (not stored in the struct), this stores the data of nbnds implications
    118 * bvars[i] = 0 -> x = vals[i]
    119 * bvars[i] = 1 -> lbs[i] <= x <= ubs[i]
    120 * where bvars[i] are binary variables.
    121 */
    123{
    124 SCIP_Real* vals0; /**< values of the variable when the corresponding bvars[i] = 0 */
    125 SCIP_Real* lbs1; /**< global lower bounds of the variable when the corresponding bvars[i] = 1 */
    126 SCIP_Real* ubs1; /**< global upper bounds of the variable when the corresponding bvars[i] = 1 */
    127 SCIP_VAR** bvars; /**< the binary variables on which the variable domain depends */
    128 int nbnds; /**< number of suitable on/off bounds the var has */
    129 int bndssize; /**< size of the arrays */
    130};
    131typedef struct SCVarData SCVARDATA;
    132
    133
    134/** locally defined heuristic data */
    135struct SCIP_HeurData
    136{
    137 SCIP_SOL* sol; /**< working solution */
    138 SCIP_CONSHDLR* indicatorconshdlr; /**< indicator constraint handler */
    139 SCIP_CONSHDLR* varboundconshdlr; /**< varbound constraint handler */
    140 SCIP_HASHMAP* scvars; /**< hashmap to store semicontinuous variables */
    141 SCIP_HASHMAP* indicatormap; /**< hashmap to store indicator constraints of binary variables */
    142 SCIP_HASHMAP* varboundmap; /**< hashmap to store varbound constraints of binary variables */
    143 SCIP_Real roundingfrac; /**< in violation case all fractional below this value are fixed to constant */
    144 int roundingmode; /**< decides which roundingmode is selected (0: conservative (default), 1: aggressive) */
    145 int semicontscoremode; /**< which values of semi-continuous variables should get a high score? (0: low (default), 1: middle, 2: high) */
    146 SCIP_Bool usevarbounds; /**< should varbound constraints be considered? */
    147 SCIP_Bool runwithoutscinds; /**< should heur run if there are no indicator constraints modeling semicont. vars? */
    148 SCIP_Bool gotoindconss; /**< can we skip the candidate var until indicator conss handler determines the candidate var? */
    149 SCIP_Bool containsviolindconss;/**< contains current solution violated indicator constraints? (only unbounded) */
    150 SCIP_Bool newnode; /**< are we at a new probing node? */
    151 int probingdepth; /**< current probing depth */
    152};
    153
    154/*
    155 * Local methods
    156 */
    157
    158/** checks if constraint is violated but not fixed, i.e., it will be a diving candidate variable */
    159static
    161 SCIP* scip, /**< SCIP data structure */
    162 SCIP_SOL* sol, /**< pointer to solution */
    163 SCIP_CONS* cons /**< pointer to indicator constraint */
    164 )
    165{
    166 SCIP_VAR* binvar;
    167 SCIP_Real solval;
    168
    170
    171 if( !SCIPisViolatedIndicator(scip, cons, sol) )
    172 return FALSE;
    173
    174 binvar = SCIPgetBinaryVarIndicator(cons);
    175 solval = SCIPgetSolVal(scip, sol, binvar);
    176
    177 return (SCIPisFeasIntegral(scip, solval) && SCIPvarGetLbLocal(binvar) < SCIPvarGetUbLocal(binvar) - 0.5);
    178}
    179
    180/** releases all data from given hashmap filled with SCVarData and the hashmap itself */
    181static
    183 SCIP* scip, /**< SCIP data structure */
    184 SCIP_HASHMAP* hashmap /**< hashmap to be freed */
    185 )
    186{
    187 SCIP_HASHMAPENTRY* entry;
    188 SCVARDATA* data;
    189 int c;
    190
    191 if( hashmap != NULL )
    192 {
    193 for( c = 0; c < SCIPhashmapGetNEntries( hashmap ); c++ )
    194 {
    195 entry = SCIPhashmapGetEntry( hashmap, c);
    196 if( entry != NULL )
    197 {
    198 data = (SCVARDATA*) SCIPhashmapEntryGetImage(entry);
    204 }
    205 }
    206 SCIPhashmapFree(&hashmap);
    207 assert(hashmap == NULL);
    208 }
    209
    210 return SCIP_OKAY;
    211}
    212
    213/** checks if variable is indicator variable and stores corresponding indicator constraint; additionally, if we are at a
    214 * new probing node, it checks whether there are violated but not fixed indicator constraints
    215 */
    216static
    218 SCIP* scip, /**< SCIP data structure */
    219 SCIP_VAR* cand, /**< candidate variable */
    220 SCIP_HASHMAP* map, /**< pointer to hashmap containing indicator conss */
    221 SCIP_CONS** cons, /**< pointer to store indicator constraint */
    222 SCIP_Bool* isindicator, /**< pointer to store whether candidate variable is indicator variable */
    223 SCIP_Bool* containsviolindconss,/**< pointer to store whether there are violated and not fixed (unbounded) indicator constraints */
    224 SCIP_Bool newnode, /**< are we at a new probing node? */
    225 SCIP_SOL* sol, /**< pointer to solution */
    226 SCIP_CONSHDLR* conshdlr /**< constraint handler */
    227 )
    228{
    229 assert(scip != NULL);
    230 assert(cand != NULL);
    231 assert(map != NULL);
    232 assert(cons != NULL);
    233 assert(isindicator != NULL);
    234 assert(sol != NULL);
    235
    236 *cons = NULL;
    237 *isindicator = FALSE;
    238
    239 *cons = (SCIP_CONS*) SCIPhashmapGetImage(map, cand);
    240 if( *cons != NULL )
    241 *isindicator = TRUE;
    242
    243 /* since we are at a new probing node, check if there are violated and not fixed indicator constraints */
    244 if( newnode )
    245 {
    246 SCIP_CONS** indicatorconss;
    247 int nconss;
    248 int c;
    249
    250 indicatorconss = SCIPconshdlrGetConss(conshdlr);
    251 nconss = SCIPconshdlrGetNActiveConss(conshdlr);
    252 *containsviolindconss = FALSE;
    253
    254 for( c = 0; c < nconss; c++ )
    255 {
    256 *containsviolindconss = *containsviolindconss || isViolatedAndNotFixed(scip, sol, indicatorconss[c]);
    257
    258 if( *containsviolindconss )
    259 break;
    260 }
    261 }
    262}
    263
    264/** checks if variable is binary variable of varbound constraint and stores corresponding varbound constraint */
    265static
    267 SCIP* scip, /**< SCIP data structure */
    268 SCIP_VAR* cand, /**< candidate variable */
    269 SCIP_HASHMAP* map, /**< pointer to hashmap containing varbound conss */
    270 SCIP_CONS** cons, /**< pointer to store varbound constraint */
    271 SCIP_Bool* isvarbound /**< pointer to store whether candidate variable is indicator variable */
    272 )
    273{
    274 assert(scip != NULL);
    275 assert(cand != NULL);
    276 assert(map != NULL);
    277 assert(cons != NULL);
    278 assert(isvarbound != NULL);
    279
    280 *cons = NULL;
    281 *isvarbound = FALSE;
    282
    284 return;
    285
    286 *cons = (SCIP_CONS*) SCIPhashmapGetImage(map, cand);
    287 if( *cons != NULL )
    288 *isvarbound = TRUE;
    289}
    290
    291/** adds an indicator to the data of a semicontinuous variable */
    292static
    294 SCIP* scip, /**< SCIP data structure */
    295 SCVARDATA* scvdata, /**< semicontinuous variable data */
    296 SCIP_VAR* indicator, /**< indicator to be added */
    297 SCIP_Real val0, /**< value of the variable when indicator == 0 */
    298 SCIP_Real lb1, /**< lower bound of the variable when indicator == 1 */
    299 SCIP_Real ub1 /**< upper bound of the variable when indicator == 1 */
    300 )
    301{
    302 int newsize;
    303 int i;
    304 SCIP_Bool found;
    305 int pos;
    306
    307 assert(scvdata != NULL);
    308 assert(indicator != NULL);
    309
    310 /* find the position where to insert */
    311 if( scvdata->bvars == NULL )
    312 {
    313 assert(scvdata->nbnds == 0 && scvdata->bndssize == 0);
    314 found = FALSE;
    315 pos = 0;
    316 }
    317 else
    318 {
    319 found = SCIPsortedvecFindPtr((void**)scvdata->bvars, SCIPvarComp, (void*)indicator, scvdata->nbnds, &pos);
    320 }
    321
    322 if( found )
    323 return SCIP_OKAY;
    324
    325 /* ensure sizes */
    326 if( scvdata->nbnds + 1 > scvdata->bndssize )
    327 {
    328 newsize = SCIPcalcMemGrowSize(scip, scvdata->nbnds + 1);
    329 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->bvars, scvdata->bndssize, newsize) );
    330 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->vals0, scvdata->bndssize, newsize) );
    331 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->lbs1, scvdata->bndssize, newsize) );
    332 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->ubs1, scvdata->bndssize, newsize) );
    333 scvdata->bndssize = newsize;
    334 }
    335 assert(scvdata->nbnds + 1 <= scvdata->bndssize);
    336 assert(scvdata->bvars != NULL);
    337
    338 /* move entries if needed */
    339 for( i = scvdata->nbnds; i > pos; --i )
    340 {
    341 /* coverity[var_deref_op] */
    342 scvdata->bvars[i] = scvdata->bvars[i-1];
    343 scvdata->vals0[i] = scvdata->vals0[i-1];
    344 scvdata->lbs1[i] = scvdata->lbs1[i-1];
    345 scvdata->ubs1[i] = scvdata->ubs1[i-1];
    346 }
    347
    348 scvdata->bvars[pos] = indicator;
    349 scvdata->vals0[pos] = val0;
    350 scvdata->lbs1[pos] = lb1;
    351 scvdata->ubs1[pos] = ub1;
    352 ++scvdata->nbnds;
    353
    354 return SCIP_OKAY;
    355}
    356
    357/** checks if a variable is semicontinuous and stores it data in the hashmap scvars
    358 *
    359 * A variable x is semicontinuous if its bounds depend on at least one binary variable called the indicator,
    360 * and indicator == 0 => x == x^0 for some real constant x^0.
    361 */
    362static
    364 SCIP* scip, /**< SCIP data structure */
    365 SCIP_VAR* var, /**< the variable to check */
    366 SCIP_HASHMAP* scvars, /**< semicontinuous variable information */
    367 SCIP_Real constant, /**< value which should be equal to the constant */
    368 SCIP_Bool* result /**< buffer to store whether var is semicontinuous */
    369 )
    370{
    371 SCIP_Real lb0;
    372 SCIP_Real ub0;
    373 SCIP_Real lb1;
    374 SCIP_Real ub1;
    375 SCIP_Real glb;
    376 SCIP_Real gub;
    377 SCIP_Bool exists;
    378 int c;
    379 int pos;
    380 SCIP_VAR** vlbvars;
    381 SCIP_VAR** vubvars;
    382 SCIP_Real* vlbcoefs;
    383 SCIP_Real* vubcoefs;
    384 SCIP_Real* vlbconstants;
    385 SCIP_Real* vubconstants;
    386 int nvlbs;
    387 int nvubs;
    388 SCVARDATA* scvdata;
    389 SCIP_VAR* bvar;
    390
    391 assert(scip != NULL);
    392 assert(var != NULL);
    393 assert(scvars != NULL);
    394 assert(result != NULL);
    395
    396 scvdata = (SCVARDATA*) SCIPhashmapGetImage(scvars, (void*)var);
    397 if( scvdata != NULL )
    398 {
    399 *result = TRUE;
    400 return SCIP_OKAY;
    401 }
    402
    403 vlbvars = SCIPvarGetVlbVars(var);
    404 vubvars = SCIPvarGetVubVars(var);
    405 vlbcoefs = SCIPvarGetVlbCoefs(var);
    406 vubcoefs = SCIPvarGetVubCoefs(var);
    407 vlbconstants = SCIPvarGetVlbConstants(var);
    408 vubconstants = SCIPvarGetVubConstants(var);
    409 nvlbs = SCIPvarGetNVlbs(var);
    410 nvubs = SCIPvarGetNVubs(var);
    411 glb = SCIPvarGetLbGlobal(var);
    412 gub = SCIPvarGetUbGlobal(var);
    413
    414 pos = -1;
    415
    416 *result = FALSE;
    417
    418 /* Scan through lower bounds; for each binary vlbvar save the corresponding lb0 and lb1.
    419 * Then check if there is an upper bound with this vlbvar and save ub0 and ub1.
    420 * If the found bounds imply that the var value is fixed to some val0 when vlbvar = 0,
    421 * save vlbvar and val0 to scvdata.
    422 */
    423 for( c = 0; c < nvlbs; ++c )
    424 {
    425 if( SCIPvarGetType(vlbvars[c]) != SCIP_VARTYPE_BINARY || SCIPvarIsImpliedIntegral(vlbvars[c]) )
    426 continue;
    427
    428 bvar = vlbvars[c];
    429
    430 lb0 = MAX(vlbconstants[c], glb);
    431 lb1 = MAX(vlbconstants[c] + vlbcoefs[c], glb);
    432
    433 /* look for bvar in vubvars */
    434 if( vubvars != NULL )
    435 exists = SCIPsortedvecFindPtr((void**)vubvars, SCIPvarComp, bvar, nvubs, &pos);
    436 else
    437 exists = FALSE;
    438
    439 if( exists )
    440 {
    441 /* save the upper bounds */
    442 ub0 = MIN(vubconstants[pos], gub);
    443 ub1 = MIN(vubconstants[pos] + vubcoefs[pos], gub);
    444 }
    445 else
    446 {
    447 /* if there is no upper bound with vubvar = bvar, use global var bounds */
    448 ub0 = gub;
    449 ub1 = gub;
    450 }
    451
    452 /* the 'off' domain of a semicontinuous var should reduce to a single point (constant) and be different from the 'on' domain */
    453 if( SCIPisEQ(scip, lb0, constant) && (!SCIPisEQ(scip, lb0, lb1) || !SCIPisEQ(scip, ub0, ub1)) )
    454 {
    455 if( scvdata == NULL )
    456 {
    458 }
    459 SCIP_CALL( addSCVarIndicator(scip, scvdata, bvar, lb0, lb1, ub1) );
    460 }
    461 }
    462
    463 /* look for vubvars that have not been processed yet */
    464 assert(vubvars != NULL || nvubs == 0);
    465 for( c = 0; c < nvubs; ++c )
    466 {
    467 /* coverity[var_deref_op] */
    468 if( SCIPvarGetType(vubvars[c]) != SCIP_VARTYPE_BINARY || SCIPvarIsImpliedIntegral(vubvars[c]) ) /*lint !e613*/
    469 continue;
    470
    471 bvar = vubvars[c]; /*lint !e613*/
    472
    473 /* skip vars that are in vlbvars */
    474 if( vlbvars != NULL && SCIPsortedvecFindPtr((void**)vlbvars, SCIPvarComp, bvar, nvlbs, &pos) )
    475 continue;
    476
    477 lb0 = glb;
    478 lb1 = glb;
    479 ub0 = MIN(vubconstants[c], gub);
    480 ub1 = MIN(vubconstants[c] + vubcoefs[c], gub);
    481
    482 /* the 'off' domain of a semicontinuous var should reduce to a single point (constant) and be different from the 'on' domain */
    483 if( SCIPisEQ(scip, lb0, constant) && (!SCIPisEQ(scip, lb0, lb1) || !SCIPisEQ(scip, ub0, ub1)) )
    484 {
    485 if( scvdata == NULL )
    486 {
    488 }
    489
    490 SCIP_CALL( addSCVarIndicator(scip, scvdata, bvar, lb0, lb1, ub1) );
    491 }
    492 }
    493
    494 if( scvdata != NULL )
    495 {
    496#ifdef SCIP_DEBUG
    497 SCIPdebugMsg(scip, "var <%s> has global bounds [%f, %f] and the following on/off bounds:\n", SCIPvarGetName(var), glb, gub);
    498 for( c = 0; c < scvdata->nbnds; ++c )
    499 {
    500 SCIPdebugMsg(scip, " c = %d, bvar <%s>: val0 = %f\n", c, SCIPvarGetName(scvdata->bvars[c]), scvdata->vals0[c]);
    501 }
    502#endif
    503 SCIP_CALL( SCIPhashmapInsert(scvars, var, scvdata) );
    504 *result = TRUE;
    505 }
    506
    507 return SCIP_OKAY;
    508}
    509
    510/** checks if there are unfixed indicator variables modeling semicont. vars */
    511static
    513 SCIP* scip, /**< SCIP data structure */
    514 SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
    515 SCIP_HASHMAP* scvars, /**< semicontinuous variable information */
    516 SCIP_Bool* hasunfixedscindconss /**< pointer to store if there are unfixed indicator variables modeling semicont. vars */
    517 )
    518{
    519 SCIP_CONS** indicatorconss;
    520 SCIP_VAR** consvars;
    521 SCIP_Real* consvals;
    522 int nconss;
    523 int i;
    524
    525 *hasunfixedscindconss = FALSE;
    526 indicatorconss = SCIPconshdlrGetConss(conshdlr);
    527 nconss = SCIPconshdlrGetNConss(conshdlr);
    528 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) );
    529 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) );
    530
    531 for( i = 0; i < nconss; i++ )
    532 {
    533 SCIP_VAR *binvar;
    534 SCIP_VAR* semicontinuousvar;
    535 SCIP_CONS* lincons;
    536 SCIP_Real rhs;
    537 int nconsvars;
    538 SCIP_Bool success;
    539 int v;
    540
    541 binvar = SCIPgetBinaryVarIndicator(indicatorconss[i]);
    542
    543 /* check if indicator variable is unfixed */
    544 if( SCIPvarGetLbLocal(binvar) < SCIPvarGetUbLocal(binvar) - 0.5 )
    545 {
    546 lincons = SCIPgetLinearConsIndicator(indicatorconss[i]);
    547 rhs = SCIPconsGetRhs(scip, lincons, &success);
    548 SCIP_CALL( SCIPgetConsNVars(scip, lincons, &nconsvars, &success) );
    549
    550 /* check if constraint contains only two variables with finite rhs */
    551 /* TODO: allow also indicators for lower bounds */
    552 if( nconsvars == 2 && !SCIPisInfinity(scip, rhs) )
    553 {
    554 SCIP_CALL( SCIPgetConsVars(scip, lincons, consvars, nconsvars, &success) );
    555 SCIP_CALL( SCIPgetConsVals(scip, lincons, consvals, nconsvars, &success) );
    556
    557 for( v = 0; v < nconsvars ; v++ )
    558 {
    559 if( consvars[v] == SCIPgetSlackVarIndicator(indicatorconss[i]) ) /* note that we have exact two variables */
    560 continue;
    561
    562 semicontinuousvar = consvars[v];
    563 SCIP_CALL( varIsSemicontinuous(scip, semicontinuousvar, scvars, rhs, &success) );
    564
    565 /* check if semicontinuous variable */
    566 if( success )
    567 {
    568 *hasunfixedscindconss = TRUE;
    569 break;
    570 }
    571 }
    572 if( *hasunfixedscindconss )
    573 break;
    574 }
    575 }
    576 }
    577 SCIPfreeBufferArray(scip, &consvals);
    578 SCIPfreeBufferArray(scip, &consvars);
    579 return SCIP_OKAY;
    580}
    581
    582/** creates and initializes hashmaps
    583 *
    584 * indicatormap: binary var -> indicator constraint
    585 * varboundmap: binary var -> varbound constraint
    586 *
    587 * Currently exactly one constraint is assigned to a binary variable (per hashmap),
    588 * but a binary variable can also control more than one constraint.
    589 * TODO: Allow more than one corresponding indicator/varbound constraint per binary variable.
    590 */
    591static
    593 SCIP* scip, /**< SCIP data structure */
    594 SCIP_CONSHDLR* indicatorconshdlr, /**< indicator constraint handler */
    595 SCIP_CONSHDLR* varboundconshdlr, /**< varbound constraint handler */
    596 SCIP_Bool usevarbounds, /**< should varbound constraints be considered? */
    597 SCIP_HASHMAP** indicatormap, /**< hashmap to store indicator constraints of binary variables */
    598 SCIP_HASHMAP** varboundmap /**< hashmap to store varbound constraints of binary variables */
    599 )
    600{
    601 SCIP_CONS** conss;
    602 int nconss;
    603 int i;
    604
    605 SCIP_STRINGEQ( SCIPconshdlrGetName(indicatorconshdlr), "indicator", SCIP_INVALIDCALL );
    606 SCIP_STRINGEQ( SCIPconshdlrGetName(varboundconshdlr), "varbound", SCIP_INVALIDCALL );
    607
    608 /* indicator constraints */
    609 nconss = SCIPconshdlrGetNConss(indicatorconshdlr);
    610 conss = SCIPconshdlrGetConss(indicatorconshdlr);
    611 SCIP_CALL( SCIPhashmapCreate(indicatormap, SCIPblkmem(scip), nconss) );
    612 for( i = 0; i < nconss; i++ )
    613 {
    614 if( !SCIPhashmapExists(*indicatormap, SCIPgetBinaryVarIndicator(conss[i])) )
    615 {
    616 SCIP_CALL( SCIPhashmapInsert(*indicatormap, SCIPgetBinaryVarIndicator(conss[i]), conss[i]) );
    617 }
    618 }
    619
    620 /* varbound constraints */
    621 if( usevarbounds )
    622 {
    623 nconss = SCIPconshdlrGetNConss(varboundconshdlr);
    624 conss = SCIPconshdlrGetConss(varboundconshdlr);
    625 SCIP_CALL( SCIPhashmapCreate(varboundmap, SCIPblkmem(scip), nconss) );
    626 for( i = 0; i < nconss; i++ )
    627 {
    628 if( !SCIPhashmapExists(*varboundmap, SCIPgetVbdvarVarbound(scip, conss[i])) )
    629 {
    630 SCIP_CALL( SCIPhashmapInsert(*varboundmap, SCIPgetVbdvarVarbound(scip, conss[i]), conss[i]) );
    631 }
    632 }
    633 }
    634 return SCIP_OKAY;
    635}
    636
    637#define MIN_RAND 1e-06
    638#define MAX_RAND 1e-05
    639
    640/** calculate score and preferred rounding direction for the candidate variable */
    641static
    643 SCIP* scip, /**< SCIP data structure */
    644 SCIP_DIVESET* diveset, /**< diving settings */
    645 SCIP_VAR* cand, /**< candidate variable */
    646 SCIP_Real candsfrac, /**< fractional part of solution value of candidate variable */
    647 SCIP_Bool* roundup, /**< pointer to store whether the preferred rounding direction is upwards */
    648 SCIP_Real* score /**< pointer for diving score value */
    649 )
    650{
    651 SCIP_RANDNUMGEN* randnumgen;
    652 SCIP_Real obj;
    653
    654 randnumgen = SCIPdivesetGetRandnumgen(diveset);
    655 assert(randnumgen != NULL);
    656
    657 obj = SCIPvarGetObj(cand);
    658
    659 /* dive towards the pseudosolution, at the same time approximate the contribution to
    660 * a potential Farkas-proof (infeasibility proof) by y^TA_i = c_i.
    661 */
    662 if( SCIPisNegative(scip, obj) )
    663 *roundup = TRUE;
    664 else if( SCIPisPositive(scip, obj) )
    665 *roundup = FALSE;
    666 else
    667 {
    668 if( SCIPisEQ(scip, candsfrac, 0.5) )
    669 *roundup = !SCIPrandomGetInt(randnumgen, 0, 1);
    670 else
    671 *roundup = (candsfrac > 0.5);
    672 }
    673
    674 /* larger score is better */
    675 *score = REALABS(obj) + SCIPrandomGetReal(randnumgen, MIN_RAND, MAX_RAND);
    676
    677 /* prefer decisions on binary variables */
    679 *score = -1.0 / *score;
    680}
    681
    682
    683/*
    684 * Callback methods
    685 */
    686
    687/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    688static
    689SCIP_DECL_HEURCOPY(heurCopyIndicatordiving)
    690{ /*lint --e{715}*/
    691 assert(scip != NULL);
    692 assert(heur != NULL);
    693
    695
    696 /* call inclusion method of primal heuristic */
    698
    699 return SCIP_OKAY;
    700}
    701
    702
    703/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    704static
    705SCIP_DECL_HEURFREE(heurFreeIndicatordiving)
    706{ /*lint --e{715}*/
    707 SCIP_HEURDATA* heurdata;
    708
    709 assert(heur != NULL);
    710 assert(scip != NULL);
    711
    713
    714 /* free heuristic data */
    715 heurdata = SCIPheurGetData(heur);
    716 assert(heurdata != NULL);
    717
    718 SCIPfreeBlockMemory(scip, &heurdata);
    719 SCIPheurSetData(heur, NULL);
    720
    721 return SCIP_OKAY;
    722}
    723
    724
    725/** initialization method of primal heuristic (called after problem was transformed) */
    726static
    727SCIP_DECL_HEURINIT(heurInitIndicatordiving)
    728{ /*lint --e{715}*/
    729 SCIP_HEURDATA* heurdata;
    730
    731 assert(heur != NULL);
    732 assert(scip != NULL);
    733
    735
    736 /* get heuristic data */
    737 heurdata = SCIPheurGetData(heur);
    738 assert(heurdata != NULL);
    739
    740 /* create working data */
    741 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
    742 SCIP_CALL( SCIPhashmapCreate( &heurdata->scvars, SCIPblkmem( scip ), SCIPgetNVars(scip)) );
    743
    744 heurdata->indicatorconshdlr = SCIPfindConshdlr(scip, "indicator");
    745 heurdata->varboundconshdlr = SCIPfindConshdlr(scip, "varbound");
    746
    747 return SCIP_OKAY;
    748}
    749
    750
    751/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    752static
    753SCIP_DECL_HEUREXIT(heurExitIndicatordiving)
    754{ /*lint --e{715}*/
    755 SCIP_HEURDATA* heurdata;
    756
    757 assert(heur != NULL);
    758 assert(scip != NULL);
    759
    761
    762 /* get heuristic data */
    763 heurdata = SCIPheurGetData(heur);
    764 assert(heurdata != NULL);
    765
    766 /* free working data */
    767 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
    768 SCIP_CALL( releaseSCHashmap(scip, heurdata->scvars) );
    769
    770 return SCIP_OKAY;
    771}
    772
    773
    774/** execution method of primal heuristic */
    775static
    776SCIP_DECL_HEUREXEC(heurExecIndicatordiving)
    777{ /*lint --e{715}*/
    778 SCIP_HEURDATA* heurdata;
    779 SCIP_DIVESET* diveset;
    780 SCIP_Bool hasunfixedscindconss; /* are there unfixed indicator variables modeling a semicont. variable? */
    781
    782 heurdata = SCIPheurGetData(heur);
    783 assert(heurdata != NULL);
    784
    785 assert(SCIPheurGetNDivesets(heur) > 0);
    786 assert(SCIPheurGetDivesets(heur) != NULL);
    787 diveset = SCIPheurGetDivesets(heur)[0];
    788 assert(diveset != NULL);
    789
    790 assert(result != NULL);
    791 *result = SCIP_DIDNOTRUN;
    792
    793 /* check if there are unfixed indicator variables modeling semicont. vars */
    794 SCIP_CALL( hasUnfixedSCIndicator(scip, heurdata->indicatorconshdlr, heurdata->scvars, &hasunfixedscindconss) );
    795
    796 /* skip heuristic if problem doesn't contain unfixed indicator variables,
    797 * or if there are no varbound constraints which should be considered
    798 */
    799 if( !hasunfixedscindconss && (!heurdata->runwithoutscinds || !heurdata->usevarbounds || SCIPconshdlrGetNConss(heurdata->varboundconshdlr) == 0) )
    800 return SCIP_OKAY;
    801
    802 SCIPdebugMsg(scip, "call heurExecIndicatordiving at depth %d \n", SCIPgetDepth(scip));
    803
    804 /* create and initialize hashmaps */
    805 SCIP_CALL( createMaps(scip, heurdata->indicatorconshdlr, heurdata->varboundconshdlr, heurdata->usevarbounds, &heurdata->indicatormap, &heurdata->varboundmap) );
    806
    807 /* (re-)set flags */
    808 heurdata->gotoindconss = FALSE;
    809 heurdata->containsviolindconss = FALSE;
    810 heurdata->newnode = TRUE;
    811 heurdata->probingdepth = -1;
    812
    813 SCIP_CALL( SCIPperformGenericDivingAlgorithm(scip, diveset, heurdata->sol, heur, result, nodeinfeasible, -1L, -1, -1.0, SCIP_DIVECONTEXT_SINGLE) );
    814
    815 /* free hashmaps since constraints can get removed/modified till the next call */
    816 if( heurdata->usevarbounds )
    817 SCIPhashmapFree(&heurdata->varboundmap);
    818 SCIPhashmapFree(&heurdata->indicatormap);
    819
    820 SCIPdebugMsg(scip, "leave heurExecIndicatordiving\n");
    821
    822 return SCIP_OKAY;
    823}
    824
    825
    826/** calculate score and preferred rounding direction for the candidate variable */
    827static
    828SCIP_DECL_DIVESETGETSCORE(divesetGetScoreIndicatordiving)
    829{ /*lint --e{715}*/
    830 SCIP_HEUR* heur;
    831 SCIP_HEURDATA* heurdata;
    832 SCIP_RANDNUMGEN* randnumgen;
    833 SCIP_VAR** consvars;
    834 SCIP_CONS* indicatorcons;
    835 SCIP_CONS* varboundcons;
    836 SCIP_CONS* lincons;
    837 SCIP_VAR* nonoptionvar; /* second variable in linear cons which is not the option variable (indicator: slackvar, varbound: binary var) */
    838 SCIP_VAR* semicontinuousvar;
    839 SCIP_Real lpsolsemicontinuous;
    840 SCVARDATA* scdata;
    841 SCIP_Real* consvals;
    842 SCIP_Real side;
    843 int nconsvars;
    844 int idxbvars; /* index of bounding variable in hashmap scdata */
    845 SCIP_Bool isindicatorvar;
    846 SCIP_Bool isvbdvar; /* variable bounding variable in varbound */
    847 SCIP_Bool issemicont; /* indicates whether variable has (maybe) required semicont. properties */
    848 SCIP_Bool fixconstant; /* should we fix the semicontinuous variable to its constant? */
    849 SCIP_Bool success;
    850 int v;
    851 int b;
    852
    853 varboundcons = NULL;
    854 semicontinuousvar = NULL;
    855 scdata = NULL;
    856 lpsolsemicontinuous = 0.0;
    857 idxbvars = -1;
    858 isvbdvar = FALSE;
    859 issemicont = TRUE;
    860
    861 heur = SCIPdivesetGetHeur(diveset);
    862 assert(heur != NULL);
    863 heurdata = SCIPheurGetData(heur);
    864 assert(heurdata != NULL);
    865
    866 randnumgen = SCIPdivesetGetRandnumgen(diveset);
    867 assert(randnumgen != NULL);
    868
    869 /* check if we are at a new probing node; since diving heuristics backtrack at most one probing node, we are at a new
    870 * node iff the probing depth increased */
    871 if( heurdata->probingdepth < SCIPgetProbingDepth(scip) )
    872 heurdata->newnode = TRUE;
    873 else
    874 {
    875 assert(heurdata->probingdepth == SCIPgetProbingDepth(scip));
    876 heurdata->newnode = FALSE;
    877 }
    878 heurdata->probingdepth = SCIPgetProbingDepth(scip);
    879
    880 /* skip if current candidate can not be determined by the indicator constraint handler and violated indicator
    881 * constraints still exists */
    882 if( !(SCIPisFeasIntegral(scip, candsol) && SCIPvarGetLbLocal(cand) < SCIPvarGetUbLocal(cand) - 0.5)
    883 && heurdata->gotoindconss )
    884 {
    885 *score = SCIP_REAL_MIN;
    886 *roundup = FALSE;
    887 return SCIP_OKAY;
    888 }
    889 else
    890 heurdata->gotoindconss = FALSE;
    891
    892 /* check if candidate variable is indicator variable */
    893 checkAndGetIndicator(scip, cand, heurdata->indicatormap, &indicatorcons, &isindicatorvar,
    894 &heurdata->containsviolindconss, heurdata->newnode, heurdata->sol, heurdata->indicatorconshdlr);
    895
    896 /* skip candidate in next calls since we have violated indicator constraints but current candidate is not determined
    897 * by the indicator constraint handler */
    898 if( heurdata->containsviolindconss &&
    899 !((SCIPisFeasIntegral(scip, candsol) && SCIPvarGetLbLocal(cand) < SCIPvarGetUbLocal(cand) - 0.5) && isindicatorvar) )
    900 {
    901 heurdata->gotoindconss = TRUE;
    902 *score = SCIP_REAL_MIN;
    903 *roundup = FALSE;
    904 return SCIP_OKAY;
    905 }
    906
    907 /* check if candidate variable is bounding variable */
    908 if( heurdata->usevarbounds && !isindicatorvar )
    909 {
    910 checkAndGetVarbound(scip, cand, heurdata->varboundmap, &varboundcons, &isvbdvar);
    911 }
    912
    913 /* Return
    914 * - if candidate variable is neither a indicator variable nor a variable bounding variable
    915 * - or if candidate variable is not an indicator variable but there will be indicator variables as candidates
    916 * - or if candidate variable is not an indicator variable and varbound constraints are not considered.
    917 */
    918 if( !isindicatorvar && (!isvbdvar || heurdata->containsviolindconss || !heurdata->usevarbounds) )
    919 {
    920 *score = SCIP_REAL_MIN;
    921 *roundup = FALSE;
    922
    923 if( !heurdata->containsviolindconss && !isvbdvar )
    924 {
    925 getScoreOfFarkasDiving(scip, diveset, cand, candsfrac, roundup, score);
    926 *score = (*score / (100 + fabs(*score))) * 100 - 200; /* scale to [-300,-100] */
    927 }
    928 return SCIP_OKAY;
    929 }
    930
    931 SCIPdebugMsg(scip, "cand: %s, candsol: %.2f, candobjcoeff: %f\n", SCIPvarGetName(cand), candsol, SCIPvarGetObj(cand));
    932
    933 if( isindicatorvar ) /* prefer indicator constraint */
    934 {
    935 SCIP_Real rhs;
    936
    937 lincons = SCIPgetLinearConsIndicator(indicatorcons);
    938 nonoptionvar = SCIPgetSlackVarIndicator(indicatorcons);
    939 rhs = SCIPconsGetRhs(scip, lincons, &success);
    940 issemicont = SCIPisInfinity(scip, -SCIPconsGetLhs(scip, lincons, &success)); /* TODO: allow also indicators for lower bounds */
    941 side = rhs;
    942 }
    943 else
    944 {
    945 SCIP_Real rhs;
    946 SCIP_Real lhs;
    947
    948 assert(isvbdvar);
    949
    950 lincons = varboundcons;
    951 nonoptionvar = SCIPgetVbdvarVarbound(scip, varboundcons);
    952 rhs = SCIPconsGetRhs(scip, lincons, &success);
    953 lhs = SCIPconsGetLhs(scip, lincons, &success);
    954 side = SCIPisInfinity(scip, rhs) ? lhs : rhs;
    955 assert(!SCIPisInfinity(scip, side));
    956 }
    957 SCIPdebugPrintCons(scip, lincons, NULL);
    958
    959 SCIP_CALL( SCIPgetConsNVars(scip, lincons, &nconsvars, &success) );
    960
    961 if( nconsvars != 2 || !issemicont )
    962 {
    963 getScoreOfFarkasDiving(scip, diveset, cand, candsfrac, roundup, score);
    964 *score = (*score / (100 + fabs(*score))) * 100 - 200; /* scale to [-300,-100] */
    965 return SCIP_OKAY;
    966 }
    967
    968 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nconsvars) );
    969 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) );
    970 SCIP_CALL( SCIPgetConsVars(scip, lincons, consvars, nconsvars, &success) );
    971 SCIP_CALL( SCIPgetConsVals(scip, lincons, consvals, nconsvars, &success) );
    972
    973 issemicont = FALSE;
    974 for( v = 0; v < nconsvars ; v++ )
    975 {
    976 if( consvars[v] == nonoptionvar ) /* note that we have exact two variables */
    977 continue;
    978
    979 semicontinuousvar = consvars[v];
    980 lpsolsemicontinuous = SCIPvarGetLPSol( semicontinuousvar );
    981 SCIPdebugMsg(scip, "%s lp sol %f %f\n", SCIPvarGetName( semicontinuousvar ), lpsolsemicontinuous,
    982 consvals[v] );
    983 SCIP_CALL( varIsSemicontinuous(scip, semicontinuousvar, heurdata->scvars, side, &success) );
    984
    985 /* only allow semicontinuous variables */
    986 if( success )
    987 {
    988 assert(SCIPhashmapExists(heurdata->scvars, (void*) semicontinuousvar));
    989 scdata = (SCVARDATA*) SCIPhashmapGetImage(heurdata->scvars, (void*) semicontinuousvar);
    990 assert(scdata != NULL);
    991
    992 for( b = 0; b < scdata->nbnds; b++ )
    993 {
    994 if( (scdata->bvars[b] == cand || (SCIPvarIsNegated(cand) && scdata->bvars[0] == SCIPvarGetNegationVar(cand)))
    995 && SCIPisEQ(scip, side, scdata->vals0[b]) )
    996 {
    997 /* TODO: handle also more general variables;
    998 * currently we handle only variables with domain vals0 < lb1 <= ub1 */
    999 if( SCIPisGE(scip, lpsolsemicontinuous, scdata->vals0[b]) && SCIPisLE(scip, lpsolsemicontinuous, scdata->ubs1[b]) )
    1000 {
    1001 issemicont = TRUE;
    1002 idxbvars = b;
    1003 break;
    1004 }
    1005 }
    1006 }
    1007 }
    1008 }
    1009
    1010 /* only continue if semicontinuous variable */
    1011 if( !issemicont )
    1012 {
    1013 getScoreOfFarkasDiving(scip, diveset, cand, candsfrac, roundup, score);
    1014 *score = (*score / (100 + fabs(*score))) * 100 - 200; /* scale to [-300,-100] */
    1015 SCIPfreeBufferArray(scip, &consvals);
    1016 SCIPfreeBufferArray(scip, &consvars);
    1017 return SCIP_OKAY;
    1018 }
    1019 assert(idxbvars >= 0);
    1020 assert(scdata != NULL);
    1021
    1022 /* Case: Variable is in range [lb1,ub1] */
    1023 if( SCIPisGE(scip, lpsolsemicontinuous, scdata->lbs1[idxbvars]) && SCIPisLE(scip, lpsolsemicontinuous, scdata->ubs1[idxbvars]))
    1024 {
    1025 *score = SCIPrandomGetReal(randnumgen, -1.0, 0.0);
    1026 fixconstant = FALSE;
    1027 }
    1028 /* Case: Variable is equal to constant */
    1029 else if( SCIPisEQ(scip, lpsolsemicontinuous, scdata->vals0[idxbvars]) )
    1030 {
    1031 *score = SCIPrandomGetReal(randnumgen, -1.0, 0.0);
    1032 fixconstant = TRUE;
    1033 }
    1034 /* Case: Variable is between constant and lb1 */
    1035 else
    1036 {
    1037 SCIP_Real shiftedlpsolsemicontinuous = lpsolsemicontinuous;
    1038 SCIP_Real shiftedlbs1 = scdata->lbs1[idxbvars];
    1039
    1040 assert(SCIPisGT(scip, lpsolsemicontinuous, scdata->vals0[idxbvars]) && SCIPisLT(scip, lpsolsemicontinuous, scdata->lbs1[idxbvars]));
    1041
    1042 /* handle case if constant of semicont. var is not zero -> shift values */
    1043 if( !SCIPisZero(scip, scdata->vals0[idxbvars]) )
    1044 {
    1045 shiftedlpsolsemicontinuous -= scdata->vals0[idxbvars];
    1046 shiftedlbs1 -= scdata->vals0[idxbvars];
    1047 }
    1048
    1049 *score = 100 * (shiftedlbs1 - shiftedlpsolsemicontinuous) / shiftedlbs1;
    1050 assert(*score>0);
    1051
    1052 switch( (INDICATORDIVINGROUNDINGMODE)heurdata->roundingmode )
    1053 {
    1055 fixconstant = (*score > (1 - heurdata->roundingfrac) * 100);
    1056 break;
    1058 fixconstant = (*score <= (1 - heurdata->roundingfrac) * 100);
    1059 break;
    1060 default:
    1061 return SCIP_INVALIDDATA;
    1062 }
    1063
    1064 switch( heurdata->semicontscoremode )
    1065 {
    1066 case 0:
    1067 break;
    1068 case 1:
    1069 if( shiftedlpsolsemicontinuous < shiftedlbs1 * heurdata->roundingfrac )
    1070 *score = 100 * (shiftedlpsolsemicontinuous / (heurdata->roundingfrac * shiftedlbs1));
    1071 else
    1072 *score = 100 * (-shiftedlpsolsemicontinuous / ((1 - heurdata->roundingfrac) * shiftedlbs1) + (1 / (1 - heurdata->roundingfrac)) );
    1073 break;
    1074 case 2:
    1075 *score = 100 - *score;
    1076 break;
    1077 default:
    1078 return SCIP_INVALIDDATA;
    1079 }
    1080 assert(*score>0);
    1081 }
    1082
    1083 /* Set roundup depending on whether we have an indicator constraint or a varbound constraint:
    1084 * - indicator constraint: roundup == fix to constant
    1085 * - varbound constraint: roundup == push to range
    1086 */
    1087 *roundup = isindicatorvar ? fixconstant : !fixconstant; /*lint !e644*/
    1088
    1089 /* free memory */
    1090 SCIPfreeBufferArray(scip, &consvals);
    1091 SCIPfreeBufferArray(scip, &consvars);
    1092
    1093 return SCIP_OKAY;
    1094}
    1095
    1096
    1097/** callback to check preconditions for diving, e.g., if an incumbent solution is available */
    1098static
    1099SCIP_DECL_DIVESETAVAILABLE(divesetAvailableIndicatordiving)
    1100{
    1101 /* Skip if problem doesn't contain indicator constraints.
    1102 * If varbound constraints should be considered, skip only if there are also no varbound constraints.
    1103 */
    1104 *available = SCIPconshdlrGetNActiveConss(SCIPfindConshdlr(scip, "indicator")) == 0;
    1105
    1106 if( !*available )
    1107 {
    1108 SCIP_HEUR* heur;
    1109 SCIP_HEURDATA* heurdata;
    1110
    1111 heur = SCIPdivesetGetHeur(diveset);
    1112 assert(heur != NULL);
    1113 heurdata = SCIPheurGetData(heur);
    1114 assert(heurdata != NULL);
    1115
    1116 if( heurdata->runwithoutscinds && heurdata->usevarbounds )
    1117 {
    1118 *available = SCIPconshdlrGetNActiveConss(SCIPfindConshdlr(scip, "varbound")) == 0;
    1119 }
    1120 }
    1121
    1122 return SCIP_OKAY;
    1123}
    1124
    1125/*
    1126 * heuristic specific interface methods
    1127 */
    1128
    1129/** creates the indicatordiving heuristic and includes it in SCIP */
    1131 SCIP* scip /**< SCIP data structure */
    1132 )
    1133{
    1134 SCIP_HEURDATA* heurdata;
    1135 SCIP_HEUR* heur;
    1136
    1137 /* create indicatordiving primal heuristic data */
    1138 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    1139
    1140 heur = NULL;
    1141
    1142 /* include primal heuristic */
    1145 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecIndicatordiving, heurdata) );
    1146
    1147 assert(heur != NULL);
    1148
    1149 /* primal heuristic is safe to use in exact solving mode */
    1150 SCIPheurMarkExact(heur);
    1151
    1152 /* set non fundamental callbacks via setter functions */
    1153 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyIndicatordiving) );
    1154 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeIndicatordiving) );
    1155 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitIndicatordiving) );
    1156 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitIndicatordiving) );
    1157
    1158 /* create a diveset (this will automatically install some additional parameters for the heuristic)*/
    1162 DIVESET_ISPUBLIC, DIVESET_DIVETYPES, divesetGetScoreIndicatordiving, divesetAvailableIndicatordiving) );
    1163
    1164 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/roundingfrac",
    1165 "in violation case all fractional below this value are fixed to constant",
    1166 &heurdata->roundingfrac, FALSE, DEFAULT_ROUNDINGFRAC, 0.0, 1.0, NULL, NULL) );
    1167
    1168 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/roundingmode",
    1169 "decides which roundingmode is selected (0: conservative, 1: aggressive)",
    1170 &heurdata->roundingmode, FALSE, DEFAULT_ROUNDINGMODE, 0, 1, NULL, NULL) );
    1171
    1172 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/semicontscoremode",
    1173 "which values of semi-continuous variables should get a high score? (0: low, 1: middle, 2: high)",
    1174 &heurdata->semicontscoremode, FALSE, DEFAULT_SEMICONTSCOREMODE, 0, 2, NULL, NULL) );
    1175
    1176 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/usevarbounds",
    1177 "should varbound constraints be considered?",
    1178 &heurdata->usevarbounds, FALSE, DEFAULT_USEVARBOUNDS, NULL, NULL) );
    1179
    1180 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/runwithoutscinds",
    1181 "should heur run if there are no indicator constraints modeling semicont. vars?",
    1182 &heurdata->runwithoutscinds, FALSE, DEFAULT_RUNWITHOUTSCINDS, NULL, NULL) );
    1183
    1184 return SCIP_OKAY;
    1185}
    SCIP_VAR ** b
    Definition: circlepacking.c:65
    constraint handler for indicator constraints
    Constraint handler for variable bound constraints .
    #define NULL
    Definition: def.h:257
    #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_REAL_MIN
    Definition: def.h:168
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_VAR * SCIPgetVbdvarVarbound(SCIP *scip, SCIP_CONS *cons)
    SCIP_VAR * SCIPgetBinaryVarIndicator(SCIP_CONS *cons)
    SCIP_VAR * SCIPgetSlackVarIndicator(SCIP_CONS *cons)
    SCIP_CONS * SCIPgetLinearConsIndicator(SCIP_CONS *cons)
    SCIP_Bool SCIPisViolatedIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
    Definition: misc.c:3613
    void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3284
    SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
    Definition: misc.c:3143
    int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
    Definition: misc.c:3584
    SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
    Definition: misc.c:3592
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    #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 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 SCIPincludeHeurIndicatordiving(SCIP *scip)
    int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4782
    const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4320
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4816
    SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4739
    SCIP_RETCODE SCIPgetConsNVars(SCIP *scip, SCIP_CONS *cons, int *nvars, SCIP_Bool *success)
    Definition: scip_cons.c:2621
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8413
    SCIP_RETCODE SCIPgetConsVars(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **vars, int varssize, SCIP_Bool *success)
    Definition: scip_cons.c:2577
    SCIP_RETCODE SCIPcreateDiveset(SCIP *scip, SCIP_DIVESET **diveset, SCIP_HEUR *heur, const char *name, SCIP_Real minreldepth, SCIP_Real maxreldepth, SCIP_Real maxlpiterquot, SCIP_Real maxdiveubquot, SCIP_Real maxdiveavgquot, SCIP_Real maxdiveubquotnosol, SCIP_Real maxdiveavgquotnosol, SCIP_Real lpresolvedomchgquot, int lpsolvefreq, int maxlpiterofs, unsigned int initialseed, SCIP_Bool backtrack, SCIP_Bool onlylpbranchcands, SCIP_Bool ispublic, SCIP_Bool specificsos1score, SCIP_DECL_DIVESETGETSCORE((*divesetgetscore)), SCIP_DECL_DIVESETAVAILABLE((*divesetavailable)))
    Definition: scip_heur.c:323
    SCIP_RANDNUMGEN * SCIPdivesetGetRandnumgen(SCIP_DIVESET *diveset)
    Definition: heur.c:720
    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
    int SCIPheurGetNDivesets(SCIP_HEUR *heur)
    Definition: heur.c:1675
    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
    SCIP_DIVESET ** SCIPheurGetDivesets(SCIP_HEUR *heur)
    Definition: heur.c:1665
    void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
    Definition: heur.c:1378
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    #define SCIPallocClearBlockMemory(scip, ptr)
    Definition: scip_mem.h:91
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
    Definition: scip_mem.h:99
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    int SCIPgetProbingDepth(SCIP *scip)
    Definition: scip_probing.c:199
    SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:514
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1250
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_RETCODE SCIPperformGenericDivingAlgorithm(SCIP *scip, SCIP_DIVESET *diveset, SCIP_SOL *worksol, SCIP_HEUR *heur, SCIP_RESULT *result, SCIP_Bool nodeinfeasible, SCIP_Longint iterlim, int nodelimit, SCIP_Real lpresolvedomchgquot, SCIP_DIVECONTEXT divecontext)
    Definition: heuristics.c:221
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    int SCIPvarGetNVlbs(SCIP_VAR *var)
    Definition: var.c:24514
    SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
    Definition: var.c:24536
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23530
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
    Definition: var.c:24546
    int SCIPvarGetNVubs(SCIP_VAR *var)
    Definition: var.c:24556
    SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
    Definition: var.c:24696
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
    Definition: var.c:23475
    SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
    Definition: var.c:23910
    SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
    Definition: var.c:24526
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
    Definition: var.c:24588
    SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
    Definition: var.c:24568
    SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
    Definition: var.c:24578
    SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
    Definition: misc.c:10245
    int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
    Definition: misc.c:10223
    SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
    SCIP_HEUR * SCIPdivesetGetHeur(SCIP_DIVESET *diveset)
    Definition: heur.c:416
    #define DEFAULT_ONLYLPBRANCHCANDS
    static SCIP_RETCODE releaseSCHashmap(SCIP *scip, SCIP_HASHMAP *hashmap)
    #define DEFAULT_MAXDIVEUBQUOT
    #define DEFAULT_LPRESOLVEDOMCHGQUOT
    static SCIP_DECL_DIVESETGETSCORE(divesetGetScoreIndicatordiving)
    #define DEFAULT_ROUNDINGMODE
    static void checkAndGetIndicator(SCIP *scip, SCIP_VAR *cand, SCIP_HASHMAP *map, SCIP_CONS **cons, SCIP_Bool *isindicator, SCIP_Bool *containsviolindconss, SCIP_Bool newnode, SCIP_SOL *sol, SCIP_CONSHDLR *conshdlr)
    static SCIP_RETCODE createMaps(SCIP *scip, SCIP_CONSHDLR *indicatorconshdlr, SCIP_CONSHDLR *varboundconshdlr, SCIP_Bool usevarbounds, SCIP_HASHMAP **indicatormap, SCIP_HASHMAP **varboundmap)
    #define HEUR_TIMING
    #define DEFAULT_USEVARBOUNDS
    enum IndicatorDivingRoundingMode INDICATORDIVINGROUNDINGMODE
    #define DEFAULT_MAXLPITERQUOT
    #define HEUR_FREQOFS
    #define HEUR_DESC
    #define DEFAULT_MAXDIVEAVGQUOT
    #define DEFAULT_LPSOLVEFREQ
    static SCIP_DECL_DIVESETAVAILABLE(divesetAvailableIndicatordiving)
    static SCIP_RETCODE hasUnfixedSCIndicator(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_HASHMAP *scvars, SCIP_Bool *hasunfixedscindconss)
    #define DEFAULT_BACKTRACK
    #define DEFAULT_MAXDIVEUBQUOTNOSOL
    #define HEUR_DISPCHAR
    #define HEUR_MAXDEPTH
    #define HEUR_PRIORITY
    static void getScoreOfFarkasDiving(SCIP *scip, SCIP_DIVESET *diveset, SCIP_VAR *cand, SCIP_Real candsfrac, SCIP_Bool *roundup, SCIP_Real *score)
    #define DEFAULT_SEMICONTSCOREMODE
    #define DEFAULT_MAXRELDEPTH
    #define DEFAULT_ROUNDINGFRAC
    #define DEFAULT_MAXLPITEROFS
    static SCIP_DECL_HEUREXIT(heurExitIndicatordiving)
    static SCIP_DECL_HEURINIT(heurInitIndicatordiving)
    static SCIP_RETCODE varIsSemicontinuous(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *scvars, SCIP_Real constant, SCIP_Bool *result)
    #define DEFAULT_MAXDIVEAVGQUOTNOSOL
    #define HEUR_NAME
    static void checkAndGetVarbound(SCIP *scip, SCIP_VAR *cand, SCIP_HASHMAP *map, SCIP_CONS **cons, SCIP_Bool *isvarbound)
    static SCIP_DECL_HEURFREE(heurFreeIndicatordiving)
    #define MAX_RAND
    static SCIP_RETCODE addSCVarIndicator(SCIP *scip, SCVARDATA *scvdata, SCIP_VAR *indicator, SCIP_Real val0, SCIP_Real lb1, SCIP_Real ub1)
    #define DEFAULT_RANDSEED
    #define DIVESET_DIVETYPES
    static SCIP_Bool isViolatedAndNotFixed(SCIP *scip, SCIP_SOL *sol, SCIP_CONS *cons)
    #define DEFAULT_RUNWITHOUTSCINDS
    #define DIVESET_ISPUBLIC
    #define HEUR_FREQ
    #define MIN_RAND
    #define DEFAULT_MINRELDEPTH
    #define HEUR_USESSUBSCIP
    IndicatorDivingRoundingMode
    @ ROUNDING_CONSERVATIVE
    @ ROUNDING_AGGRESSIVE
    static SCIP_DECL_HEURCOPY(heurCopyIndicatordiving)
    static SCIP_DECL_HEUREXEC(heurExecIndicatordiving)
    LP diving heuristic that fixes indicator variables controlling semicontinuous variables.
    methods commonly used by primal heuristics
    SCIP_Real SCIPconsGetLhs(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
    Definition: misc_linear.c:112
    SCIP_RETCODE SCIPgetConsVals(SCIP *scip, SCIP_CONS *cons, SCIP_Real *vals, int varssize, SCIP_Bool *success)
    Definition: misc_linear.c:253
    SCIP_Real SCIPconsGetRhs(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
    Definition: misc_linear.c:48
    public methods for managing constraints
    public methods for primal heuristics
    public methods for message output
    #define SCIPdebugPrintCons(x, y, z)
    Definition: pub_message.h:102
    public data structures and miscellaneous methods
    public methods for problem variables
    public methods for constraint handler plugins and constraints
    public methods for primal heuristic plugins and divesets
    public methods for memory management
    public methods for message handling
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for the probing mode
    public methods for solutions
    public methods for the branch-and-bound tree
    SCIP_SOL * sol
    Definition: struct_heur.h:71
    SCIP_Real * vals0
    SCIP_VAR ** bvars
    SCIP_Real * ubs1
    SCIP_Real * lbs1
    struct SCIP_HeurData SCIP_HEURDATA
    Definition: type_heur.h:77
    @ SCIP_DIVECONTEXT_SINGLE
    Definition: type_heur.h:69
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_INVALIDDATA
    Definition: type_retcode.h:52
    @ 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_VARTYPE_BINARY
    Definition: type_var.h:64