SCIP

    Solving Constraint Integer Programs

    prop_vbounds.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 prop_vbounds.c
    26 * @ingroup DEFPLUGINS_PROP
    27 * @brief variable upper and lower bound propagator
    28 * @author Stefan Heinz
    29 * @author Jens Schulz
    30 * @author Gerald Gamrath
    31 * @author Marc Pfetsch
    32 *
    33 * This propagator uses global bound information provided by SCIP to deduce global and local bound changes.
    34 * It can take into account
    35 * - implications (bound change following from specific value of a binary variable)
    36 * - cliques (set of binary variables, each with a corresponding value, of which at most one variable can get the value)
    37 * - variable lower/upper bounds (bounds of arbitrary variables that depend linearly on the value of another variable)
    38 *
    39 * The propagator does not look at a variable in whole, but at one point in time only handles one specific bound (lower
    40 * or upper) of a variable and deduces changes for lower or upper bounds of other variables. The concept is as follows:
    41 *
    42 * 1) Extract variable bound data
    43 *
    44 * Implications and cliques are stored in a way such that given a variable and its new value, we can access all bound
    45 * changes that can be deduced from setting the variable to that value. However, for variable bounds, this currently
    46 * does not hold, they are only stored in the other direction, i.e. for a bound of a given variable, we have a list
    47 * of all other bounds of variables that directly influence the bound of the given variable and a linear function
    48 * describing how they do this.
    49 * For the propagation, we need the other direction, thus we store it in the propagator data when the branch-and-bound
    50 * solving process is about to begin.
    51 *
    52 * 2) Topological sorting of bounds of variable
    53 *
    54 * We compute a topological order of the bounds of variables. This is needed to define an order in which we will
    55 * regard bounds of variables in the propagation process in order to avoid unneccessarily regarding the same variable
    56 * bound multiple times because it was changed in the meantime when propagating another bound of a variable.
    57 * Therefore, we implictly regard a directed graph, in which each node corresponds to a bound of a variable and there
    58 * exists a directed edge from one node to another, if the bound corresponding to the former node influences the
    59 * bound corresponding to the latter node. This is done by iteratively running a DFS until all nodes were visited.
    60 * Note that there might be cycles in the graph, which are randomly broken, so the order is only almost topological.
    61 *
    62 * 3) Collecting bound changes
    63 *
    64 * For each bound of a variable, which can trigger bound changes of other variables, the propagator catches all
    65 * events informing about a global change of the bound or a local tightening of the bound. The event handler
    66 * then adds the bound of the variable to a priority queue, with the key in the priority queue corresponding
    67 * to the position of the bound in the topological sort.
    68 *
    69 * 4) Propagating Bounds
    70 *
    71 * As long as there are bounds contained in the priority queue, the propagator pops one bound from the queue, which
    72 * is the one most at the beginning of the topological sort, so it should not be influenced by propagating other
    73 * bounds currently contained in the queue. Starting at this bound, all implication, clique, and variable bound
    74 * information is used to deduce tigther bounds for other variables and change the bounds, if a tighter one is found.
    75 * These bound changes trigger an event that will lead to adding the corresponding bound to the priority queue,
    76 * if it is not contained, yet. The process is iterated until the priority queue contains no more bounds.
    77 *
    78 * Additionally, the propagator analyzes the conflict/clique graph during presolving. It uses Tarjan's algorithm to
    79 * search for strongly connected components, for each of which all variables can be aggregated to one. Additionally,
    80 * it may detect invalid assignments of binary variables and fix the variable to the only possible value left.
    81 */
    82
    83/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    84
    86#include "scip/prop_vbounds.h"
    87#include "scip/pub_event.h"
    88#include "scip/pub_implics.h"
    89#include "scip/pub_message.h"
    90#include "scip/pub_misc.h"
    91#include "scip/pub_prop.h"
    92#include "scip/pub_var.h"
    93#include "scip/scip_conflict.h"
    94#include "scip/scip_event.h"
    95#include "scip/scip_general.h"
    96#include "scip/scip_mem.h"
    97#include "scip/scip_message.h"
    98#include "scip/scip_numerics.h"
    99#include "scip/scip_param.h"
    100#include "scip/scip_prob.h"
    101#include "scip/scip_prop.h"
    102#include "scip/scip_tree.h"
    103#include "scip/scip_var.h"
    104
    105
    106/**@name Propagator properties
    107 *
    108 * @{
    109 */
    110
    111#define PROP_NAME "vbounds"
    112#define PROP_DESC "propagates variable upper and lower bounds"
    113#define PROP_TIMING SCIP_PROPTIMING_BEFORELP | SCIP_PROPTIMING_AFTERLPLOOP
    114#define PROP_PRIORITY 3000000 /**< propagator priority */
    115#define PROP_FREQ 1 /**< propagator frequency */
    116#define PROP_DELAY FALSE /**< should propagation method be delayed, if other propagators found reductions? */
    117
    118#define PROP_PRESOL_PRIORITY -90000 /**< priority of the presolving method (>= 0: before, < 0: after constraint handlers); combined with presolvers */
    119#define PROP_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM | SCIP_PRESOLTIMING_EXHAUSTIVE
    120#define PROP_PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no
    121 * limit) */
    122/**@} */
    123
    124/**@name Event handler properties
    125 *
    126 * @{
    127 */
    128
    129#define EVENTHDLR_NAME "vbounds"
    130#define EVENTHDLR_DESC "bound change event handler for for vbounds propagator"
    131
    132/**@} */
    133
    134/**@name Default parameter values
    135 *
    136 * @{
    137 */
    138
    139#define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used to initialize conflict analysis? */
    140#define DEFAULT_USEIMPLICS FALSE /**< should implications be propagated? */
    141#define DEFAULT_USECLIQUES FALSE /**< should cliques be propagated? */
    142#define DEFAULT_USEVBOUNDS TRUE /**< should variable bounds be propagated? */
    143#define DEFAULT_DOTOPOSORT TRUE /**< should the bounds be topologically sorted in advance? */
    144#define DEFAULT_SORTCLIQUES FALSE /**< should cliques be regarded for the topological sort? */
    145#define DEFAULT_DETECTCYCLES FALSE /**< should cycles in the variable bound graph be identified? */
    146#define DEFAULT_MINNEWCLIQUES 0.1 /**< minimum number of new cliques to trigger another clique table analysis */
    147#define DEFAULT_MAXCLIQUESMEDIUM 50.0 /**< maximum number of cliques per variable to run clique table analysis in
    148 * medium presolving */
    149#define DEFAULT_MAXCLIQUESEXHAUSTIVE 100.0 /**< maximum number of cliques per variable to run clique table analysis in
    150 * exhaustive presolving */
    151
    152/**@} */
    153
    154/**@name Propagator defines
    155 *
    156 * @{
    157 *
    158 * The propagator works on indices representing a bound of a variable. This index will be called bound index in the
    159 * following. For a given active variable with problem index i (note that active variables have problem indices
    160 * between 0 and nactivevariable - 1), the bound index of its lower bound is 2*i, the bound index of its upper
    161 * bound is 2*i + 1. The other way around, a given bound index i corresponds to the variable with problem index
    162 * i/2 (rounded down), and to the lower bound, if i is even, to the upper bound if i is odd.
    163 * The following macros can be used to convert bound index into variable problem index and boundtype and vice versa.
    164 */
    165#define getLbIndex(idx) (2*(idx))
    166#define getUbIndex(idx) (2*(idx)+1)
    167#define getVarIndex(idx) ((idx)/2)
    168#define getBoundtype(idx) (((idx) % 2 == 0) ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER)
    169#define isIndexLowerbound(idx) ((idx) % 2 == 0)
    170#define getBoundString(lower) ((lower) ? "lb" : "ub")
    171#define getBoundtypeString(type) ((type) == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper")
    172#define indexGetBoundString(idx) (getBoundString(isIndexLowerbound(idx)))
    173#define getOtherBoundIndex(idx) ((idx) + 1 - 2 * ((idx) % 2))
    174
    175/**@} */
    176
    177/*
    178 * Data structures
    179 */
    180
    181/** propagator data */
    182struct SCIP_PropData
    183{
    184 SCIP_EVENTHDLR* eventhdlr; /**< event handler for catching bound changes */
    185 SCIP_VAR** vars; /**< array containing all variable which are considered within the propagator */
    186 SCIP_HASHMAP* varhashmap; /**< hashmap mapping from variable to index in the vars array */
    187 int* topoorder; /**< array mapping on the bounds of variables in topological order;
    188 * or -1, if the bound that should be at that position has no outgoing
    189 * implications, cliques, or vbounds;
    190 * i.e., for i < j and topoorder[i] != -1 != topoorder[j], the variable
    191 * and boundtype represented by index topoorder[i] are earlier in the
    192 * topological order than those represented by index topoorder[j]
    193 */
    194 int** vboundboundedidx; /**< array storing for each bound index the bound indices of all bounds
    195 * influenced by this bound through variable bounds */
    196 SCIP_Real** vboundcoefs; /**< array storing for each bound index the coefficients in the variable
    197 * bounds influencing the corresponding bound index stored in
    198 * vboundboundedidx */
    199 SCIP_Real** vboundconstants; /**< array storing for each bound index the constants in the variable
    200 * bounds influencing the corresponding bound index stored in
    201 * vboundboundedidx */
    202 int* nvbounds; /**< array storing for each bound index the number of vbounds stored */
    203 int* vboundsize; /**< array with sizes of vbound arrays for the nodes */
    204 int nbounds; /**< number of bounds of variables regarded (two times number of active variables) */
    205 int lastpresolncliques; /**< number of cliques created until the last call to the presolver */
    206 SCIP_PQUEUE* propqueue; /**< priority queue to handle the bounds of variables that were changed and have to be propagated */
    207 SCIP_Bool* inqueue; /**< boolean array to store whether a bound of a variable is already contained in propqueue */
    208 SCIP_Bool initialized; /**< was the data for propagation already initialized? */
    209 SCIP_Real minnewcliques; /**< minimum percentage of new cliques to trigger another clique table analysis */
    210 SCIP_Real maxcliquesmedium; /**< maximum number of cliques per variable to run clique table analysis in medium presolving */
    211 SCIP_Real maxcliquesexhaustive;/**< maximum number of cliques per variable to run clique table analysis in exhaustive presolving */
    212 SCIP_Bool usebdwidening; /**< should bound widening be used to initialize conflict analysis? */
    213 SCIP_Bool useimplics; /**< should implications be propagated? */
    214 SCIP_Bool usecliques; /**< should cliques be propagated? */
    215 SCIP_Bool usevbounds; /**< should variable bounds be propagated? */
    216 SCIP_Bool dotoposort; /**< should the bounds be topologically sorted in advance? */
    217 SCIP_Bool sortcliques; /**< should cliques be regarded for the topological sort? */
    218 SCIP_Bool detectcycles; /**< should cycles in the variable bound graph be identified? */
    219};
    220
    221/** inference information */
    222struct InferInfo
    223{
    224 union
    225 {
    226 struct
    227 {
    228 unsigned int pos:31; /**< position of the variable which forced that propagation */
    229 unsigned int boundtype:1; /**< bound type which was the reason (0: lower, 1: upper) */
    230 } asbits;
    231 int asint; /**< inference information as a single int value */
    232 } val;
    233};
    234typedef struct InferInfo INFERINFO;
    235
    236/** converts an integer into an inference information */
    237static
    239 int i /**< integer to convert */
    240 )
    241{
    242 INFERINFO inferinfo;
    243
    244 inferinfo.val.asint = i;
    245
    246 return inferinfo;
    247}
    248
    249/** converts an inference information into an int */
    250static
    252 INFERINFO inferinfo /**< inference information to convert */
    253 )
    254{
    255 return inferinfo.val.asint;
    256}
    257
    258/** returns the propagation rule stored in the inference information */
    259static
    261 INFERINFO inferinfo /**< inference information to convert */
    262 )
    263{
    264 assert((SCIP_BOUNDTYPE)inferinfo.val.asbits.boundtype == SCIP_BOUNDTYPE_LOWER
    265 || (SCIP_BOUNDTYPE)inferinfo.val.asbits.boundtype == SCIP_BOUNDTYPE_UPPER);
    266 return (SCIP_BOUNDTYPE)inferinfo.val.asbits.boundtype;
    267}
    268
    269/** returns the position stored in the inference information */
    270static
    272 INFERINFO inferinfo /**< inference information to convert */
    273 )
    274{
    275 return (int) inferinfo.val.asbits.pos;
    276}
    277
    278/** constructs an inference information out of a position of a variable and a boundtype */
    279static
    281 int pos, /**< position of the variable which forced that propagation */
    282 SCIP_BOUNDTYPE boundtype /**< propagation rule that deduced the value */
    283 )
    284{
    285 INFERINFO inferinfo;
    286
    287 assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
    288 assert(pos >= 0);
    289
    290 inferinfo.val.asbits.pos = (unsigned int) pos; /*lint !e732*/
    291 inferinfo.val.asbits.boundtype = (unsigned int) boundtype; /*lint !e641*/
    292
    293 return inferinfo;
    294}
    295
    296/*
    297 * Local methods
    298 */
    299
    300/* returns the lower bound index of a variable */
    301static
    303 SCIP_PROPDATA* propdata, /**< propagator data */
    304 SCIP_VAR* var /**< variable to get the index for */
    305 )
    306{
    307 int i;
    308
    309 i = SCIPhashmapGetImageInt(propdata->varhashmap, var);
    310
    311 assert(SCIPhashmapExists(propdata->varhashmap, var) == (i != INT_MAX));
    312 assert(i >= 0);
    313
    314 return getLbIndex(i == INT_MAX ? -1 : i);
    315}
    316
    317/* returns the upper bound index of a variable */
    318static
    320 SCIP_PROPDATA* propdata, /**< propagator data */
    321 SCIP_VAR* var /**< variable to get the index for */
    322 )
    323{
    324 int i;
    325
    326 i = SCIPhashmapGetImageInt(propdata->varhashmap, var);
    327
    328 assert(SCIPhashmapExists(propdata->varhashmap, var) == (i != INT_MAX));
    329 assert(i >= 0);
    330
    331 return getUbIndex(i == INT_MAX ? -1 : i);
    332}
    333
    334/** reset propagation data */
    335static
    337 SCIP_PROPDATA* propdata /**< propagator data */
    338 )
    339{
    340 propdata->vars = NULL;
    341 propdata->varhashmap = NULL;
    342 propdata->topoorder = NULL;
    343 propdata->vboundboundedidx = NULL;
    344 propdata->vboundcoefs = NULL;
    345 propdata->vboundconstants = NULL;
    346 propdata->nvbounds = NULL;
    347 propdata->vboundsize = NULL;
    348 propdata->nbounds = 0;
    349 propdata->initialized = FALSE;
    350}
    351
    352/** catches events for variables */
    353static
    355 SCIP* scip, /**< SCIP data structure */
    356 SCIP_PROPDATA* propdata /**< propagator data */
    357 )
    358{
    359 SCIP_EVENTHDLR* eventhdlr;
    360 SCIP_EVENTTYPE eventtype;
    361 SCIP_VAR** vars;
    362 SCIP_VAR* var;
    363 SCIP_Bool lower;
    364 int nbounds;
    365 int v;
    366 int idx;
    367
    368 assert(scip != NULL);
    369 assert(propdata != NULL);
    370 assert(propdata->vars != NULL);
    371 assert(propdata->topoorder != NULL);
    372
    373 /* catch variable events according to computed eventtypes */
    374 eventhdlr = propdata->eventhdlr;
    375 assert(eventhdlr != NULL);
    376
    377 vars = propdata->vars;
    378 nbounds = propdata->nbounds;
    379
    380 /* setup events */
    381 for( v = 0; v < nbounds; ++v )
    382 {
    383 idx = propdata->topoorder[v];
    384 assert(idx >= 0 && idx < nbounds);
    385
    386 var = vars[getVarIndex(idx)];
    387 lower = isIndexLowerbound(idx);
    388
    389 /* if the bound does not influence another bound by implications, cliques, or vbounds,
    390 * we do not create an event and do not catch changes of the bound;
    391 * we mark this by setting the value in topoorder to -1
    392 */
    393 if( propdata->nvbounds[idx] == 0 && SCIPvarGetNImpls(var, lower) == 0 && SCIPvarGetNCliques(var, lower) == 0 )
    394 {
    395 propdata->topoorder[v] = -1;
    396 continue;
    397 }
    398
    399 /* determine eventtype that we want to catch depending on boundtype of variable */
    400 if( lower )
    402 else
    404
    405 SCIP_CALL( SCIPcatchVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*) (uintptr_t) v, NULL) ); /*lint !e571*/
    406 }
    407
    408 return SCIP_OKAY;
    409}
    410
    411/** drops events for variables */
    412static
    414 SCIP* scip, /**< SCIP data structure */
    415 SCIP_PROPDATA* propdata /**< propagator data */
    416 )
    417{
    418 SCIP_EVENTHDLR* eventhdlr;
    419 SCIP_EVENTTYPE eventtype;
    420 SCIP_VAR** vars;
    421 SCIP_VAR* var;
    422 SCIP_Bool lower;
    423 int nbounds;
    424 int v;
    425 int idx;
    426
    427 assert(propdata != NULL);
    428
    429 eventhdlr = propdata->eventhdlr;
    430 assert(eventhdlr != NULL);
    431
    432 vars = propdata->vars;
    433 nbounds = propdata->nbounds;
    434
    435 for( v = 0; v < nbounds; ++v )
    436 {
    437 idx = propdata->topoorder[v];
    438
    439 if( idx == -1 )
    440 continue;
    441
    442 assert(idx >= 0 && idx < nbounds);
    443
    444 var = vars[getVarIndex(idx)];
    445 lower = isIndexLowerbound(idx);
    446
    447 /* determine eventtype that we catch and now want to drop depending on boundtype of variable */
    448 if( lower )
    450 else
    452
    453 SCIP_CALL( SCIPdropVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*) (uintptr_t) v, -1) ); /*lint !e571*/
    454 }
    455
    456 return SCIP_OKAY;
    457}
    458
    459#define INITMEMSIZE 5
    460
    461/* adds a vbound to the propagator data to store it internally and allow forward propagation */
    462static
    464 SCIP* scip, /**< SCIP data structure */
    465 SCIP_PROPDATA* propdata, /**< propagator data */
    466 int startidx, /**< index of bound of variable influencing the other variable */
    467 int endidx, /**< index of bound of variable which is influenced */
    468 SCIP_Real coef, /**< coefficient in the variable bound */
    469 SCIP_Real constant /**< constant in the variable bound */
    470 )
    471{
    472 int nvbounds;
    473
    474 assert(scip != NULL);
    475 assert(propdata != NULL);
    476
    477 if( propdata->vboundsize[startidx] == 0 )
    478 {
    479 /* allocate memory for storing vbounds */
    480 propdata->vboundsize[startidx] = INITMEMSIZE;
    481
    482 SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundboundedidx[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
    483 SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundcoefs[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
    484 SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundconstants[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
    485 }
    486 else if( propdata->nvbounds[startidx] >= propdata->vboundsize[startidx] )
    487 {
    488 /* reallocate memory for storing vbounds */
    489 propdata->vboundsize[startidx] = SCIPcalcMemGrowSize(scip, propdata->nvbounds[startidx] + 1);
    490 assert(propdata->nvbounds[startidx] < propdata->vboundsize[startidx]);
    491
    492 SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundboundedidx[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
    493 SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundcoefs[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
    494 SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundconstants[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
    495 }
    496
    497 nvbounds = propdata->nvbounds[startidx];
    498 propdata->vboundboundedidx[startidx][nvbounds] = endidx;
    499 propdata->vboundcoefs[startidx][nvbounds] = coef;
    500 propdata->vboundconstants[startidx][nvbounds] = constant;
    501 (propdata->nvbounds[startidx])++;
    502
    503 return SCIP_OKAY;
    504}
    505
    506/** comparison method for two indices in the topoorder array, preferring higher indices because the order is reverse
    507 * topological
    508 */
    509static
    510SCIP_DECL_SORTPTRCOMP(compVarboundIndices)
    511{
    512 int idx1 = (int)(size_t)elem1;
    513 int idx2 = (int)(size_t)elem2;
    514
    515 return idx2 - idx1;
    516}
    517
    518/* extract bound changes or infeasibility information from a cycle in the variable bound graph detected during
    519 * depth-first search
    520 */
    521static
    523 SCIP* scip, /**< SCIP data structure */
    524 SCIP_PROPDATA* propdata, /**< propagator data */
    525 int* dfsstack, /**< array of size number of nodes to store the stack;
    526 * only needed for performance reasons */
    527 int* stacknextedge, /**< array storing the next edge to be visited in dfs for all nodes on the
    528 * stack/in the current path; negative numbers represent a clique,
    529 * positive numbers an implication (smaller numbers) or a variable bound */
    530 int stacksize, /**< current stack size */
    531 SCIP_Bool samebound, /**< does the cycle contain the same bound twice or both bounds of the same variable? */
    532 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
    533
    534 )
    535{
    536 SCIP_VAR** vars;
    537 SCIP_VAR* currvar;
    538 SCIP_Bool currlower;
    539
    540 SCIP_Real coef = 1.0;
    541 SCIP_Real constant = 0.0;
    542 SCIP_Bool islower;
    543 SCIP_Real newbound;
    544 int cycleidx;
    545 int startidx;
    546 int ntmpimpls;
    547 int j;
    548 int k;
    549
    550 assert(scip != NULL);
    551 assert(propdata != NULL);
    552
    553 vars = propdata->vars;
    554
    555 /* the last element on the stack is the end-point of the cycle */
    556 cycleidx = dfsstack[stacksize - 1];
    557
    558 /* the same bound of the variable was visited already earlier on the current path, so the start-point of the cycle
    559 * has the same index
    560 */
    561 if( samebound )
    562 startidx = cycleidx;
    563 /* the other bound of the variable was visited earlier on the current path, so the start-point of the cycle
    564 * has the index of the other bound
    565 */
    566 else
    567 startidx = getOtherBoundIndex(cycleidx);
    568
    569 /* search for the start-point of the cycle; since the endpoint is at position stacksize - 1 we start at stacksize - 2
    570 * and go backwards
    571 */
    572 for( j = stacksize - 2; dfsstack[j] != startidx && j >= 0; --j ){};
    573 assert(j >= 0);
    574
    575 for( ; j < stacksize - 1; ++j )
    576 {
    577 currvar = vars[getVarIndex(dfsstack[j])];
    578 currlower = isIndexLowerbound(dfsstack[j]);
    579
    580 /* if we do not use implications, we assume the number of implications to be 0 (as we did before) */
    581 ntmpimpls = (propdata->useimplics ? SCIPvarGetNImpls(currvar, currlower) : 0);
    582
    583 /* stacknextedge[j] <= 0 --> the last outgoing edge traversed during dfs starting from node dfsstack[j] was given
    584 * by a clique
    585 */
    586 if( stacknextedge[j] <= 0 )
    587 {
    588 SCIP_Bool nextlower = isIndexLowerbound(dfsstack[j+1]);
    589#if defined(SCIP_DEBUG) || defined(SCIP_MORE_DEBUG)
    590 SCIP_CLIQUE** tmpcliques = SCIPvarGetCliques(currvar, currlower);
    591 SCIP_VAR** cliquevars;
    592 SCIP_Bool* cliquevals;
    593 int ntmpcliques = SCIPvarGetNCliques(currvar, currlower);
    594 int ncliquevars;
    595 int v;
    596#endif
    597 /* there are four cases:
    598 * a) lb(x) -> ub(y) ==> clique(x,y,...) ==> y <= 1 - x
    599 * b) lb(x) -> lb(y) ==> clique(x,~y,...) ==> y >= x
    600 * c) ub(x) -> ub(y) ==> clique(~x,y,...) ==> y <= x
    601 * d) ub(x) -> lb(y) ==> clique(~x,~y,...) ==> y >= 1 - x
    602 *
    603 * in cases b) and c), coef=1.0 and constant=0.0; these are the cases where both nodes represent
    604 * the same type of bound
    605 * in cases a) and d), coef=-1.0 and constant=1.0; both nodes represent different types of bounds
    606 *
    607 * we do not need to change the overall coef and constant in cases b) and c), but for the others
    608 */
    609 if( currlower != nextlower )
    610 {
    611 coef = -coef;
    612 constant = -constant + 1.0;
    613 }
    614
    615 /* since the coefficient and constant only depend on the type of bounds of the two nodes (see below), we do not
    616 * need to search for the variable in the clique; however, if debug output is enabled, we want to print the
    617 * clique, if more debugging is enabled, we explicitly check that the variable and bound we expect are in the
    618 * clique
    619 */
    620#if defined(SCIP_DEBUG) || defined(SCIP_MORE_DEBUG)
    621 if( stacknextedge[j] == 0 )
    622 {
    623 k = ntmpcliques - 1;
    624 }
    625 else
    626 {
    627 /* we processed at least one edge, so the next one should be -2 or smaller (we have a -1 offset) */
    628 assert(stacknextedge[j] <= -2);
    629
    630 k = -stacknextedge[j] - 2;
    631
    632 assert(k < ntmpcliques);
    633 }
    634
    635 cliquevars = SCIPcliqueGetVars(tmpcliques[k]);
    636 cliquevals = SCIPcliqueGetValues(tmpcliques[k]);
    637 ncliquevars = SCIPcliqueGetNVars(tmpcliques[k]);
    638#ifdef SCIP_DEBUG
    639 SCIPdebugMsg(scip, "clique: ");
    640 for( v = 0; v < ncliquevars; ++v )
    641 {
    642 SCIPdebugMsg(scip, "%s%s ", cliquevals[v] ? "" : "~", SCIPvarGetName(cliquevars[v]));
    643 }
    644 SCIPdebugMsg(scip, "(equation:%d)\n", SCIPcliqueIsEquation(tmpcliques[k]));
    645#endif
    646#ifdef SCIP_MORE_DEBUG
    647 for( v = 0; v < ncliquevars; ++v )
    648 {
    649 if( cliquevars[v] == vars[getVarIndex(dfsstack[j+1])] && cliquevals[v] == !nextlower )
    650 break;
    651 }
    652 assert(v < ncliquevars);
    653#endif
    654
    655 SCIPdebugMsg(scip, "%s(%s) -- (*%g + %g)[clique(<%s%s>,<%s%s>,...)] --> %s(%s)\n",
    656 indexGetBoundString(dfsstack[j]), SCIPvarGetName(currvar),
    657 (currlower != nextlower ? -1.0 : 1.0),
    658 (currlower != nextlower ? 1.0 : 0.0),
    659 (currlower ? "" : "~"), SCIPvarGetName(currvar),
    660 (nextlower ? "~" : ""), SCIPvarGetName(vars[getVarIndex(dfsstack[j+1])]),
    661 indexGetBoundString(dfsstack[j+1]), SCIPvarGetName(currvar));
    662#endif
    663 }
    664 /* stacknextedge[j] > 0 --> the last outgoing edge traversed during dfs starting from node dfsstack[j] was given
    665 * by an implication or vbound. Implications are looked at first, so if stacknextedge[j] <= ntmpimpls, it comes
    666 * from an implication
    667 */
    668 else if( stacknextedge[j] <= ntmpimpls )
    669 {
    670#ifndef NDEBUG
    671 SCIP_VAR** implvars = SCIPvarGetImplVars(currvar, currlower);
    672#endif
    673 SCIP_BOUNDTYPE* impltypes = SCIPvarGetImplTypes(currvar, currlower);
    674 SCIP_Real* implbounds = SCIPvarGetImplBounds(currvar, currlower);
    675 SCIP_VAR* nextvar = vars[getVarIndex(dfsstack[j+1])];
    676 SCIP_Real newconstant;
    677 SCIP_Real newcoef;
    678
    679 k = stacknextedge[j] - 1;
    680
    681 assert(dfsstack[j+1] == (impltypes[k] == SCIP_BOUNDTYPE_LOWER ?
    682 varGetLbIndex(propdata, implvars[k]) : varGetUbIndex(propdata, implvars[k])));
    683
    684 if( impltypes[k] == SCIP_BOUNDTYPE_LOWER )
    685 {
    686 newcoef = implbounds[k] - SCIPvarGetLbLocal(nextvar);
    687
    688 if( currlower )
    689 {
    690 newconstant = SCIPvarGetLbLocal(nextvar);
    691 }
    692 else
    693 {
    694 newconstant = implbounds[k];
    695 newcoef *= -1.0;
    696 }
    697 }
    698 else
    699 {
    700 assert(impltypes[k] == SCIP_BOUNDTYPE_UPPER);
    701
    702 newcoef = SCIPvarGetUbLocal(nextvar) - implbounds[k];
    703
    704 if( currlower )
    705 {
    706 newconstant = SCIPvarGetUbLocal(nextvar);
    707 newcoef *= -1.0;
    708 }
    709 else
    710 {
    711 newconstant = implbounds[k];
    712 }
    713 }
    714
    715 coef = coef * newcoef;
    716 constant = constant * newcoef + newconstant;
    717
    718 SCIPdebugMsg(scip, "%s(%s) -- (*%g + %g) --> %s(%s)\n",
    719 indexGetBoundString(dfsstack[j]), SCIPvarGetName(vars[getVarIndex(dfsstack[j])]),
    720 newcoef, newconstant,
    721 indexGetBoundString(dfsstack[j+1]), SCIPvarGetName(vars[getVarIndex(dfsstack[j+1])]));
    722 }
    723 /* the edge was given by a variable bound relation */
    724 else
    725 {
    726 assert(stacknextedge[j] > ntmpimpls);
    727
    728 k = stacknextedge[j] - ntmpimpls - 1;
    729 assert(k < propdata->nvbounds[dfsstack[j]]);
    730 assert(propdata->vboundboundedidx[dfsstack[j]][k] == dfsstack[j+1]);
    731
    732 SCIPdebugMsg(scip, "%s(%s) -- (*%g + %g) --> %s(%s)\n",
    733 indexGetBoundString(dfsstack[j]), SCIPvarGetName(vars[getVarIndex(dfsstack[j])]),
    734 propdata->vboundcoefs[dfsstack[j]][k], propdata->vboundconstants[dfsstack[j]][k],
    735 indexGetBoundString(dfsstack[j+1]), SCIPvarGetName(vars[getVarIndex(dfsstack[j+1])]));
    736
    737 coef = coef * propdata->vboundcoefs[dfsstack[j]][k];
    738 constant = constant * propdata->vboundcoefs[dfsstack[j]][k] + propdata->vboundconstants[dfsstack[j]][k];
    739 }
    740 }
    741
    742 SCIPdebugMsg(scip, "==> %s(%s) -- (*%g + %g) --> %s(%s)\n",
    743 indexGetBoundString(startidx), SCIPvarGetName(vars[getVarIndex(startidx)]),
    744 coef, constant,
    745 indexGetBoundString(cycleidx), SCIPvarGetName(vars[getVarIndex(cycleidx)]));
    746
    747 islower = isIndexLowerbound(cycleidx);
    748
    749 /* we have a relation x <=/>= coef * x + constant now
    750 * (the relation depends on islower, i.e., whether the last node in the cycle is a lower or upper bound)
    751 * case 1) coef is 1.0 --> x cancels out and we have a statement 0 <=/>= constant.
    752 * if we have a >= relation and constant is positive, we have a contradiction 0 >= constant
    753 * if we have a <= relation and constant is negative, we have a contradiction 0 <= constant
    754 * case 2) coef != 1.0 --> we have a relation x - coef * x <=/>= constant
    755 * <=> (1 - coef) * x <=/>= constant
    756 * if coef < 1.0 this gives us x >= constant / (1 - coef) (if islower=TRUE)
    757 * or x <= constant / (1 - coef) (if islower=FALSE)
    758 * if coef > 1.0, the relation signs need to be switched.
    759 */
    760 if( SCIPisEQ(scip, coef, 1.0) )
    761 {
    762 if( islower && SCIPisFeasPositive(scip, constant) )
    763 {
    764 SCIPdebugMsg(scip, "-> infeasible aggregated variable bound relation 0 >= %g\n", constant);
    765 *infeasible = TRUE;
    766 }
    767 else if( !islower && SCIPisFeasNegative(scip, constant) )
    768 {
    769 SCIPdebugMsg(scip, "-> infeasible aggregated variable bound relation 0 <= %g\n", constant);
    770 *infeasible = TRUE;
    771 }
    772 }
    773 else
    774 {
    775 SCIP_Bool tightened;
    776
    777 newbound = constant / (1.0 - coef);
    778
    779 if( SCIPisGT(scip, coef, 1.0) )
    780 islower = !islower;
    781
    782 if( islower )
    783 {
    784 SCIPdebugMsg(scip, "-> found new lower bound: <%s>[%g,%g] >= %g\n", SCIPvarGetName(vars[getVarIndex(cycleidx)]),
    785 SCIPvarGetLbLocal(vars[getVarIndex(cycleidx)]), SCIPvarGetUbLocal(vars[getVarIndex(cycleidx)]), newbound);
    786 SCIP_CALL( SCIPtightenVarLb(scip, vars[getVarIndex(cycleidx)], newbound, FALSE, infeasible, &tightened) );
    787 }
    788 else
    789 {
    790 SCIPdebugMsg(scip, "-> found new upper bound: <%s>[%g,%g] <= %g\n", SCIPvarGetName(vars[getVarIndex(cycleidx)]),
    791 SCIPvarGetLbLocal(vars[getVarIndex(cycleidx)]), SCIPvarGetUbLocal(vars[getVarIndex(cycleidx)]), newbound);
    792 SCIP_CALL( SCIPtightenVarUb(scip, vars[getVarIndex(cycleidx)], newbound, FALSE, infeasible, &tightened) );
    793 }
    794
    795 if( tightened )
    796 SCIPdebugMsg(scip, "---> applied new bound\n");
    797 }
    798
    799 return SCIP_OKAY;
    800}
    801
    802#define VISITED 1
    803#define ACTIVE 2
    804/** performs depth-first-search in the implicitly given directed graph from the given start index */
    805static
    807 SCIP* scip, /**< SCIP data structure */
    808 SCIP_PROPDATA* propdata, /**< propagator data */
    809 int startnode, /**< node to start the depth-first-search */
    810 int* visited, /**< array to store for each node, whether it was already visited */
    811 int* dfsstack, /**< array of size number of nodes to store the stack;
    812 * only needed for performance reasons */
    813 int* stacknextedge, /**< array of size number of nodes to store the next edge to be visited in
    814 * dfs for all nodes on the stack/in the current path; only needed for
    815 * performance reasons */
    816 int* dfsnodes, /**< array of nodes that can be reached starting at startnode, in reverse
    817 * dfs order */
    818 int* ndfsnodes, /**< pointer to store number of nodes that can be reached starting at
    819 * startnode */
    820 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
    821 )
    822{
    823 SCIP_VAR** vars;
    824 SCIP_VAR* startvar;
    825 SCIP_Bool lower;
    826 int stacksize;
    827 int curridx;
    828 int nimpls;
    829 int idx;
    830 /* for cycle detection, we need to mark currently active nodes, otherwise we just mark them as visited */
    831 int visitedflag = (propdata->detectcycles ? ACTIVE : VISITED);
    832
    833 assert(startnode >= 0);
    834 assert(startnode < propdata->nbounds);
    835 assert(visited != NULL);
    836 assert(visited[startnode] == 0);
    837 assert(dfsstack != NULL);
    838 assert(dfsnodes != NULL);
    839 assert(ndfsnodes != NULL);
    840 assert(infeasible != NULL);
    841
    842 *infeasible = FALSE;
    843
    844 vars = propdata->vars;
    845
    846 /* put start node on the stack */
    847 dfsstack[0] = startnode;
    848 stacknextedge[0] = 0;
    849 stacksize = 1;
    850 idx = -1;
    851
    852 /* we run until no more bounds indices are on the stack, i.e. all changed bounds were propagated */
    853 while( stacksize > 0 )
    854 {
    855 /* get next node from stack */
    856 curridx = dfsstack[stacksize - 1];
    857
    858 /* mark current node as visited */
    859 assert((visited[curridx] != 0) == (stacknextedge[stacksize - 1] != 0));
    860 visited[curridx] = visitedflag;
    861
    862 startvar = vars[getVarIndex(curridx)];
    863 lower = isIndexLowerbound(curridx);
    864
    865 /* if the variable was fixed in the meantime, it is a loose end in the variable bound graph */
    866 if( SCIPisFeasGE(scip, SCIPvarGetLbGlobal(startvar), SCIPvarGetUbGlobal(startvar)) )
    867 goto REMOVE;
    868
    869 nimpls = 0;
    870
    871 if( propdata->sortcliques && propdata->usecliques && stacknextedge[stacksize - 1] == 0 )
    872 stacknextedge[stacksize - 1] = -1;
    873
    874 /* stacknextedge is negative, if the last visited edge from the current node belongs to a clique;
    875 * the index of the clique in the variable's clique list equals abs(stacknextedge) - 1
    876 */
    877 if( propdata->sortcliques && propdata->usecliques && stacknextedge[stacksize - 1] < 0 )
    878 {
    879 SCIP_CLIQUE** cliques;
    880 int ncliques;
    881 int j;
    882 int i;
    883 SCIP_Bool found;
    884
    885 ncliques = SCIPvarGetNCliques(startvar, lower);
    886 cliques = SCIPvarGetCliques(startvar, lower);
    887 found = FALSE;
    888
    889 assert(stacknextedge[stacksize - 1] == -1 || -stacknextedge[stacksize - 1] - 1 <= ncliques);
    890
    891 /* iterate over all not yet handled cliques and search for an unvisited node */
    892 for( j = -stacknextedge[stacksize - 1] - 1; j < ncliques; ++j )
    893 {
    894 SCIP_VAR** cliquevars;
    895 SCIP_Bool* cliquevals;
    896 int ncliquevars;
    897
    898 cliquevars = SCIPcliqueGetVars(cliques[j]);
    899 cliquevals = SCIPcliqueGetValues(cliques[j]);
    900 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
    901
    902 for( i = 0; i < ncliquevars; ++i )
    903 {
    904 if( cliquevars[i] == startvar )
    905 continue;
    906
    907 if( cliquevals[i] )
    908 idx = varGetUbIndex(propdata, cliquevars[i]);
    909 else
    910 idx = varGetLbIndex(propdata, cliquevars[i]);
    911
    912 /* we reached a variable that was already visited on the active path, so we have a cycle in the variable
    913 * bound graph and try to extract valid bound changes from it or detect infeasibility
    914 */
    915 if( idx >= 0 && (visited[idx] == ACTIVE || visited[getOtherBoundIndex(idx)] == ACTIVE)
    916 && !SCIPisFeasGE(scip, SCIPvarGetLbGlobal(cliquevars[i]), SCIPvarGetUbGlobal(cliquevars[i])) )
    917 {
    918 SCIPdebugMsg(scip, "found cycle\n");
    919
    920 dfsstack[stacksize] = idx;
    921 stacknextedge[stacksize - 1] = -j - 2;
    922
    923 SCIP_CALL( extractCycle(scip, propdata, dfsstack, stacknextedge, stacksize + 1,
    924 visited[idx] == ACTIVE, infeasible) );
    925
    926 if( *infeasible )
    927 break;
    928 }
    929
    930 /* break when the first unvisited node is reached */
    931 if( idx >= 0 && !visited[idx] )
    932 {
    933 found = TRUE;
    934 break;
    935 }
    936 }
    937 if( found )
    938 break;
    939 }
    940
    941 /* we stopped because we found an unhandled node and not because we reached the end of the list */
    942 if( found )
    943 {
    944 assert(idx >= 0);
    945 assert(!visited[idx]);
    946 assert(j < ncliques);
    947
    948 SCIPdebugMsg(scip, "clique: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
    950
    951 /* put the adjacent node onto the stack */
    952 dfsstack[stacksize] = idx;
    953 stacknextedge[stacksize] = 0;
    954 stacknextedge[stacksize - 1] = -j - 2;
    955 stacksize++;
    956 assert(stacksize <= propdata->nbounds);
    957
    958 /* restart while loop, get next index from stack */
    959 continue;
    960 }
    961 else
    962 {
    963 /* we did not find an edge to an unhandled node given by a clique */
    964 stacknextedge[stacksize - 1] = 0;
    965 }
    966 }
    967 assert(stacknextedge[stacksize - 1] >= 0);
    968
    969 /* go over edges given by implications */
    970 if( propdata->useimplics )
    971 {
    972 nimpls = SCIPvarGetNImpls(startvar, lower);
    973
    974 if( stacknextedge[stacksize - 1] < nimpls )
    975 {
    976 SCIP_VAR** implvars;
    977 SCIP_BOUNDTYPE* impltypes;
    978 int* implids;
    979 int i;
    980
    981 implvars = SCIPvarGetImplVars(startvar, lower);
    982 impltypes = SCIPvarGetImplTypes(startvar, lower);
    983 implids = SCIPvarGetImplIds(startvar, lower);
    984
    985 for( i = stacknextedge[stacksize - 1]; i < nimpls; ++i )
    986 {
    987 /* it might happen that implications point to inactive variables (normally, those are removed when a
    988 * variable becomes inactive, but in some cases, it cannot be done), we have to ignore these variables
    989 */
    990 if( !SCIPvarIsActive(implvars[i]) )
    991 continue;
    992
    993 /* implication is just a shortcut, so we dont regard it now, because will later go the long way, anyway;
    994 * however, if we do regard cliques for the topological order, we use them to get a better order
    995 */
    996 if( propdata->usecliques && !propdata->sortcliques && implids[i] < 0 )
    997 continue;
    998
    999 idx = (impltypes[i] == SCIP_BOUNDTYPE_LOWER ?
    1000 varGetLbIndex(propdata, implvars[i]) : varGetUbIndex(propdata, implvars[i]));
    1001
    1002 /* we reached a variable that was already visited on the active path, so we have a cycle in the variable
    1003 * bound graph and try to extract valid bound changes from it or detect infeasibility
    1004 */
    1005 if( idx >= 0 && (visited[idx] == ACTIVE || visited[getOtherBoundIndex(idx)] == ACTIVE)
    1006 && !SCIPisFeasGE(scip, SCIPvarGetLbGlobal(implvars[i]), SCIPvarGetUbGlobal(implvars[i])) )
    1007 {
    1008 SCIPdebugMsg(scip, "found cycle\n");
    1009
    1010 dfsstack[stacksize] = idx;
    1011 stacknextedge[stacksize - 1] = i + 1;
    1012
    1013 SCIP_CALL( extractCycle(scip, propdata, dfsstack, stacknextedge, stacksize + 1,
    1014 visited[idx] == ACTIVE, infeasible) );
    1015
    1016 if( *infeasible )
    1017 break;
    1018 }
    1019
    1020 /* break when the first unvisited node is reached */
    1021 if( idx >= 0 && !visited[idx] )
    1022 break;
    1023 }
    1024
    1025 /* we stopped because we found an unhandled node and not because we reached the end of the list */
    1026 if( i < nimpls )
    1027 {
    1028 assert(!visited[idx]);
    1029
    1030 SCIPdebugMsg(scip, "impl: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
    1032
    1033 /* put the adjacent node onto the stack */
    1034 dfsstack[stacksize] = idx;
    1035 stacknextedge[stacksize] = 0;
    1036 stacknextedge[stacksize - 1] = i + 1;
    1037 stacksize++;
    1038 assert(stacksize <= propdata->nbounds);
    1039
    1040 /* restart while loop, get next index from stack */
    1041 continue;
    1042 }
    1043 else
    1044 {
    1045 stacknextedge[stacksize - 1] = nimpls;
    1046 }
    1047 }
    1048 }
    1049 assert(stacknextedge[stacksize - 1] >= nimpls);
    1050
    1051 /* go over edges corresponding to varbounds */
    1052 if( propdata->usevbounds )
    1053 {
    1054 int nvbounds;
    1055 int* vboundidx;
    1056 int i;
    1057
    1058 nvbounds = propdata->nvbounds[curridx];
    1059 vboundidx = propdata->vboundboundedidx[curridx];
    1060
    1061 /* iterate over all vbounds for the given bound */
    1062 for( i = stacknextedge[stacksize - 1] - nimpls; i < nvbounds; ++i )
    1063 {
    1064 idx = vboundidx[i];
    1065 assert(idx >= 0);
    1066
    1067 if( (visited[idx] == ACTIVE || visited[getOtherBoundIndex(idx)] == ACTIVE)
    1069 {
    1070 SCIPdebugMsg(scip, "found cycle\n");
    1071
    1072 dfsstack[stacksize] = idx;
    1073 stacknextedge[stacksize - 1] = nimpls + i + 1;
    1074
    1075 /* we reached a variable that was already visited on the active path, so we have a cycle in the variable
    1076 * bound graph and try to extract valid bound changes from it or detect infeasibility
    1077 */
    1078 SCIP_CALL( extractCycle(scip, propdata, dfsstack, stacknextedge, stacksize + 1,
    1079 visited[idx] == ACTIVE, infeasible) );
    1080
    1081 if( *infeasible )
    1082 break;
    1083 }
    1084
    1085 /* break when the first unvisited node is reached */
    1086 if( !visited[idx] )
    1087 break;
    1088 }
    1089
    1090 if( *infeasible )
    1091 break;
    1092
    1093 /* we stopped because we found an unhandled node and not because we reached the end of the list */
    1094 if( i < nvbounds )
    1095 {
    1096 assert(!visited[idx]);
    1097
    1098 SCIPdebugMsg(scip, "vbound: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
    1100
    1101 /* put the adjacent node onto the stack */
    1102 dfsstack[stacksize] = idx;
    1103 stacknextedge[stacksize] = 0;
    1104 stacknextedge[stacksize - 1] = nimpls + i + 1;
    1105 stacksize++;
    1106 assert(stacksize <= propdata->nbounds);
    1107
    1108 /* restart while loop, get next index from stack */
    1109 continue;
    1110 }
    1111 }
    1112 REMOVE:
    1113 /* the current node was completely handled, remove it from stack */
    1114 stacksize--;
    1115
    1116 SCIPdebugMsg(scip, "topoorder[%d] = %s(%s)\n", *ndfsnodes, getBoundString(lower), SCIPvarGetName(startvar));
    1117
    1118 /* store node in the sorted nodes array */
    1119 dfsnodes[(*ndfsnodes)] = curridx;
    1120 assert(visited[curridx] == visitedflag);
    1121 visited[curridx] = VISITED;
    1122 (*ndfsnodes)++;
    1123 }
    1124
    1125 return SCIP_OKAY;
    1126}
    1127
    1128/** sort the bounds of variables topologically */
    1129static
    1131 SCIP* scip, /**< SCIP data structure */
    1132 SCIP_PROPDATA* propdata, /**< propagator data */
    1133 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
    1134 )
    1135{
    1136 int* dfsstack;
    1137 int* stacknextedge;
    1138 int* visited;
    1139 int nsortednodes;
    1140 int nbounds;
    1141 int i;
    1142
    1143 assert(scip != NULL);
    1144 assert(propdata != NULL);
    1145 assert(infeasible != NULL);
    1146
    1147 nbounds = propdata->nbounds;
    1148
    1149 SCIP_CALL( SCIPallocBufferArray(scip, &dfsstack, nbounds) );
    1150 SCIP_CALL( SCIPallocBufferArray(scip, &stacknextedge, nbounds) );
    1151 SCIP_CALL( SCIPallocClearBufferArray(scip, &visited, nbounds) );
    1152
    1153 nsortednodes = 0;
    1154
    1155 /* while there are unvisited nodes, run dfs starting from one of these nodes; the dfs orders are stored in the
    1156 * topoorder array, later dfs calls are just appended after the stacks of previous dfs calls, which gives us a
    1157 * reverse topological order
    1158 */
    1159 for( i = 0; i < nbounds && !(*infeasible); ++i )
    1160 {
    1161 if( !visited[i] )
    1162 {
    1163 SCIP_CALL( dfs(scip, propdata, i, visited, dfsstack, stacknextedge, propdata->topoorder, &nsortednodes, infeasible) );
    1164 }
    1165 }
    1166 assert((nsortednodes == nbounds) || (*infeasible));
    1167
    1168 SCIPfreeBufferArray(scip, &visited);
    1169 SCIPfreeBufferArray(scip, &stacknextedge);
    1170 SCIPfreeBufferArray(scip, &dfsstack);
    1171
    1172 return SCIP_OKAY;
    1173}
    1174
    1175/** initializes the internal data for the variable bounds propagator */
    1176static
    1178 SCIP* scip, /**< SCIP data structure */
    1179 SCIP_PROP* prop, /**< vbounds propagator */
    1180 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
    1181 )
    1182{
    1183 SCIP_PROPDATA* propdata;
    1184 SCIP_VAR** vars;
    1185 int nvars;
    1186 int nbounds;
    1187 int startidx;
    1188 int v;
    1189 int n;
    1190
    1191 assert(scip != NULL);
    1192 assert(prop != NULL);
    1193 assert(infeasible != NULL);
    1194
    1195 /* get propagator data */
    1196 propdata = SCIPpropGetData(prop);
    1197 assert(propdata != NULL);
    1198 assert(!propdata->initialized);
    1199
    1200 SCIPdebugMsg(scip, "initialize vbounds propagator for problem <%s>\n", SCIPgetProbName(scip));
    1201
    1202 vars = SCIPgetVars(scip);
    1203 nvars = SCIPgetNVars(scip);
    1204 nbounds = 2 * nvars;
    1205
    1206 *infeasible = FALSE;
    1207
    1208 /* store size of the bounds of variables array */
    1209 propdata->nbounds = nbounds;
    1210
    1211 if( nbounds == 0 )
    1212 return SCIP_OKAY;
    1213
    1214 propdata->initialized = TRUE;
    1215
    1216 /* prepare priority queue structure */
    1217 SCIP_CALL( SCIPpqueueCreate(&propdata->propqueue, nvars, 2.0, compVarboundIndices, NULL) );
    1218 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->inqueue, nbounds) );
    1219 BMSclearMemoryArray(propdata->inqueue, nbounds);
    1220
    1221 /* we need to copy the variable since this array is the basis of the propagator and the corresponding variable array
    1222 * within SCIP might change during the search
    1223 */
    1224 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &propdata->vars, vars, nvars) );
    1225 SCIP_CALL( SCIPhashmapCreate(&propdata->varhashmap, SCIPblkmem(scip), nvars) );
    1226
    1227 for( v = 0; v < nvars; ++v )
    1228 {
    1229 SCIP_CALL( SCIPhashmapInsertInt(propdata->varhashmap, propdata->vars[v], v) );
    1230 }
    1231
    1232 /* allocate memory for the arrays of the propdata */
    1233 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->topoorder, nbounds) );
    1234 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundboundedidx, nbounds) );
    1235 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundcoefs, nbounds) );
    1236 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundconstants, nbounds) );
    1237 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->nvbounds, nbounds) );
    1238 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundsize, nbounds) );
    1239 BMSclearMemoryArray(propdata->vboundboundedidx, nbounds);
    1240 BMSclearMemoryArray(propdata->vboundcoefs, nbounds);
    1241 BMSclearMemoryArray(propdata->vboundconstants, nbounds);
    1242 BMSclearMemoryArray(propdata->nvbounds, nbounds);
    1243 BMSclearMemoryArray(propdata->vboundsize, nbounds);
    1244
    1245 for( v = 0; v < nbounds; ++v )
    1246 {
    1247 propdata->topoorder[v] = v;
    1248 propdata->vboundboundedidx[v] = NULL;
    1249 propdata->vboundcoefs[v] = NULL;
    1250 propdata->vboundconstants[v] = NULL;
    1251 propdata->nvbounds[v] = 0;
    1252 propdata->vboundsize[v] = 0;
    1253 }
    1254
    1255 /* collect information about varbounds */
    1256 for( v = 0; v < nbounds; ++v )
    1257 {
    1258 SCIP_VAR** vbvars;
    1259 SCIP_VAR* var;
    1260 SCIP_Real* coefs;
    1261 SCIP_Real* constants;
    1262 SCIP_Bool lower;
    1263 int nvbvars;
    1264
    1265 var = vars[getVarIndex(v)];
    1266 lower = isIndexLowerbound(v);
    1267
    1268 /* get the variable bound informations for the current variable */
    1269 if( lower )
    1270 {
    1271 vbvars = SCIPvarGetVlbVars(var);
    1272 coefs = SCIPvarGetVlbCoefs(var);
    1273 constants = SCIPvarGetVlbConstants(var);
    1274 nvbvars = SCIPvarGetNVlbs(var);
    1275 }
    1276 else
    1277 {
    1278 vbvars = SCIPvarGetVubVars(var);
    1279 coefs = SCIPvarGetVubCoefs(var);
    1280 constants = SCIPvarGetVubConstants(var);
    1281 nvbvars = SCIPvarGetNVubs(var);
    1282 }
    1283
    1284 /* loop over all variable bounds; a variable lower bound has the form: x >= b*y + d,
    1285 * a variable upper bound the form x <= b*y + d */
    1286 for( n = 0; n < nvbvars; ++n )
    1287 {
    1288 SCIP_VAR* vbvar;
    1289 SCIP_Real coef;
    1290 SCIP_Real constant;
    1291
    1292 vbvar = vbvars[n];
    1293 coef = coefs[n];
    1294 constant = constants[n];
    1295 assert(vbvar != NULL);
    1296
    1297 /* transform variable bound variable to an active variable, if possible */
    1298 SCIP_CALL( SCIPgetProbvarSum(scip, &vbvar, &coef, &constant) );
    1299 assert(vbvar != NULL);
    1300
    1301 if( !SCIPvarIsActive(vbvar) )
    1302 continue;
    1303
    1304 /* if the coefficient is positive, the type of bound is the same for the bounded and the bounding variable */
    1305 if( SCIPisPositive(scip, coef) )
    1306 startidx = (lower ? varGetLbIndex(propdata, vbvar) : varGetUbIndex(propdata, vbvar));
    1307 else
    1308 startidx = (lower ? varGetUbIndex(propdata, vbvar) : varGetLbIndex(propdata, vbvar));
    1309 assert(startidx >= 0);
    1310
    1311 /* If the vbvar is binary, the vbound should be stored as an implication already.
    1312 * However, it might happen that vbvar was integer when the variable bound was added, but was converted
    1313 * to a binary variable later during presolving when its upper bound was changed to 1. In this case,
    1314 * the implication might not have been created.
    1315 */
    1317 && SCIPvarHasImplic(vbvar, isIndexLowerbound(startidx), var, getBoundtype(v)) )
    1318 {
    1319 SCIPdebugMsg(scip, "varbound <%s> %s %g * <%s> + %g not added to propagator data due to reverse implication\n",
    1320 SCIPvarGetName(var), (lower ? ">=" : "<="), coef,
    1321 SCIPvarGetName(vbvar), constant);
    1322 }
    1323 else
    1324 {
    1325 SCIP_CALL( addVbound(scip, propdata, startidx, v, coef, constant) );
    1326
    1327 SCIPdebugMsg(scip, "varbound <%s> %s %g * <%s> + %g added to propagator data\n",
    1328 SCIPvarGetName(var), (lower ? ">=" : "<="), coef,
    1329 SCIPvarGetName(vbvar), constant);
    1330 }
    1331 }
    1332 }
    1333
    1334 /* sort the bounds topologically */
    1335 if( propdata->dotoposort )
    1336 {
    1337 SCIP_CALL( topologicalSort(scip, propdata, infeasible) );
    1338 }
    1339
    1340 /* catch variable events */
    1341 SCIP_CALL( catchEvents(scip, propdata) );
    1342
    1343 return SCIP_OKAY;
    1344}
    1345
    1346/** resolves a propagation by adding the variable which implied that bound change */
    1347static
    1349 SCIP* scip, /**< SCIP data structure */
    1350 SCIP_PROPDATA* propdata, /**< propagator data */
    1351 SCIP_VAR* var, /**< variable to be reported */
    1352 SCIP_BOUNDTYPE boundtype, /**< bound to be reported */
    1353 SCIP_BDCHGIDX* bdchgidx /**< the index of the bound change, representing the point of time where
    1354 * the change took place, or NULL for the current local bounds */
    1355 )
    1356{
    1357 assert(propdata != NULL);
    1358 assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
    1359
    1360 SCIPdebugMsg(scip, " -> add %s bound of variable <%s> as reason\n",
    1361 getBoundtypeString(boundtype), SCIPvarGetName(var));
    1362
    1363 switch( boundtype )
    1364 {
    1366 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
    1367 break;
    1369 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
    1370 break;
    1371 default:
    1372 SCIPerrorMessage("invalid bound type <%d>\n", boundtype);
    1373 SCIPABORT();
    1374 return SCIP_INVALIDDATA; /*lint !e527*/
    1375 }
    1376
    1377 return SCIP_OKAY;
    1378}
    1379
    1380/** relaxes bound of give variable as long as the given inference bound still leads to a cutoff and add that bound
    1381 * change to the conflict set
    1382 */
    1383static
    1385 SCIP* scip, /**< SCIP data structure */
    1386 SCIP_VAR* var, /**< variable for which the upper bound should be relaxed */
    1387 SCIP_BOUNDTYPE boundtype, /**< boundtype used for the variable bound variable */
    1388 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where
    1389 * the change took place, or NULL for the current local bounds */
    1390 SCIP_Real relaxedbd /**< relaxed bound */
    1391 )
    1392{
    1393 if( boundtype == SCIP_BOUNDTYPE_LOWER )
    1394 {
    1395 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, relaxedbd) );
    1396 }
    1397 else
    1398 {
    1399 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
    1400 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, relaxedbd) );
    1401 }
    1402
    1403 return SCIP_OKAY;
    1404}
    1405
    1406/** compute the relaxed bound which is sufficient to propagate the inference lower bound of given variable */
    1407static
    1409 SCIP* scip, /**< SCIP data structure */
    1410 SCIP_VAR* var, /**< variable which was propagated */
    1411 SCIP_Real inferlb, /**< inference lower bound */
    1412 SCIP_Real coef, /**< inference variable bound coefficient used */
    1413 SCIP_Real constant /**< inference variable bound constant used */
    1414 )
    1415{
    1416 SCIP_Real relaxedbd;
    1417
    1418 if( SCIPvarIsIntegral(var) && inferlb < SCIPgetHugeValue(scip) * SCIPfeastol(scip) )
    1419 relaxedbd = (inferlb - 1.0 + 2*SCIPfeastol(scip) - constant) / coef;
    1420 else
    1421 relaxedbd = (inferlb - constant) / coef;
    1422
    1423 /* check the computed relaxed lower/upper bound is a proper reason for the inference bound which has to be explained */
    1424 assert(SCIPisEQ(scip, inferlb, SCIPadjustedVarLb(scip, var, relaxedbd * coef + constant)));
    1425
    1426 if( coef > 0.0 )
    1427 relaxedbd += SCIPfeastol(scip);
    1428 else
    1429 relaxedbd -= SCIPfeastol(scip);
    1430
    1431 return relaxedbd;
    1432}
    1433
    1434/** analyzes an infeasibility which was reached by updating the lower bound of the inference variable above its upper
    1435 * bound
    1436 */
    1437static
    1439 SCIP* scip, /**< SCIP data structure */
    1440 SCIP_PROPDATA* propdata, /**< propagator data */
    1441 SCIP_VAR* infervar, /**< variable which led to a cutoff */
    1442 SCIP_Real inferlb, /**< lower bound which led to infeasibility */
    1443 SCIP_VAR* vbdvar, /**< variable which is the reason for the lower bound change */
    1444 SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the lower bound change */
    1445 SCIP_Real coef, /**< inference variable bound coefficient used */
    1446 SCIP_Real constant, /**< inference variable bound constant used */
    1447 SCIP_Bool canwide /**< can bound widening be used (for vbounds) or not
    1448 * (for implications or cliques) */
    1449 )
    1450{
    1451 assert(scip != NULL);
    1452 assert(propdata != NULL);
    1453 assert(infervar != NULL);
    1454 assert(SCIPisEQ(scip, SCIPvarGetUbLocal(infervar), SCIPgetVarUbAtIndex(scip, infervar, NULL, FALSE)));
    1455 assert(SCIPisEQ(scip, SCIPgetVarUbAtIndex(scip, infervar, NULL, TRUE), SCIPgetVarUbAtIndex(scip, infervar, NULL, FALSE)));
    1456 assert(SCIPisGT(scip, inferlb, SCIPvarGetUbLocal(infervar)));
    1458
    1459 /* check if conflict analysis is applicable */
    1461 return SCIP_OKAY;
    1462
    1463 if( canwide && propdata->usebdwidening )
    1464 {
    1465 SCIP_Real relaxedbd;
    1466 SCIP_Real relaxedub;
    1467
    1468 SCIPdebugMsg(scip, "try to create conflict using bound widening order: inference variable, variable bound variable\n");
    1469
    1470 /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
    1472
    1473 /* adjust lower bound */
    1474 inferlb = SCIPadjustedVarLb(scip, infervar, inferlb);
    1475
    1476 /* compute a relaxed upper bound which would be sufficient to be still infeasible */
    1477 if( SCIPvarIsIntegral(infervar) )
    1478 relaxedub = inferlb - 1.0;
    1479 else
    1480 relaxedub = inferlb - 2*SCIPfeastol(scip);
    1481
    1482 /* try to relax inference variable upper bound such that the infeasibility is still given */
    1483 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, relaxedub) );
    1484
    1485 /* collect the upper bound which is reported to the conflict analysis */
    1486 relaxedub = SCIPgetConflictVarUb(scip, infervar);
    1487
    1488 /* adjust inference bound with respect to the upper bound reported to the conflict analysis */
    1489 if( SCIPvarIsIntegral(infervar) )
    1490 relaxedub = relaxedub + 1.0;
    1491 else
    1492 relaxedub = relaxedub + 2*SCIPfeastol(scip);
    1493
    1494 /* compute the relaxed bound which is sufficient to propagate the inference lower bound of given variable */
    1495 relaxedbd = computeRelaxedLowerbound(scip, infervar, relaxedub, coef, constant);
    1496
    1497 /* try to relax variable bound variable */
    1498 SCIP_CALL( relaxVbdvar(scip, vbdvar, boundtype, NULL, relaxedbd) );
    1499
    1500 /* analyze the conflict */
    1502 }
    1503 else
    1504 {
    1505 /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
    1507
    1508 /* add upper bound of the variable for which we tried to change the lower bound */
    1509 SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
    1510
    1511 /* add (correct) bound of the variable which let to the new lower bound */
    1512 SCIP_CALL( resolvePropagation(scip, propdata, vbdvar, boundtype, NULL) );
    1513
    1514 /* analyze the conflict */
    1516 }
    1517
    1518 return SCIP_OKAY;
    1519}
    1520
    1521/** compute the relaxed bound which is sufficient to propagate the inference upper bound of given variable */
    1522static
    1524 SCIP* scip, /**< SCIP data structure */
    1525 SCIP_VAR* var, /**< variable which was propagated */
    1526 SCIP_Real inferub, /**< inference upper bound */
    1527 SCIP_Real coef, /**< inference variable bound coefficient used */
    1528 SCIP_Real constant /**< inference variable bound constant used */
    1529 )
    1530{
    1531 SCIP_Real relaxedbd;
    1532
    1533 if( SCIPvarIsIntegral(var) && inferub < SCIPgetHugeValue(scip) * SCIPfeastol(scip) )
    1534 relaxedbd = (inferub + 1.0 - 2*SCIPfeastol(scip) - constant) / coef;
    1535 else
    1536 relaxedbd = (inferub - constant) / coef;
    1537
    1538 /* check the computed relaxed lower/upper bound is a proper reason for the inference bound which has to be explained */
    1539 assert(SCIPisEQ(scip, inferub, SCIPadjustedVarUb(scip, var, relaxedbd * coef + constant)));
    1540
    1541 if( coef > 0.0 )
    1542 relaxedbd -= SCIPfeastol(scip);
    1543 else
    1544 relaxedbd += SCIPfeastol(scip);
    1545
    1546 return relaxedbd;
    1547}
    1548
    1549/** analyzes an infeasibility which was reached by updating the upper bound of the inference variable below its lower
    1550 * bound
    1551 */
    1552static
    1554 SCIP* scip, /**< SCIP data structure */
    1555 SCIP_PROPDATA* propdata, /**< propagator data */
    1556 SCIP_VAR* infervar, /**< variable which led to a cutoff */
    1557 SCIP_Real inferub, /**< upper bound which led to infeasibility */
    1558 SCIP_VAR* vbdvar, /**< variable which is the reason for the upper bound change */
    1559 SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the upper bound change */
    1560 SCIP_Real coef, /**< inference variable bound coefficient used */
    1561 SCIP_Real constant, /**< inference variable bound constant used */
    1562 SCIP_Bool canwide /**< can bound widening be used (for vbounds) or not (for inplications or cliques) */
    1563 )
    1564{
    1565 assert(scip != NULL);
    1566 assert(propdata != NULL);
    1567 assert(infervar != NULL);
    1568 assert(SCIPisEQ(scip, SCIPvarGetLbLocal(infervar), SCIPgetVarLbAtIndex(scip, infervar, NULL, FALSE)));
    1569 assert(SCIPisEQ(scip, SCIPgetVarLbAtIndex(scip, infervar, NULL, TRUE), SCIPgetVarLbAtIndex(scip, infervar, NULL, FALSE)));
    1570 assert(SCIPisLT(scip, inferub, SCIPvarGetLbLocal(infervar)));
    1572
    1573 /* check if conflict analysis is applicable */
    1575 return SCIP_OKAY;
    1576
    1577 if( canwide && propdata->usebdwidening )
    1578 {
    1579 SCIP_Real relaxedbd;
    1580 SCIP_Real relaxedlb;
    1581
    1582 SCIPdebugMsg(scip, "try to create conflict using bound widening order: inference variable, variable bound variable\n");
    1583
    1584 /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
    1586
    1587 /* adjust upper bound */
    1588 inferub = SCIPadjustedVarUb(scip, infervar, inferub);
    1589
    1590 /* compute a relaxed lower bound which would be sufficient to be still infeasible */
    1591 if( SCIPvarIsIntegral(infervar) )
    1592 relaxedlb = inferub + 1.0;
    1593 else
    1594 relaxedlb = inferub + 2*SCIPfeastol(scip);
    1595
    1596 /* try to relax inference variable lower bound such that the infeasibility is still given */
    1597 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, relaxedlb) );
    1598
    1599 /* collect the lower bound which is reported to the conflict analysis */
    1600 relaxedlb = SCIPgetConflictVarLb(scip, infervar);
    1601
    1602 /* adjust inference bound with respect to the upper bound reported to the conflict analysis */
    1603 if( SCIPvarIsIntegral(infervar) )
    1604 relaxedlb = relaxedlb - 1.0;
    1605 else
    1606 relaxedlb = relaxedlb - 2*SCIPfeastol(scip);
    1607
    1608 /* compute the relaxed bound which is sufficient to propagate the inference upper bound of given variable */
    1609 relaxedbd = computeRelaxedUpperbound(scip, infervar, relaxedlb, coef, constant);
    1610
    1611 /* try to relax variable bound variable */
    1612 SCIP_CALL( relaxVbdvar(scip, vbdvar, boundtype, NULL, relaxedbd) );
    1613
    1614 /* analyze the conflict */
    1616 }
    1617 else
    1618 {
    1619 /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
    1621
    1622 /* add lower bound of the variable for which we tried to change the upper bound */
    1623 SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
    1624
    1625 /* add (correct) bound of the variable which let to the new upper bound */
    1626 SCIP_CALL( resolvePropagation(scip, propdata, vbdvar, boundtype, NULL) );
    1627
    1628 /* analyze the conflict */
    1630 }
    1631
    1632 return SCIP_OKAY;
    1633}
    1634
    1635/* tries to tighten the (global) lower bound of the given variable to the given new bound */
    1636static
    1638 SCIP* scip, /**< SCIP data structure */
    1639 SCIP_PROP* prop, /**< vbounds propagator */
    1640 SCIP_PROPDATA* propdata, /**< propagator data */
    1641 SCIP_VAR* var, /**< variable whose lower bound should be tightened */
    1642 SCIP_Real newlb, /**< new lower bound for the variable */
    1643 SCIP_Bool global, /**< is the bound globally valid? */
    1644 SCIP_VAR* vbdvar, /**< variable which is the reason for the lower bound change */
    1645 SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the lower bound change */
    1646 SCIP_Bool force, /**< should domain changes for continuous variables be forced */
    1647 SCIP_Real coef, /**< coefficient in vbound constraint causing the propagation;
    1648 * or 0.0 if propagation is caused by clique or implication */
    1649 SCIP_Real constant, /**< constant in vbound constraint causing the propagation;
    1650 * or 0.0 if propagation is caused by clique or implication */
    1651 SCIP_Bool canwide, /**< can bound widening be used (for vbounds) or not (for inplications or cliques) */
    1652 int* nchgbds, /**< pointer to increase, if a bound was changed */
    1653 SCIP_RESULT* result /**< pointer to store the result of the propagation */
    1654 )
    1655{
    1656 INFERINFO inferinfo;
    1657 SCIP_Real lb;
    1658 SCIP_Bool tightened;
    1659 SCIP_Bool infeasible;
    1660
    1661 assert(scip != NULL);
    1662 assert(prop != NULL);
    1663 assert(propdata != NULL);
    1664 assert(var != NULL);
    1665 assert(nchgbds != NULL);
    1666 assert(result != NULL);
    1667
    1668 lb = SCIPvarGetLbLocal(var);
    1669
    1670 /* check that the new upper bound is better */
    1671 if( (SCIPvarIsIntegral(var) && newlb - lb > 0.5) || (force && SCIPisGT(scip, newlb, lb)) )
    1672 force = TRUE;
    1673 else
    1674 force = FALSE;
    1675
    1676 /* try to tighten the lower bound */
    1677 if( global )
    1678 {
    1679 SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, newlb, force, &infeasible, &tightened) );
    1680 }
    1681 else
    1682 {
    1683 inferinfo = getInferInfo(boundtype == SCIP_BOUNDTYPE_LOWER ? varGetLbIndex(propdata, vbdvar) : varGetUbIndex(propdata, vbdvar), boundtype);
    1684
    1685 SCIP_CALL( SCIPinferVarLbProp(scip, var, newlb, prop, inferInfoToInt(inferinfo), force, &infeasible, &tightened) );
    1686 }
    1687
    1688 if( infeasible )
    1689 {
    1690 /* the infeasible results comes from the fact that the new lower bound lies above the current upper bound */
    1691 assert(SCIPisGT(scip, newlb, SCIPvarGetUbLocal(var)));
    1692 assert(!global || SCIPisGT(scip, newlb, SCIPvarGetUbGlobal(var)));
    1693
    1694 SCIPdebugMsg(scip, "tightening%s lower bound of variable <%s> to %g due the %s bound of variable <%s> led to infeasibility\n",
    1695 (global ? " global" : ""), SCIPvarGetName(var), newlb, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
    1696
    1697 if( global )
    1698 {
    1699 /* cutoff the root node */
    1701 }
    1702 else
    1703 {
    1704 /* analyzes a infeasibility via conflict analysis */
    1705 SCIP_CALL( analyzeConflictLowerbound(scip, propdata, var, newlb, vbdvar, boundtype, coef, constant, canwide) );
    1706 }
    1707 *result = SCIP_CUTOFF;
    1708 }
    1709 else if( tightened )
    1710 {
    1711 SCIPdebugMsg(scip, "tightened%s lower bound of variable <%s> to %g due the %s bound of variable <%s>\n",
    1712 (global ? " global" : ""), SCIPvarGetName(var), newlb, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
    1713 (*nchgbds)++;
    1714 }
    1715
    1716 return SCIP_OKAY;
    1717}
    1718
    1719/* tries to tighten the (global) upper bound of the given variable to the given new bound */
    1720static
    1722 SCIP* scip, /**< SCIP data structure */
    1723 SCIP_PROP* prop, /**< vbounds propagator */
    1724 SCIP_PROPDATA* propdata, /**< propagator data */
    1725 SCIP_VAR* var, /**< variable whose upper bound should be tightened */
    1726 SCIP_Real newub, /**< new upper bound of the variable */
    1727 SCIP_Bool global, /**< is the bound globally valid? */
    1728 SCIP_VAR* vbdvar, /**< variable which is the reason for the upper bound change */
    1729 SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the upper bound change */
    1730 SCIP_Bool force, /**< should domain changes for continuous variables be forced */
    1731 SCIP_Real coef, /**< coefficient in vbound constraint causing the propagation;
    1732 * or 0.0 if propagation is caused by clique or implication */
    1733 SCIP_Real constant, /**< constant in vbound constraint causing the propagation;
    1734 * or 0.0 if propagation is caused by clique or implication */
    1735 SCIP_Bool canwide, /**< can bound widening be used (for vbounds) or not (for inplications or cliques) */
    1736 int* nchgbds, /**< pointer to increase, if a bound was changed */
    1737 SCIP_RESULT* result /**< pointer to store the result of the propagation */
    1738 )
    1739{
    1740 INFERINFO inferinfo;
    1741 SCIP_Real ub;
    1742 SCIP_Bool tightened;
    1743 SCIP_Bool infeasible;
    1744
    1745 assert(scip != NULL);
    1746 assert(prop != NULL);
    1747 assert(propdata != NULL);
    1748 assert(var != NULL);
    1749 assert(nchgbds != NULL);
    1750 assert(result != NULL);
    1751
    1752 ub = SCIPvarGetUbLocal(var);
    1753
    1754 /* check that the new upper bound is better */
    1755 if( (SCIPvarIsIntegral(var) && ub - newub > 0.5) || (force && SCIPisLT(scip, newub, ub)) )
    1756 force = TRUE;
    1757 else
    1758 force = FALSE;
    1759
    1760 /* try to tighten the upper bound */
    1761 if( global )
    1762 {
    1763 SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, newub, force, &infeasible, &tightened) );
    1764 }
    1765 else
    1766 {
    1767 inferinfo = getInferInfo(boundtype == SCIP_BOUNDTYPE_LOWER ? varGetLbIndex(propdata, vbdvar) : varGetUbIndex(propdata, vbdvar), boundtype);
    1768
    1769 SCIP_CALL( SCIPinferVarUbProp(scip, var, newub, prop, inferInfoToInt(inferinfo), force, &infeasible, &tightened) );
    1770 }
    1771
    1772 if( infeasible )
    1773 {
    1774 /* the infeasible results comes from the fact that the new upper bound lies below the current lower bound */
    1775 assert(SCIPisLT(scip, newub, SCIPvarGetLbLocal(var)));
    1776 assert(!global || SCIPisLT(scip, newub, SCIPvarGetLbGlobal(var)));
    1777
    1778 SCIPdebugMsg(scip, "tightening%s upper bound of variable <%s> to %g due the %s bound of variable <%s> led to infeasibility\n",
    1779 (global ? " global" : ""), SCIPvarGetName(var), newub, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
    1780
    1781 if( global )
    1782 {
    1783 /* cutoff the root node */
    1785 }
    1786 else
    1787 {
    1788 /* analyzes a infeasibility via conflict analysis */
    1789 SCIP_CALL( analyzeConflictUpperbound(scip, propdata, var, newub, vbdvar, boundtype, coef, constant, canwide) );
    1790 }
    1791 *result = SCIP_CUTOFF;
    1792 }
    1793 else if( tightened )
    1794 {
    1795 SCIPdebugMsg(scip, "tightened%s upper bound of variable <%s> to %g due the %s bound of variable <%s>\n",
    1796 (global ? " global" : ""), SCIPvarGetName(var), newub, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
    1797 (*nchgbds)++;
    1798 }
    1799
    1800 return SCIP_OKAY;
    1801}
    1802
    1803/** performs propagation of variables lower and upper bounds, implications, and cliques */
    1804static
    1806 SCIP* scip, /**< SCIP data structure */
    1807 SCIP_PROP* prop, /**< vbounds propagator */
    1808 SCIP_Bool force, /**< should domain changes for continuous variables be forced */
    1809 SCIP_RESULT* result /**< pointer to store the result of the propagation */
    1810 )
    1811{
    1812 SCIP_PROPDATA* propdata;
    1813 SCIP_VAR** vars;
    1814 SCIP_VAR* startvar;
    1815 SCIP_BOUNDTYPE starttype;
    1816 SCIP_Real startbound;
    1817 SCIP_Real globalbound;
    1818 int* queuelist = NULL;
    1819 int nqueuelist = 0;
    1820 int startpos;
    1821 int topopos;
    1822 int v;
    1823 int n;
    1824 int nchgbds;
    1825 int nbounds;
    1826 SCIP_Bool lower;
    1827 SCIP_Bool global;
    1828
    1829 assert(scip != NULL);
    1830 assert(prop != NULL);
    1831 assert(result != NULL);
    1832
    1833 (*result) = SCIP_DIDNOTRUN;
    1834
    1835 /* we do not run the propagator in presolving, because we want to avoid doing the expensive creation of the graph twice */
    1837 return SCIP_OKAY;
    1838
    1839 propdata = SCIPpropGetData(prop);
    1840 assert(propdata != NULL);
    1841
    1842 /* initialize propagator data needed for propagation, if not done yet */
    1843 if( !propdata->initialized )
    1844 {
    1845 SCIP_Bool infeasible;
    1846
    1847 SCIP_CALL( initData(scip, prop, &infeasible) );
    1848
    1849 if( infeasible )
    1850 {
    1851 *result = SCIP_CUTOFF;
    1852 return SCIP_OKAY;
    1853 }
    1854 }
    1855 assert(propdata->nbounds == 0 || propdata->propqueue != NULL);
    1856
    1857 vars = propdata->vars;
    1858 nbounds = propdata->nbounds;
    1859
    1860 if( nbounds == 0 )
    1861 return SCIP_OKAY;
    1862
    1863 /* propagate all variables if we are in repropagation */
    1865 {
    1866 SCIP_VAR* var;
    1867 int idx;
    1868
    1869 for( v = nbounds - 1; v >= 0; --v )
    1870 {
    1871 idx = propdata->topoorder[v];
    1872 if( idx != -1 && !propdata->inqueue[v] )
    1873 {
    1874 var = vars[getVarIndex(idx)];
    1875 lower = isIndexLowerbound(idx);
    1876 if( !SCIPvarIsBinary(var) || (lower && SCIPvarGetLbLocal(var) > 0.5)
    1877 || (!lower && SCIPvarGetUbLocal(var) < 0.5) )
    1878 {
    1879 SCIP_CALL( SCIPpqueueInsert(propdata->propqueue, (void*)(size_t)(v + 1)) ); /*lint !e571 !e776*/
    1880 propdata->inqueue[v] = TRUE;
    1881 }
    1882 }
    1883 }
    1884 }
    1885
    1886 /* return if no bound changes are in the priority queue (no changed bounds to handle since last propagation) */
    1887 if( SCIPpqueueNElems(propdata->propqueue) == 0 )
    1888 return SCIP_OKAY;
    1889
    1890 nchgbds = 0;
    1891
    1892 (*result) = SCIP_DIDNOTFIND;
    1893
    1894 /* allocate space for variables added to the queue - needed to clean up data */
    1895 SCIP_CALL( SCIPallocBufferArray(scip, &queuelist, nbounds) );
    1896
    1897 SCIPdebugMsg(scip, "varbound propagator: %d elements in the propagation queue\n", SCIPpqueueNElems(propdata->propqueue));
    1898
    1899 /* get variable bound of highest priority from priority queue and try to deduce bound changes for other variables;
    1900 * the priority queue is ordered w.r.t the topological sort of the varbound graph
    1901 */
    1902 while( SCIPpqueueNElems(propdata->propqueue) > 0 )
    1903 {
    1904 /* coverity[pointer_conversion_loses_bits] */
    1905 topopos = ((int)(size_t)SCIPpqueueRemove(propdata->propqueue)) - 1;
    1906 assert(propdata->inqueue[topopos]);
    1907 startpos = propdata->topoorder[topopos];
    1908 assert(startpos >= 0);
    1909 queuelist[nqueuelist++] = topopos;
    1910 assert( nqueuelist <= nbounds );
    1911
    1912 /* do not directly set propdata->inqueue[topopos] = FALSE: we allow only one propagation sweep through the
    1913 * topologically ordered bounds; otherwise an infinite loop could occur */
    1914
    1915 startvar = vars[getVarIndex(startpos)];
    1916 starttype = getBoundtype(startpos);
    1917 lower = (starttype == SCIP_BOUNDTYPE_LOWER);
    1918 startbound = ( lower ? SCIPvarGetLbLocal(startvar) : SCIPvarGetUbLocal(startvar) );
    1919 globalbound = ( lower ? SCIPvarGetLbGlobal(startvar) : SCIPvarGetUbGlobal(startvar));
    1920 global = SCIPisEQ(scip, startbound, globalbound);
    1921
    1922 SCIPdebugMsg(scip, "propagate new %s bound of %g of variable <%s>:\n",
    1923 getBoundtypeString(starttype), startbound, SCIPvarGetName(startvar));
    1924
    1925 /* there should be neither implications nor cliques for non-binary variables */
    1926 assert(SCIPvarIsBinary(startvar) || SCIPvarGetNImpls(startvar, lower) == 0);
    1927 assert(SCIPvarIsBinary(startvar) || SCIPvarGetNCliques(startvar, lower) == 0);
    1928
    1929 if( SCIPvarIsBinary(startvar) )
    1930 {
    1931 /* we only propagate binary variables if the lower bound changed to 1.0 or the upper bound changed to 0.0 */
    1932 if( lower != (startbound > 0.5) )
    1933 continue;
    1934
    1935 /* propagate implications */
    1936 if( propdata->useimplics )
    1937 {
    1938 int nimplvars;
    1939
    1940 /* if the lower bound of the startvar was changed, it was fixed to 1.0, otherwise it was fixed to 0.0;
    1941 * get all implications for this varfixing
    1942 */
    1943 nimplvars = SCIPvarGetNImpls(startvar, lower);
    1944
    1945 /* if there are implications for the varfixing, propagate them */
    1946 if( nimplvars > 0 )
    1947 {
    1948 SCIP_VAR** implvars;
    1949 SCIP_BOUNDTYPE* impltypes;
    1950 SCIP_Real* implbounds;
    1951 int* implids;
    1952
    1953 implvars = SCIPvarGetImplVars(startvar, lower);
    1954 impltypes = SCIPvarGetImplTypes(startvar, lower);
    1955 implbounds = SCIPvarGetImplBounds(startvar, lower);
    1956 implids = SCIPvarGetImplIds(startvar, lower);
    1957
    1958 for( n = 0; n < nimplvars; ++n )
    1959 {
    1960 /* implication is just a shortcut, so we do not propagate it now,
    1961 * because we will propagate the longer way, anyway
    1962 */
    1963 if( implids[n] < 0 )
    1964 continue;
    1965
    1966 /* it might happen that implications point to inactive variables (normally, those are removed when a
    1967 * variable becomes inactive, but in some cases, it cannot be done), we have to ignore these variables
    1968 */
    1969 if( !SCIPvarIsActive(implvars[n]) )
    1970 continue;
    1971
    1972 if( impltypes[n] == SCIP_BOUNDTYPE_LOWER )
    1973 {
    1974 SCIP_CALL( tightenVarLb(scip, prop, propdata, implvars[n], implbounds[n], global, startvar,
    1975 starttype, force, 0.0, 0.0, FALSE, &nchgbds, result) );
    1976 }
    1977 else
    1978 {
    1979 SCIP_CALL( tightenVarUb(scip, prop, propdata, implvars[n], implbounds[n], global, startvar,
    1980 starttype, force, 0.0, 0.0, FALSE, &nchgbds, result) );
    1981 }
    1982
    1983 if( *result == SCIP_CUTOFF )
    1984 break;
    1985 }
    1986 if( *result == SCIP_CUTOFF )
    1987 break;
    1988 }
    1989 }
    1990
    1991 /* propagate cliques */
    1992 if( propdata->usecliques )
    1993 {
    1994 int ncliques;
    1995
    1996 /* if the lower bound of the startvar was changed, it was fixed to 1.0, otherwise it was fixed to 0.0;
    1997 * get all cliques for this varfixing
    1998 */
    1999 ncliques = SCIPvarGetNCliques(startvar, lower);
    2000
    2001 /* if there are cliques for the varfixing, propagate them */
    2002 if( ncliques > 0 )
    2003 {
    2004 SCIP_CLIQUE** cliques;
    2005 int j;
    2006
    2007 cliques = SCIPvarGetCliques(startvar, lower);
    2008
    2009 for( j = 0; j < ncliques; ++j )
    2010 {
    2011 SCIP_VAR** cliquevars;
    2012 SCIP_Bool* cliquevals;
    2013 int ncliquevars;
    2014
    2015 cliquevars = SCIPcliqueGetVars(cliques[j]);
    2016 cliquevals = SCIPcliqueGetValues(cliques[j]);
    2017 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
    2018
    2019 /* fix all variables except for the startvar to the value which is not in the clique */
    2020 for( n = 0; n < ncliquevars; ++n )
    2021 {
    2022 if( cliquevars[n] == startvar )
    2023 continue;
    2024
    2025 /* try to tighten the bound */
    2026 if( cliquevals[n] )
    2027 {
    2028 /* unnegated variable is in clique, so it has to be fixed to 0.0 */
    2029 SCIP_CALL( tightenVarUb(scip, prop, propdata, cliquevars[n], 0.0, global, startvar, starttype,
    2030 force, 0.0, 0.0, FALSE, &nchgbds, result) );
    2031 }
    2032 else
    2033 {
    2034 /* negated variable is in clique, so it has to be fixed to 1.0 */
    2035 SCIP_CALL( tightenVarLb(scip, prop, propdata, cliquevars[n], 1.0, global, startvar, starttype,
    2036 force, 0.0, 0.0, FALSE, &nchgbds, result) );
    2037 }
    2038
    2039 if( *result == SCIP_CUTOFF )
    2040 break;
    2041 }
    2042 }
    2043 if( *result == SCIP_CUTOFF )
    2044 break;
    2045 }
    2046 }
    2047 }
    2048
    2049 /* propagate vbounds */
    2050 if( propdata->usevbounds && ! SCIPisInfinity(scip, REALABS(startbound)) )
    2051 {
    2052 SCIP_VAR* boundedvar;
    2053 SCIP_Real newbound;
    2054 SCIP_Real coef;
    2055 SCIP_Real constant;
    2056
    2057 /* iterate over all vbounds for the given bound */
    2058 for( n = 0; n < propdata->nvbounds[startpos]; ++n )
    2059 {
    2060 boundedvar = vars[getVarIndex(propdata->vboundboundedidx[startpos][n])];
    2061 coef = propdata->vboundcoefs[startpos][n];
    2062 constant = propdata->vboundconstants[startpos][n];
    2063
    2064 /* compute new bound */
    2065 newbound = startbound * coef + constant;
    2066
    2067 /* try to tighten the bound */
    2068 if( isIndexLowerbound(propdata->vboundboundedidx[startpos][n]) )
    2069 {
    2070 SCIP_CALL( tightenVarLb(scip, prop, propdata, boundedvar, newbound, global, startvar, starttype, force,
    2071 coef, constant, TRUE, &nchgbds, result) );
    2072 }
    2073 else
    2074 {
    2075 SCIP_CALL( tightenVarUb(scip, prop, propdata, boundedvar, newbound, global, startvar, starttype, force,
    2076 coef, constant, TRUE, &nchgbds, result) );
    2077 }
    2078
    2079 if( *result == SCIP_CUTOFF )
    2080 break;
    2081 }
    2082 if( *result == SCIP_CUTOFF )
    2083 break;
    2084 }
    2085 }
    2086
    2087 /* clean up inqueue */
    2088 for( v = 0; v < nqueuelist; ++v )
    2089 {
    2090 assert( 0 <= queuelist[v] && queuelist[v] < nbounds );
    2091 propdata->inqueue[queuelist[v]] = FALSE;
    2092 assert( SCIPpqueueFind(propdata->propqueue, (void*)(size_t) (queuelist[v] + 1)) == -1 ); /*lint !e571*//*lint !e776*/
    2093 }
    2094 SCIPfreeBufferArray(scip, &queuelist);
    2095
    2096#ifdef SCIP_DEBUG
    2097 for( v = 0; v < nbounds; ++v)
    2098 {
    2099 if( propdata->inqueue[v] )
    2100 assert( SCIPpqueueFind(propdata->propqueue, (void*)(size_t) (v + 1)) >= 0 );
    2101 else
    2102 assert( SCIPpqueueFind(propdata->propqueue, (void*)(size_t) (v + 1)) == -1 );
    2103 }
    2104#endif
    2105
    2106 SCIPdebugMsg(scip, "tightened %d variable bounds\n", nchgbds);
    2107
    2108 /* set the result depending on whether bound changes were found or not */
    2109 if( *result != SCIP_CUTOFF && nchgbds > 0 )
    2110 (*result) = SCIP_REDUCEDDOM;
    2111
    2112 return SCIP_OKAY;
    2113}
    2114
    2115/**@name Callback methods of propagator
    2116 *
    2117 * @{
    2118 */
    2119
    2120/** copy method for propagator plugins (called when SCIP copies plugins) */
    2121static
    2122SCIP_DECL_PROPCOPY(propCopyVbounds)
    2123{ /*lint --e{715}*/
    2124 assert(scip != NULL);
    2125 assert(prop != NULL);
    2126
    2128
    2129 /* call inclusion method of propagator */
    2131
    2132 return SCIP_OKAY;
    2133}
    2134
    2135/** destructor of propagator to free user data (called when SCIP is exiting) */
    2136static
    2137SCIP_DECL_PROPFREE(propFreeVbounds)
    2138{ /*lint --e{715}*/
    2139 SCIP_PROPDATA* propdata;
    2140
    2141 /* free propagator data */
    2142 propdata = SCIPpropGetData(prop);
    2143
    2144 SCIPfreeBlockMemory(scip, &propdata);
    2145 SCIPpropSetData(prop, NULL);
    2146
    2147 return SCIP_OKAY;
    2148}
    2149
    2150/** presolving initialization method of propagator (called when presolving is about to begin) */
    2151static
    2152SCIP_DECL_PROPINITPRE(propInitpreVbounds)
    2153{ /*lint --e{715}*/
    2154 SCIP_PROPDATA* propdata;
    2155
    2156 propdata = SCIPpropGetData(prop);
    2157 assert(propdata != NULL);
    2158
    2159 propdata->lastpresolncliques = 0;
    2160
    2161 return SCIP_OKAY;
    2162}
    2163
    2164/** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
    2165static
    2166SCIP_DECL_PROPEXITSOL(propExitsolVbounds)
    2167{ /*lint --e{715}*/
    2168 SCIP_PROPDATA* propdata;
    2169 int v;
    2170
    2171 propdata = SCIPpropGetData(prop);
    2172 assert(propdata != NULL);
    2173
    2174 /* free data stored for propagation */
    2175 if( propdata->initialized )
    2176 {
    2177 /* drop all variable events */
    2178 SCIP_CALL( dropEvents(scip, propdata) );
    2179
    2180 /* release all variables */
    2181 for( v = 0; v < propdata->nbounds; ++v )
    2182 {
    2183 /* free vbound data */
    2184 if( propdata->vboundsize[v] > 0 )
    2185 {
    2186 SCIPfreeMemoryArray(scip, &propdata->vboundboundedidx[v]);
    2187 SCIPfreeMemoryArray(scip, &propdata->vboundcoefs[v]);
    2188 SCIPfreeMemoryArray(scip, &propdata->vboundconstants[v]);
    2189 }
    2190 }
    2191
    2192 /* free priority queue */
    2193 SCIPpqueueFree(&propdata->propqueue);
    2194
    2195 /* free arrays */
    2196 SCIPfreeBlockMemoryArray(scip, &propdata->vboundsize, propdata->nbounds);
    2197 SCIPfreeBlockMemoryArray(scip, &propdata->nvbounds, propdata->nbounds);
    2198 SCIPfreeBlockMemoryArray(scip, &propdata->vboundconstants, propdata->nbounds);
    2199 SCIPfreeBlockMemoryArray(scip, &propdata->vboundcoefs, propdata->nbounds);
    2200 SCIPfreeBlockMemoryArray(scip, &propdata->vboundboundedidx, propdata->nbounds);
    2201 SCIPfreeBlockMemoryArray(scip, &propdata->inqueue, propdata->nbounds);
    2202 SCIPfreeBlockMemoryArray(scip, &propdata->topoorder, propdata->nbounds);
    2203
    2204 /* free variable array and hashmap */
    2205 SCIPhashmapFree(&propdata->varhashmap);
    2206 SCIPfreeBlockMemoryArray(scip, &propdata->vars, propdata->nbounds / 2);
    2207 }
    2208
    2209 /* reset propagation data */
    2210 resetPropdata(propdata);
    2211
    2212 return SCIP_OKAY;
    2213}
    2214
    2215/** performs Tarjan's algorithm for strongly connected components in the implicitly given directed implication graph
    2216 * from the given start index; each variable x is represented by two nodes lb(x) = 2*idx(x) and ub(x) = 2*idx(x)+1
    2217 * where lb(x) means that the lower bound of x should be changed, i.e., that x is fixed to 1, and vice versa.
    2218 *
    2219 * The algorithm is an iterative version of Tarjans algorithm
    2220 * (see https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm)
    2221 * with some additional tweaks.
    2222 * Each clique x_1 + ... + x_k <= 1 is represented by k(k-1) arcs (lb(x_i),ub(x_j)), j != i.
    2223 * This quadratic number can blow up the running time of Tarjan's algorithm, which is linear in the number of
    2224 * nodes and arcs of the graph. However, it suffices to consider only k of these arcs during the course of the algorithm.
    2225 * To this end, when we first come to a node lb(x_i) of the clique, traverse all arcs (lb(x_i),ub(x_j)) for this particular i,
    2226 * and store that we entered the clique via lb(x_i). Next time we come to any node lb(x_i') of the clique, we know
    2227 * that the only arc pointing to an unvisited node is (lb(x_i'),ub(x_i)), all other edges can be disregarded.
    2228 * After that, we can disregard the clique for the further search.
    2229 * Additionally, we try to identify infeasible fixings for binary variables. Those can be given by a path
    2230 * from x=1 to x=0 (or vice versa) or if x=0 (or 1) implies both y=0 and y=1.
    2231 */
    2232static
    2234 SCIP* scip, /**< SCIP data structure */
    2235 int startnode, /**< node to start the depth-first-search */
    2236 int* startindex, /**< next index to assign to a processed node */
    2237 SCIP_Shortbool* nodeonstack, /**< array to store the whether a each node is on the stack */
    2238 int* nodeindex, /**< array to store the dfs index for each node */
    2239 int* nodelowlink, /**< array to store the lowlink for each node */
    2240 SCIP_Shortbool* nodeinfeasible, /**< array to store whether the fixing of a node was detected to be infeasible */
    2241 int* dfsstack, /**< array of size number of nodes to store the stack */
    2242 int* predstackidx, /**< for each node on the stack: stack position of its predecessor in the Tarjan search */
    2243 int* stacknextclique, /**< array of size number of nodes to store the next clique to be regarded in
    2244 * the algorithm for all nodes on the stack */
    2245 int* stacknextcliquevar, /**< array of size number of nodes to store the next variable in the next clique to be
    2246 * regarded in the algorithm for all nodes on the stack */
    2247 int* topoorder, /**< array with reverse (almost) topological ordering of the nodes */
    2248 int* nordered, /**< number of ordered nodes (disconnected nodes are disregarded) */
    2249 int* cliquefirstentry, /**< node from which a clique was entered for the first time; needed because when
    2250 * entering the clique a second time, only the other bound corresponding to this node
    2251 * remains to be processed */
    2252 int* cliquecurrentexit, /**< for cliques which define an arc on the current path: target node of this arc */
    2253 int* sccvars, /**< array with all nontrivial strongly connected components in the graph */
    2254 int* sccstarts, /**< start indices of SCCs in sccvars array; one additional entry at the end
    2255 * to give length of used part of sccvars array */
    2256 int* nsccs, /**< pointer to store number of strongly connected components */
    2257 int* infeasnodes, /**< sparse array with node indices of infeasible nodes */
    2258 int* ninfeasnodes, /**< pointer to store the number of infeasible nodes */
    2259 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
    2260 )
    2261{
    2262 SCIP_VAR** vars;
    2263 SCIP_VAR* startvar;
    2264 SCIP_Bool lower;
    2265 int label = *startindex;
    2266 int stacksize;
    2267 int currstackidx;
    2268 int curridx;
    2269 int idx;
    2270
    2271 assert(startnode >= 0);
    2272 assert(startnode < 2 * (SCIPgetNVars(scip) - SCIPgetNContVars(scip)));
    2273 assert(nodeindex != NULL);
    2274 assert(nodeindex[startnode] == 0);
    2275 assert(nodelowlink != NULL);
    2276 assert(nodelowlink[startnode] == 0);
    2277 assert(dfsstack != NULL);
    2278 assert(stacknextclique != NULL);
    2279 assert(infeasible != NULL);
    2280
    2281 *infeasible = FALSE;
    2282
    2283 vars = SCIPgetVars(scip);
    2284
    2285 /* put start node on the stack */
    2286 dfsstack[0] = startnode;
    2287 stacknextclique[0] = 0;
    2288 stacknextcliquevar[0] = 0;
    2289 predstackidx[0] = -1;
    2290 stacksize = 1;
    2291 idx = -1;
    2292 currstackidx = 0;
    2293#ifdef DEBUG_TARJAN
    2294 SCIPdebugMsg(scip, "put %s(%s) on stack[%d]\n", indexGetBoundString(dfsstack[stacksize-1]),
    2295 SCIPvarGetName(vars[getVarIndex(dfsstack[stacksize-1])]), stacksize-1);
    2296#endif
    2297
    2298 /* we run until no more bounds indices are on the stack, i.e., no further nodes are connected to the startnode */
    2299 while( stacksize > 0 )
    2300 {
    2301 SCIP_CLIQUE** cliques;
    2302 int ncliques;
    2303 SCIP_Bool found;
    2304 int clqidx = -1;
    2305 int j;
    2306 int i;
    2307
    2308 /* get next node from stack */
    2309 curridx = dfsstack[currstackidx];
    2310 assert(nodelowlink[curridx] <= nodeindex[curridx]);
    2311
    2312 startvar = vars[getVarIndex(curridx)];
    2313 lower = isIndexLowerbound(curridx);
    2314
    2315 /* mark current node as on stack, assign index and lowlink */
    2316 if( nodeindex[curridx] == 0 )
    2317 {
    2318 assert(!nodeonstack[curridx]);
    2319 assert(stacknextclique[currstackidx] == 0);
    2320 assert(stacknextcliquevar[currstackidx] == 0);
    2321 nodeonstack[curridx] = 1;
    2322 nodeindex[curridx] = label;
    2323 nodelowlink[curridx] = label;
    2324 ++label;
    2325
    2326#ifdef DEBUG_TARJAN
    2327 {
    2328 ncliques = SCIPvarGetNCliques(startvar, lower);
    2329 cliques = SCIPvarGetCliques(startvar, lower);
    2330
    2331 SCIPdebugMsg(scip, "variable %s(%s) has %d cliques\n", indexGetBoundString(curridx), SCIPvarGetName(startvar),
    2332 ncliques);
    2333 for( j = 0; j < ncliques; ++j )
    2334 {
    2335 SCIP_VAR** cliquevars;
    2336 SCIP_Bool* cliquevals;
    2337 int ncliquevars;
    2338
    2339 clqidx = SCIPcliqueGetIndex(cliques[j]);
    2340 cliquevars = SCIPcliqueGetVars(cliques[j]);
    2341 cliquevals = SCIPcliqueGetValues(cliques[j]);
    2342 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
    2343
    2344 SCIPdebugMsg(scip, "clique %d [%d vars, stacksize: %d]...\n", clqidx, ncliquevars, stacksize);
    2345 for( int v = 0; v < ncliquevars; ++v )
    2346 SCIPdebugMsgPrint(scip, " %s<%s>", cliquevals[v] ? "" : "~", SCIPvarGetName(cliquevars[v]));
    2347 SCIPdebugMsgPrint(scip, "\n");
    2348 }
    2349 }
    2350#endif
    2351 }
    2352 /* we just did a backtrack and still need to investigate some outgoing edges of the node;
    2353 * however, we should have investigated some of the outgoing edges before
    2354 */
    2355 else
    2356 {
    2357 assert(stacknextclique[currstackidx] > 0 || stacknextcliquevar[currstackidx] > 0);
    2358 assert(nodeindex[curridx] < label);
    2359 }
    2360 assert(stacknextclique[currstackidx] >= 0);
    2361
    2362 ncliques = SCIPvarGetNCliques(startvar, lower);
    2363 cliques = SCIPvarGetCliques(startvar, lower);
    2364 found = FALSE;
    2365
    2366 /* iterate over all not yet handled cliques and search for an unvisited node */
    2367 for( j = stacknextclique[currstackidx]; j < ncliques; ++j )
    2368 {
    2369 SCIP_VAR** cliquevars;
    2370 SCIP_Bool* cliquevals;
    2371 int ncliquevars;
    2372
    2373 clqidx = SCIPcliqueGetIndex(cliques[j]);
    2374 cliquevars = SCIPcliqueGetVars(cliques[j]);
    2375 cliquevals = SCIPcliqueGetValues(cliques[j]);
    2376 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
    2377
    2378 /* we did not look at this clique before from the current node, i.e., we did not backtrack now from another
    2379 * node which was reached via this clique
    2380 */
    2381 if( stacknextcliquevar[currstackidx] == 0 )
    2382 {
    2383#ifdef DEBUG_TARJAN
    2384 SCIPdebugMsg(scip, "clique %d [%d vars, stacksize: %d]...\n", clqidx, ncliquevars, stacksize);
    2385 for( int v = 0; v < ncliquevars; ++v )
    2386 SCIPdebugMsgPrint(scip, " %s<%s>", cliquevals[v] ? "" : "~", SCIPvarGetName(cliquevars[v]));
    2387 SCIPdebugMsgPrint(scip, "\n");
    2388#endif
    2389 /* the clique was not entered before, remember that we first entered it from curridx
    2390 * (add 1 to distinguish it from 0 initialization)
    2391 */
    2392 if( cliquefirstentry[clqidx] == 0 )
    2393 {
    2394 cliquefirstentry[clqidx] = curridx + 1;
    2395 }
    2396 else
    2397 {
    2398 int cliquefirstentryidx = (cliquefirstentry[clqidx] > 0 ? cliquefirstentry[clqidx] : -cliquefirstentry[clqidx]) - 1;
    2399 int infeasnode = -1;
    2400 assert(cliquefirstentryidx != curridx);
    2401
    2402 /* The node by which we entered the clique the first time is still on the stack, so there is a
    2403 * way from that node to the node by which we are entering the clique right now.
    2404 * Since these two assignments together violate the clique and the second assignment is implied by the first,
    2405 * the first one is infeasible
    2406 */
    2407 if( nodeonstack[cliquefirstentryidx] && !nodeinfeasible[cliquefirstentryidx] )
    2408 {
    2409 SCIPdebugMsg(scip, "infeasible assignment (1): %s(%s)\n", indexGetBoundString(cliquefirstentryidx),
    2410 SCIPvarGetName(vars[getVarIndex(cliquefirstentryidx)]));
    2411 infeasnode = cliquefirstentryidx;
    2412 }
    2413 /* the first entry point of the clique was also implied by the current startnode, so this node implies
    2414 * two variables in the clique and is therefore infeasible
    2415 */
    2416 else if( nodeindex[cliquefirstentryidx] >= *startindex && !nodeinfeasible[startnode] )
    2417 {
    2418 SCIPdebugMsg(scip, "infeasible assignment (2): %s(%s)\n", indexGetBoundString(startnode),
    2419 SCIPvarGetName(vars[getVarIndex(startnode)]));
    2420 infeasnode = startnode;
    2421 }
    2422
    2423 /* we identified an infeasibility */
    2424 if( infeasnode >= 0 )
    2425 {
    2426 /* both values are invalid for the variable, the whole problem is infeasible */
    2427 if( nodeinfeasible[getOtherBoundIndex(infeasnode)] )
    2428 {
    2429 *infeasible = TRUE;
    2430 return SCIP_OKAY;
    2431 }
    2432 infeasnodes[*ninfeasnodes] = infeasnode;
    2433 nodeinfeasible[infeasnode] = TRUE;
    2434 ++(*ninfeasnodes);
    2435
    2436 /* the last node by which the clique was exited is not the negation of the current node and still on
    2437 * the stack: update the lowlink of the current node
    2438 */
    2439 if( cliquecurrentexit[clqidx] > 0
    2440 && curridx != getOtherBoundIndex(cliquecurrentexit[clqidx] - 1)
    2441 && nodeonstack[cliquecurrentexit[clqidx] - 1]
    2442 && nodeindex[cliquecurrentexit[clqidx] - 1] < nodelowlink[curridx] )
    2443 {
    2444 nodelowlink[curridx] = nodeindex[cliquecurrentexit[clqidx] - 1];
    2445 }
    2446 }
    2447 /* clique is entered for the second time; there is only one edge left to investigate, namely the edge to
    2448 * the negation of the first entry point
    2449 */
    2450 else if( cliquefirstentry[clqidx] > 0 )
    2451 {
    2452#ifdef DEBUG_TARJAN
    2453 SCIPdebugMsg(scip, "entering clique %d a second time\n", clqidx);
    2454#endif
    2455 idx = getOtherBoundIndex(cliquefirstentry[clqidx] - 1);
    2456
    2457 /* node was not investigated yet, we found the next node to process */
    2458 if( nodeindex[idx] == 0 )
    2459 found = TRUE;
    2460 /* update lowlink if the node is on the stack */
    2461 else if( nodeonstack[idx] && nodeindex[idx] < nodelowlink[curridx] )
    2462 nodelowlink[curridx] = nodeindex[idx];
    2463
    2464 /* cliquefirstentry[clqidx] < 0 means that we entered the clique at least two times already */
    2465 cliquefirstentry[clqidx] = -cliquefirstentry[clqidx];
    2466 }
    2467 else
    2468 {
    2469#ifdef DEBUG_TARJAN
    2470 SCIPdebugMsg(scip, "skip clique %d: visited more than twice already!\n", clqidx);
    2471#endif
    2472 }
    2473 stacknextcliquevar[currstackidx] = ncliquevars;
    2474 }
    2475 }
    2476
    2477 /* iterate over variables in the clique; start where we stopped last time */
    2478 for( i = stacknextcliquevar[currstackidx]; i < ncliquevars; ++i )
    2479 {
    2480 if( cliquevars[i] == startvar )
    2481 continue;
    2482
    2483 if( !SCIPvarIsActive(cliquevars[i]) )
    2484 continue;
    2485
    2486 if( cliquevals[i] )
    2487 idx = getUbIndex(SCIPvarGetProbindex(cliquevars[i]));
    2488 else
    2489 idx = getLbIndex(SCIPvarGetProbindex(cliquevars[i]));
    2490 assert(idx >= 0);
    2491
    2492 /* break when the first unvisited node is reached */
    2493 if( nodeindex[idx] == 0 )
    2494 {
    2495 assert(!nodeonstack[idx]);
    2496 stacknextcliquevar[currstackidx] = i + 1;
    2497 found = TRUE;
    2498 break;
    2499 }
    2500 else if( nodeonstack[idx] && nodeindex[idx] < nodelowlink[curridx] )
    2501 {
    2502 nodelowlink[curridx] = nodeindex[idx];
    2503 }
    2504 }
    2505 if( found )
    2506 {
    2507 if( stacknextcliquevar[currstackidx] < ncliquevars )
    2508 stacknextclique[currstackidx] = j;
    2509 else
    2510 {
    2511 stacknextclique[currstackidx] = j + 1;
    2512 stacknextcliquevar[currstackidx] = 0;
    2513 }
    2514 break;
    2515 }
    2516 else
    2517 {
    2518 assert(i == ncliquevars);
    2519 stacknextclique[currstackidx] = j + 1;
    2520 stacknextcliquevar[currstackidx] = 0;
    2521 }
    2522 }
    2523 assert(found || j == ncliques);
    2524 assert(found || stacknextclique[currstackidx] == ncliques);
    2525
    2526 /* we stopped because we found an unhandled node and not because we reached the end of the list */
    2527 if( found )
    2528 {
    2529 int otheridx = getOtherBoundIndex(idx);
    2530 int infeasnode = -1;
    2531
    2532 assert(idx >= 0);
    2533 assert(!nodeonstack[idx]);
    2534 assert(j < ncliques);
    2535 assert(clqidx >= 0);
    2536
    2537 /* the negated node corresponding to the next node is already on the stack -> the negated assignment is
    2538 * infeasible
    2539 */
    2540 if( nodeonstack[otheridx] && !nodeinfeasible[otheridx] )
    2541 {
    2542 SCIPdebugMsg(scip, "infeasible assignment (3): %s(%s)\n", indexGetBoundString(otheridx),
    2543 SCIPvarGetName(vars[getVarIndex(otheridx)]));
    2544 infeasnode = otheridx;
    2545 }
    2546 /* the negated node corresponding to the next node was reached from the same startnode -> the startnode is
    2547 * infeasible
    2548 */
    2549 else if( nodeindex[otheridx] >= *startindex && !nodeinfeasible[startnode] )
    2550 {
    2551 SCIPdebugMsg(scip, "infeasible assignment (4): %s(%s)\n", indexGetBoundString(startnode),
    2552 SCIPvarGetName(vars[getVarIndex(startnode)]));
    2553 infeasnode = startnode;
    2554 }
    2555 /* treat infeasible case */
    2556 if( infeasnode >= 0 )
    2557 {
    2558 if( nodeinfeasible[getOtherBoundIndex(infeasnode)] )
    2559 {
    2560 *infeasible = TRUE;
    2561 return SCIP_OKAY;
    2562 }
    2563 infeasnodes[*ninfeasnodes] = infeasnode;
    2564 nodeinfeasible[infeasnode] = TRUE;
    2565 ++(*ninfeasnodes);
    2566 }
    2567
    2568 SCIPdebugMsg(scip, "clique: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
    2570
    2571 /* put the adjacent node onto the stack */
    2572 dfsstack[stacksize] = idx;
    2573 stacknextclique[stacksize] = 0;
    2574 stacknextcliquevar[stacksize] = 0;
    2575 cliquecurrentexit[clqidx] = idx + 1;
    2576 predstackidx[stacksize] = currstackidx;
    2577 currstackidx = stacksize;
    2578 stacksize++;
    2579 assert(stacksize <= 2 * (SCIPgetNVars(scip) - SCIPgetNContVars(scip)));
    2580
    2581#ifdef DEBUG_TARJAN
    2582 SCIPdebugMsg(scip, "put %s(%s) on stack[%d]\n", indexGetBoundString(dfsstack[stacksize-1]), SCIPvarGetName(vars[getVarIndex(dfsstack[stacksize-1])]), stacksize-1);
    2583#endif
    2584 /* restart while loop, get next index from stack */
    2585 continue;
    2586 }
    2587 assert(stacknextclique[currstackidx] == ncliques);
    2588
    2589 /* no node with a smaller index can be reached from this node -> it is the root of a SCC,
    2590 * consisting of all nodes above it on the stack, including the node itself
    2591 */
    2592 if( nodelowlink[curridx] == nodeindex[curridx] )
    2593 {
    2594 /* we are only interested in SCCs with more than one node */
    2595 if( dfsstack[stacksize-1] != curridx )
    2596 {
    2597 int sccvarspos = sccstarts[*nsccs];
    2598
    2599 SCIPdebugMsg(scip, "SCC:");
    2600
    2601 /* store the SCC in sccvars */
    2602 do{
    2603 stacksize--;
    2604 idx = dfsstack[stacksize];
    2605 nodeonstack[idx] = 0;
    2606 sccvars[sccvarspos] = idx;
    2607 ++sccvarspos;
    2609#ifdef DEBUG_TARJAN
    2610 SCIPdebugMsg(scip, "remove %s(%s) from stack[%d]\n", indexGetBoundString(dfsstack[stacksize]), SCIPvarGetName(vars[getVarIndex(dfsstack[stacksize])]), stacksize);
    2611#endif
    2612 }
    2613 while( idx != curridx );
    2614 SCIPdebugMsgPrint(scip, "\n");
    2615 ++(*nsccs);
    2616 sccstarts[*nsccs] = sccvarspos;
    2617 }
    2618 /* trivial SCC: remove the single node from the stack, but don't store it as a SCC */
    2619 else
    2620 {
    2621 stacksize--;
    2622#ifdef DEBUG_TARJAN
    2623 SCIPdebugMsg(scip, "remove %s(%s) from stack[%d]\n", indexGetBoundString(dfsstack[stacksize]), SCIPvarGetName(vars[getVarIndex(dfsstack[stacksize])]), stacksize);
    2624#endif
    2625 idx = dfsstack[stacksize];
    2626 nodeonstack[idx] = 0;
    2627 assert(nodeindex[idx] > 0);
    2628 }
    2629 }
    2630 /* in a pure dfs, the node would now leave the stack, add it to the array of nodes in reverse topological order */
    2631 if( topoorder != NULL && (stacksize > 0 || label > *startindex + 1) )
    2632 {
    2633 assert(nordered != NULL);
    2634 topoorder[*nordered] = curridx;
    2635 ++(*nordered);
    2636 }
    2637
    2638 /* the current node was handled, backtrack */
    2639 if( stacksize > 0 )
    2640 {
    2641 idx = dfsstack[predstackidx[currstackidx]];
    2642 nodelowlink[idx] = MIN(nodelowlink[idx], nodelowlink[curridx]);
    2643 currstackidx = predstackidx[currstackidx];
    2644 }
    2645 }
    2646
    2647 *startindex = label;
    2648
    2649 return SCIP_OKAY;
    2650}
    2651
    2652
    2653/** apply fixings and aggregations found by the clique graph analysis */
    2654static
    2656 SCIP* scip, /**< SCIP data structure */
    2657 SCIP_VAR** vars, /**< array of active variables */
    2658 int* infeasnodes, /**< sparse array with node indices of infeasible nodes */
    2659 int ninfeasnodes, /**< pointer to store the number of infeasible nodes */
    2660 SCIP_Shortbool* nodeinfeasible, /**< array to store whether the fixing of a node was detected to be infeasible */
    2661 int* sccvars, /**< array with all nontrivial strongly connected components in the graph */
    2662 int* sccstarts, /**< start indices of SCCs in sccvars array; one additional entry at the end
    2663 * to give length of used part of sccvars array */
    2664 int nsccs, /**< pointer to store number of strongly connected components */
    2665 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
    2666 int* nfixedvars, /**< pointer to number of fixed variables, increment when fixing another one */
    2667 int* naggrvars, /**< pointer to number of aggregated variables, increment when aggregating another one */
    2668 SCIP_RESULT* result /**< pointer to store result of the call */
    2669 )
    2670{
    2671 int i = 0;
    2672
    2673 assert(scip != NULL);
    2674 assert(vars != NULL);
    2675 assert(infeasible != NULL);
    2676
    2677 /* for all infeasible node: fix variable to the other bound */
    2678 if( !(*infeasible) && ninfeasnodes > 0 )
    2679 {
    2680 for( i = 0; i < ninfeasnodes; ++i )
    2681 {
    2682 SCIP_VAR* var = vars[getVarIndex(infeasnodes[i])];
    2683 SCIP_Bool lower = isIndexLowerbound(infeasnodes[i]);
    2684 SCIP_Bool fixed;
    2685
    2686 assert(nodeinfeasible[infeasnodes[i]]);
    2687 nodeinfeasible[infeasnodes[i]] = FALSE;
    2688
    2689 SCIP_CALL( SCIPfixVar(scip, var, lower ? 0.0 : 1.0, infeasible, &fixed) );
    2690
    2691 SCIPdebugMsg(scip, "fix <%s>[%d] to %g: inf=%u, fixed=%u\n",
    2692 SCIPvarGetName(var), infeasnodes[i], lower ? 0.0 : 1.0, *infeasible, fixed);
    2693
    2694 /* fixing was infeasible */
    2695 if( *infeasible )
    2696 break;
    2697
    2698 /* increase fixing counter and update result pointer */
    2699 if( fixed )
    2700 {
    2701 *result = SCIP_SUCCESS;
    2702 ++(*nfixedvars);
    2703 }
    2704 }
    2705 }
    2706 assert((*infeasible) || i == ninfeasnodes);
    2707
    2708 /* clear clean buffer array (if we did not enter the block above or stopped early due to an infeasibility) */
    2709 for( ; i < ninfeasnodes; ++i )
    2710 {
    2711 assert(nodeinfeasible[infeasnodes[i]]);
    2712 nodeinfeasible[infeasnodes[i]] = FALSE;
    2713 }
    2714
    2715 if( !(*infeasible) && nsccs > 0 )
    2716 {
    2717 /* for each strongly connected component: aggregate all variables to the first one */
    2718 for( i = 0; i < nsccs; ++i )
    2719 {
    2720 SCIP_VAR* startvar;
    2721 SCIP_Bool lower;
    2722 SCIP_Bool aggregated;
    2723 SCIP_Bool redundant;
    2724 int v;
    2725
    2726 assert(sccstarts[i] < sccstarts[i+1] - 1);
    2727
    2728 /* get variable and boundtype for first node of the SCC */
    2729 startvar = vars[getVarIndex(sccvars[sccstarts[i]])];
    2730 lower = isIndexLowerbound(sccvars[sccstarts[i]]);
    2731
    2732 for( v = sccstarts[i] + 1; v < sccstarts[i+1]; ++v )
    2733 {
    2734 /* aggregate variables: if both nodes represent the same bound, we have x=1 <=> y=1,
    2735 * and thus aggregate x - y = 0; if both represent different bounds we have
    2736 * x=1 <=> y=0, so we aggregate x + y = 1
    2737 */
    2738 SCIP_CALL( SCIPaggregateVars(scip, startvar, vars[getVarIndex(sccvars[v])], 1.0,
    2739 lower == isIndexLowerbound(sccvars[v]) ? -1.0 : 1.0,
    2740 lower == isIndexLowerbound(sccvars[v]) ? 0.0 : 1.0,
    2741 infeasible, &redundant, &aggregated) );
    2742
    2743 SCIPdebugMsg(scip, "aggregate <%s> + %g <%s> = %g: inf=%u, red=%u, aggr=%u\n",
    2744 SCIPvarGetName(startvar), lower == isIndexLowerbound(sccvars[v]) ? -1.0 : 1.0,
    2745 SCIPvarGetName(vars[getVarIndex(sccvars[v])]), lower == isIndexLowerbound(sccvars[v]) ? 0.0 : 1.0,
    2746 *infeasible, redundant, aggregated);
    2747
    2748 /* aggregation was infeasible */
    2749 if( *infeasible )
    2750 break;
    2751
    2752 /* increase aggregation counter and update result pointer */
    2753 if( aggregated )
    2754 {
    2755 ++(*naggrvars);
    2756 *result = SCIP_SUCCESS;
    2757 }
    2758 }
    2759 }
    2760 }
    2761
    2762 return SCIP_OKAY;
    2763}
    2764
    2765
    2766
    2767/** presolving method of propagator: search for strongly connected components in the implication graph and
    2768 * aggregate all variables within a component; additionally, identifies infeasible variable assignments
    2769 * as a side product if a path from x=1 to x=0 (or vice versa) is found or x=1 implies both y=0 and y=1
    2770 * The identification of such assignments depends on the order in which variable bounds are processed;
    2771 * therefore, we are doing a second run with the bounds processed in (almost) topological order.
    2772 */
    2773static
    2774SCIP_DECL_PROPPRESOL(propPresolVbounds)
    2775{ /*lint --e{715}*/
    2776 SCIP_PROPDATA* propdata;
    2777 SCIP_VAR** tmpvars;
    2778 SCIP_VAR** vars;
    2779 int* dfsstack;
    2780 int* stacknextclique;
    2781 int* stacknextcliquevar;
    2782 int* nodeindex;
    2783 int* nodelowlink;
    2784 int* predstackidx;
    2785 int* cliquefirstentry;
    2786 int* cliquecurrentexit;
    2787 int* topoorder;
    2788 int* sccvars;
    2789 int* sccstarts;
    2790 int* infeasnodes;
    2791 SCIP_Shortbool* nodeonstack;
    2792 SCIP_Shortbool* nodeinfeasible;
    2793 int ninfeasnodes;
    2794 int nsccs;
    2795 int nbounds;
    2796 int nbinvars;
    2797 int ncliques;
    2798 int startindex = 1;
    2799 int nordered = 0;
    2800 int i;
    2801 SCIP_Bool infeasible = FALSE;
    2802
    2803 assert(scip != NULL);
    2804
    2805 propdata = SCIPpropGetData(prop);
    2806 assert(propdata != NULL);
    2807
    2808 ncliques = SCIPgetNCliques(scip);
    2809
    2810 *result = SCIP_DIDNOTRUN;
    2811
    2812 if( ncliques < 2 )
    2813 return SCIP_OKAY;
    2814
    2815 /* too many cliques for medium presolving */
    2816 if( presoltiming == SCIP_PRESOLTIMING_MEDIUM && ncliques > propdata->maxcliquesmedium * SCIPgetNBinVars(scip) )
    2817 return SCIP_OKAY;
    2818
    2819 /* too many cliques for exhaustive presolving */
    2820 if( ncliques > propdata->maxcliquesexhaustive * SCIPgetNBinVars(scip) )
    2821 return SCIP_OKAY;
    2822
    2823 /* only run if enough new cliques were created since the last successful call */
    2824 if( SCIPgetNCliquesCreated(scip) < (1.0 + propdata->minnewcliques) * propdata->lastpresolncliques )
    2825 return SCIP_OKAY;
    2826
    2827 *result = SCIP_DIDNOTFIND;
    2828
    2829 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    2830 nbounds = 2 * nbinvars;
    2831
    2832 /* cleanup cliques, stop if this proved infeasibility already */
    2833 SCIP_CALL( SCIPcleanupCliques(scip, &infeasible) );
    2834
    2835 if( infeasible )
    2836 {
    2837 *result = SCIP_CUTOFF;
    2838 return SCIP_OKAY;
    2839 }
    2840
    2841 tmpvars = SCIPgetVars(scip);
    2842
    2843 /* duplicate variable array; needed to get the fixings right later */
    2844 SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, tmpvars, nbinvars) );
    2845
    2846 SCIP_CALL( SCIPallocBufferArray(scip, &dfsstack, nbounds) );
    2847 SCIP_CALL( SCIPallocBufferArray(scip, &stacknextclique, nbounds) );
    2848 SCIP_CALL( SCIPallocBufferArray(scip, &stacknextcliquevar, nbounds) );
    2849 SCIP_CALL( SCIPallocBufferArray(scip, &predstackidx, nbounds) );
    2850 SCIP_CALL( SCIPallocBufferArray(scip, &topoorder, nbounds) );
    2851 SCIP_CALL( SCIPallocBufferArray(scip, &sccvars, nbounds) );
    2852 SCIP_CALL( SCIPallocBufferArray(scip, &sccstarts, nbinvars + 1) );
    2853 SCIP_CALL( SCIPallocBufferArray(scip, &infeasnodes, nbounds) );
    2854 SCIP_CALL( SCIPallocClearBufferArray(scip, &nodeindex, nbounds) );
    2855 SCIP_CALL( SCIPallocClearBufferArray(scip, &nodelowlink, nbounds) );
    2856 SCIP_CALL( SCIPallocClearBufferArray(scip, &cliquefirstentry, ncliques) );
    2857 SCIP_CALL( SCIPallocClearBufferArray(scip, &cliquecurrentexit, ncliques) );
    2858 SCIP_CALL( SCIPallocClearBufferArray(scip, &nodeonstack, nbounds) );
    2859 SCIP_CALL( SCIPallocCleanBufferArray(scip, &nodeinfeasible, nbounds) );
    2860 sccstarts[0] = 0;
    2861 nsccs = 0;
    2862 ninfeasnodes = 0;
    2863
    2864 /* while there are unvisited nodes, run Tarjan's algorithm starting from one of these nodes */
    2865 for( i = 0; i < nbounds && !infeasible; ++i )
    2866 {
    2867 if( nodeindex[i] == 0 )
    2868 {
    2869 SCIP_CALL( tarjan(scip, i, &startindex, nodeonstack, nodeindex, nodelowlink, nodeinfeasible,
    2870 dfsstack, predstackidx, stacknextclique, stacknextcliquevar, topoorder, &nordered,
    2871 cliquefirstentry, cliquecurrentexit, sccvars, sccstarts, &nsccs,
    2872 infeasnodes, &ninfeasnodes, &infeasible) );
    2873 }
    2874 }
    2875 assert(nordered <= nbounds);
    2876
    2877 /* aggregate all variables within a SCC and fix all variables for which one bounds was proven infeasible */
    2878 if( ninfeasnodes > 0 || nsccs > 0 )
    2879 {
    2880 SCIP_CALL( applyFixingsAndAggregations(scip, vars, infeasnodes, ninfeasnodes, nodeinfeasible,
    2881 sccvars, sccstarts, nsccs, &infeasible, nfixedvars, naggrvars, result) );
    2882 }
    2883
    2884 /* second round, now with topological order! */
    2885 if( !infeasible && nordered > 0 )
    2886 {
    2887 SCIP_VAR** vars2;
    2888 int nbounds2;
    2889
    2890 assert(nordered > 1);
    2891
    2892 /* we already fixed or aggregated some variables in the first run, so we better clean up the cliques */
    2893 if( *result == SCIP_SUCCESS )
    2894 {
    2895 SCIP_CALL( SCIPcleanupCliques(scip, &infeasible) );
    2896
    2897 if( infeasible )
    2898 goto TERMINATE;
    2899 }
    2900
    2901 nbounds2 = 2 * (SCIPgetNVars(scip) - SCIPgetNContVars(scip));
    2902 ncliques = SCIPgetNCliques(scip);
    2903
    2904 SCIP_CALL( SCIPduplicateBufferArray(scip, &vars2, tmpvars, nbounds2/2) );
    2905
    2906 /* clear arrays that should be initialized to 0 */
    2907 BMSclearMemoryArray(nodeonstack, nbounds2);
    2908 BMSclearMemoryArray(nodeindex, nbounds2);
    2909 BMSclearMemoryArray(nodelowlink, nbounds2);
    2910 BMSclearMemoryArray(cliquefirstentry, ncliques);
    2911 BMSclearMemoryArray(cliquecurrentexit, ncliques);
    2912 sccstarts[0] = 0;
    2913 nsccs = 0;
    2914 ninfeasnodes = 0;
    2915 startindex = 1;
    2916
    2917 /* while there are unvisited nodes, run Tarjan's algorithm starting from one of these nodes */
    2918 for( i = nordered - 1; i >= 0 && !infeasible; --i )
    2919 {
    2920 int varindex;
    2921 int startpos;
    2922 assert(topoorder[i] < nbounds);
    2923
    2924 /* variable of next node in topological order */
    2925 varindex = SCIPvarGetProbindex(vars[getVarIndex(topoorder[i])]);
    2926
    2927 /* variable was not fixed after the first run */
    2928 if( varindex >= 0 )
    2929 {
    2930 startpos = isIndexLowerbound(topoorder[i]) ? getLbIndex(varindex) : getUbIndex(varindex);
    2931 if( nodeindex[startpos] == 0 )
    2932 {
    2933 SCIP_CALL( tarjan(scip, startpos, &startindex, nodeonstack, nodeindex, nodelowlink, nodeinfeasible,
    2934 dfsstack, predstackidx, stacknextclique, stacknextcliquevar, NULL, NULL,
    2935 cliquefirstentry, cliquecurrentexit, sccvars, sccstarts, &nsccs,
    2936 infeasnodes, &ninfeasnodes, &infeasible) );
    2937 }
    2938 }
    2939 }
    2940
    2941 /* aggregate all variables within a SCC and fix all variables for which one bounds was proven infeasible */
    2942 if( ninfeasnodes > 0 || nsccs > 0 )
    2943 {
    2944 SCIP_CALL( applyFixingsAndAggregations(scip, vars2, infeasnodes, ninfeasnodes, nodeinfeasible,
    2945 sccvars, sccstarts, nsccs, &infeasible, nfixedvars, naggrvars, result) );
    2946 }
    2947
    2948 SCIPfreeBufferArray(scip, &vars2);
    2949 }
    2950
    2951 TERMINATE:
    2952 if( infeasible )
    2953 *result = SCIP_CUTOFF;
    2954#ifndef NDEBUG
    2955 for( i = 0; i < nbounds; ++i )
    2956 {
    2957 assert(nodeinfeasible[i] == FALSE);
    2958 }
    2959#endif
    2960 SCIPfreeCleanBufferArray(scip, &nodeinfeasible);
    2961 SCIPfreeBufferArray(scip, &nodeonstack);
    2962 SCIPfreeBufferArray(scip, &cliquecurrentexit);
    2963 SCIPfreeBufferArray(scip, &cliquefirstentry);
    2964 SCIPfreeBufferArray(scip, &nodelowlink);
    2965 SCIPfreeBufferArray(scip, &nodeindex);
    2966 SCIPfreeBufferArray(scip, &infeasnodes);
    2967 SCIPfreeBufferArray(scip, &sccstarts);
    2968 SCIPfreeBufferArray(scip, &sccvars);
    2969 SCIPfreeBufferArray(scip, &topoorder);
    2970 SCIPfreeBufferArray(scip, &predstackidx);
    2971 SCIPfreeBufferArray(scip, &stacknextcliquevar);
    2972 SCIPfreeBufferArray(scip, &stacknextclique);
    2973 SCIPfreeBufferArray(scip, &dfsstack);
    2974 SCIPfreeBufferArray(scip, &vars);
    2975
    2976 propdata->lastpresolncliques = SCIPgetNCliquesCreated(scip);
    2977
    2978 return SCIP_OKAY;
    2979}
    2980
    2981
    2982
    2983/** execution method of propagator */
    2984static
    2985SCIP_DECL_PROPEXEC(propExecVbounds)
    2986{ /*lint --e{715}*/
    2987 *result = SCIP_DIDNOTRUN;
    2988
    2989 /* perform variable lower and upper bound propagation */
    2990 SCIP_CALL( propagateVbounds(scip, prop, FALSE, result) );
    2991
    2992 assert((*result) == SCIP_CUTOFF || (*result) == SCIP_DIDNOTRUN
    2993 || (*result) == SCIP_DIDNOTFIND || (*result) == SCIP_REDUCEDDOM);
    2994
    2995 return SCIP_OKAY;
    2996}
    2997
    2998/** propagation conflict resolving method of propagator */
    2999static
    3000SCIP_DECL_PROPRESPROP(propRespropVbounds)
    3001{ /*lint --e{715}*/
    3002 SCIP_PROPDATA* propdata;
    3003 SCIP_VAR** vars;
    3004 SCIP_VAR* startvar;
    3005 SCIP_BOUNDTYPE starttype;
    3006 int pos;
    3007
    3008 propdata = SCIPpropGetData(prop);
    3009 assert(propdata != NULL);
    3010
    3011 starttype = inferInfoGetBoundtype(intToInferInfo(inferinfo));
    3012 pos = inferInfoGetPos(intToInferInfo(inferinfo));
    3013 assert(pos >= 0);
    3014 assert(pos < propdata->nbounds);
    3015
    3016 vars = propdata->vars;
    3017 assert(vars != NULL);
    3018 startvar = vars[getVarIndex(pos)];
    3019 assert(startvar != NULL);
    3020 assert(startvar != infervar);
    3021
    3022 SCIPdebugMsg(scip, "explain %s bound change of variable <%s>\n",
    3023 getBoundtypeString(boundtype), SCIPvarGetName(infervar));
    3024
    3025 if( !SCIPvarIsBinary(startvar) && propdata->usebdwidening )
    3026 {
    3027 int* vboundboundedidx;
    3028 SCIP_Real constant;
    3029 SCIP_Real coef;
    3030 int inferidx;
    3031 int nvbounds;
    3032 int b;
    3033
    3034 nvbounds = propdata->nvbounds[pos];
    3035 vboundboundedidx = propdata->vboundboundedidx[pos];
    3036
    3037 inferidx = boundtype == SCIP_BOUNDTYPE_LOWER ? varGetLbIndex(propdata, infervar) : varGetUbIndex(propdata, infervar);
    3038 assert(inferidx >= 0);
    3039
    3040 for( b = 0; b < nvbounds; ++b )
    3041 {
    3042 if( vboundboundedidx[b] == inferidx )
    3043 break;
    3044 }
    3045 assert(b < nvbounds);
    3046
    3047 coef = propdata->vboundcoefs[pos][b];
    3048 constant = propdata->vboundconstants[pos][b];
    3049 assert(!SCIPisZero(scip, coef));
    3050
    3051 /* compute the relaxed bound which is sufficient to propagate the inference bound of given variable */
    3052 if( boundtype == SCIP_BOUNDTYPE_LOWER )
    3053 relaxedbd = computeRelaxedLowerbound(scip, infervar, relaxedbd, coef, constant);
    3054 else
    3055 relaxedbd = computeRelaxedUpperbound(scip, infervar, relaxedbd, coef, constant);
    3056
    3057 /* try to relax variable bound variable */
    3058 SCIP_CALL( relaxVbdvar(scip, startvar, starttype, bdchgidx, relaxedbd) );
    3059 }
    3060 else
    3061 {
    3062 SCIP_CALL( resolvePropagation(scip, propdata, startvar, starttype, bdchgidx) );
    3063 }
    3064
    3065 (*result) = SCIP_SUCCESS;
    3066
    3067 return SCIP_OKAY;
    3068}
    3069
    3070/**@} */
    3071
    3072/**@name Callback methods of event handler
    3073 *
    3074 * @{
    3075 */
    3076
    3077/** execution method of bound change event handler */
    3078static
    3079SCIP_DECL_EVENTEXEC(eventExecVbound)
    3080{ /*lint --e{715}*/
    3081 SCIP_PROPDATA* propdata;
    3082 int idx;
    3083
    3084 assert(eventhdlr != NULL);
    3085
    3086 propdata = (SCIP_PROPDATA*)SCIPeventhdlrGetData(eventhdlr);
    3087 assert(propdata != NULL);
    3088
    3089 /* coverity[pointer_conversion_loses_bits] */
    3090 idx = (int) (size_t) eventdata;
    3091 assert(idx >= 0);
    3092
    3093 SCIPdebugMsg(scip, "eventexec (type=%" SCIP_EVENTTYPE_FORMAT "): try to add sort index %d: %s(%s) to priority queue\n", SCIPeventGetType(event),
    3094 idx, indexGetBoundString(propdata->topoorder[idx]),
    3095 SCIPvarGetName(propdata->vars[getVarIndex(propdata->topoorder[idx])]));
    3096
    3098 && SCIPeventGetNewbound(event) > 0.5 )
    3099 return SCIP_OKAY;
    3100
    3102 && SCIPeventGetNewbound(event) < 0.5 )
    3103 return SCIP_OKAY;
    3104
    3105 assert(getVarIndex(propdata->topoorder[idx]) < SCIPgetNVars(scip));
    3106 assert(SCIPvarGetType(propdata->vars[getVarIndex(propdata->topoorder[idx])]) != SCIP_VARTYPE_BINARY
    3107 || SCIPvarIsImpliedIntegral(propdata->vars[getVarIndex(propdata->topoorder[idx])])
    3108 || (isIndexLowerbound(propdata->topoorder[idx]) == (SCIPeventGetNewbound(event) > 0.5)));
    3109
    3110 /* add the bound change to the propagation queue, if it is not already contained */
    3111 if( !propdata->inqueue[idx] )
    3112 {
    3113 SCIP_CALL( SCIPpqueueInsert(propdata->propqueue, (void*)(size_t)(idx + 1)) ); /*lint !e571 !e776*/
    3114 propdata->inqueue[idx] = TRUE;
    3115 assert(SCIPpqueueNElems(propdata->propqueue) > 0);
    3116 }
    3117
    3118 return SCIP_OKAY;
    3119}
    3120
    3121/**@} */
    3122
    3123
    3124/** creates the vbounds propagator and includes it in SCIP */
    3126 SCIP* scip /**< SCIP data structure */
    3127 )
    3128{
    3129 SCIP_PROPDATA* propdata;
    3130 SCIP_PROP* prop;
    3131
    3132 /* create vbounds propagator data */
    3133 SCIP_CALL( SCIPallocBlockMemory(scip, &propdata) );
    3134
    3135 /* reset propagation data */
    3136 resetPropdata(propdata);
    3137
    3138 /* include propagator */
    3140 propExecVbounds, propdata) );
    3141 assert(prop != NULL);
    3142
    3143 /* set optional callbacks via setter functions */
    3144 SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyVbounds) );
    3145 SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeVbounds) );
    3146 SCIP_CALL( SCIPsetPropInitpre(scip, prop, propInitpreVbounds) );
    3147 SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolVbounds) );
    3148 SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropVbounds) );
    3151
    3152 /* include event handler for bound change events */
    3154 eventExecVbound, (SCIP_EVENTHDLRDATA*)propdata) );
    3155
    3157 "propagating/" PROP_NAME "/usebdwidening", "should bound widening be used to initialize conflict analysis?",
    3158 &propdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
    3160 "propagating/" PROP_NAME "/useimplics", "should implications be propagated?",
    3161 &propdata->useimplics, TRUE, DEFAULT_USEIMPLICS, NULL, NULL) );
    3163 "propagating/" PROP_NAME "/usecliques", "should cliques be propagated?",
    3164 &propdata->usecliques, TRUE, DEFAULT_USECLIQUES, NULL, NULL) );
    3166 "propagating/" PROP_NAME "/usevbounds", "should vbounds be propagated?",
    3167 &propdata->usevbounds, TRUE, DEFAULT_USEVBOUNDS, NULL, NULL) );
    3169 "propagating/" PROP_NAME "/dotoposort", "should the bounds be topologically sorted in advance?",
    3170 &propdata->dotoposort, FALSE, DEFAULT_DOTOPOSORT, NULL, NULL) );
    3172 "propagating/" PROP_NAME "/sortcliques", "should cliques be regarded for the topological sort?",
    3173 &propdata->sortcliques, TRUE, DEFAULT_SORTCLIQUES, NULL, NULL) );
    3175 "propagating/" PROP_NAME "/detectcycles", "should cycles in the variable bound graph be identified?",
    3176 &propdata->detectcycles, FALSE, DEFAULT_DETECTCYCLES, NULL, NULL) );
    3178 "propagating/" PROP_NAME "/minnewcliques", "minimum percentage of new cliques to trigger another clique table analysis",
    3179 &propdata->minnewcliques, FALSE, DEFAULT_MINNEWCLIQUES, 0.0, 1.0, NULL, NULL) );
    3180 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/maxcliquesmedium",
    3181 "maximum number of cliques per variable to run clique table analysis in medium presolving",
    3182 &propdata->maxcliquesmedium, FALSE, DEFAULT_MAXCLIQUESMEDIUM, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    3183 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/maxcliquesexhaustive",
    3184 "maximum number of cliques per variable to run clique table analysis in exhaustive presolving",
    3185 &propdata->maxcliquesexhaustive, FALSE, DEFAULT_MAXCLIQUESEXHAUSTIVE, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    3186
    3187 return SCIP_OKAY;
    3188}
    3189
    3190/** returns TRUE if the propagator has the status that all variable lower and upper bounds are propgated */
    3192 SCIP* scip /**< SCIP data structure */
    3193 )
    3194{
    3195 SCIP_PROP* prop;
    3196 SCIP_PROPDATA* propdata;
    3197
    3198 prop = SCIPfindProp(scip, PROP_NAME);
    3199 assert(prop != NULL);
    3200
    3201 propdata = SCIPpropGetData(prop);
    3202 assert(propdata != NULL);
    3203
    3204 return (SCIPpqueueNElems(propdata->propqueue) == 0);
    3205}
    3206
    3207/** performs propagation of variables lower and upper bounds */
    3209 SCIP* scip, /**< SCIP data structure */
    3210 SCIP_Bool force, /**< should domain changes for continuous variables be forced */
    3211 SCIP_RESULT* result /**< pointer to store result */
    3212 )
    3213{
    3214 SCIP_PROP* prop;
    3215
    3216 prop = SCIPfindProp(scip, PROP_NAME);
    3217 assert(prop != NULL);
    3218
    3219 /* perform variable lower and upper bound propagation */
    3220 SCIP_CALL( propagateVbounds(scip, prop, force, result) );
    3221
    3222 assert((*result) == SCIP_CUTOFF || (*result) == SCIP_DIDNOTRUN
    3223 || (*result) == SCIP_DIDNOTFIND || (*result) == SCIP_REDUCEDDOM);
    3224
    3225 return SCIP_OKAY;
    3226}
    SCIP_VAR ** b
    Definition: circlepacking.c:65
    struct InferInfo INFERINFO
    #define NULL
    Definition: def.h:257
    #define SCIP_Shortbool
    Definition: def.h:108
    #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 SCIPABORT()
    Definition: def.h:336
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    const char * SCIPgetProbName(SCIP *scip)
    Definition: scip_prob.c:1242
    int SCIPgetNContVars(SCIP *scip)
    Definition: scip_prob.c:2569
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    int SCIPgetNBinVars(SCIP *scip)
    Definition: scip_prob.c:2293
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3304
    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
    SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3179
    #define SCIPdebugMsgPrint
    Definition: scip_message.h:79
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_Bool SCIPisPropagatedVbounds(SCIP *scip)
    SCIP_RETCODE SCIPexecPropVbounds(SCIP *scip, SCIP_Bool force, SCIP_RESULT *result)
    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
    int SCIPpqueueFind(SCIP_PQUEUE *pqueue, void *elem)
    Definition: misc.c:1551
    void SCIPpqueueFree(SCIP_PQUEUE **pqueue)
    Definition: misc.c:1324
    SCIP_RETCODE SCIPpqueueInsert(SCIP_PQUEUE *pqueue, void *elem)
    Definition: misc.c:1396
    int SCIPpqueueNElems(SCIP_PQUEUE *pqueue)
    Definition: misc.c:1529
    SCIP_RETCODE SCIPpqueueCreate(SCIP_PQUEUE **pqueue, int initsize, SCIP_Real sizefac, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), SCIP_DECL_PQUEUEELEMCHGPOS((*elemchgpos)))
    Definition: misc.c:1297
    void * SCIPpqueueRemove(SCIP_PQUEUE *pqueue)
    Definition: misc.c:1495
    SCIP_RETCODE SCIPincludePropVbounds(SCIP *scip)
    SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
    SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
    SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
    SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
    SCIP_RETCODE SCIPanalyzeConflict(SCIP *scip, int validdepth, SCIP_Bool *success)
    SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
    SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
    SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
    SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
    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
    SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
    Definition: event.c:406
    SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
    Definition: event.c:1194
    SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
    Definition: scip_event.c:367
    SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
    Definition: scip_event.c:413
    SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
    Definition: event.c:1217
    SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
    Definition: event.c:1415
    #define SCIPfreeCleanBufferArray(scip, ptr)
    Definition: scip_mem.h:146
    #define SCIPallocCleanBufferArray(scip, ptr, num)
    Definition: scip_mem.h:142
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    #define SCIPreallocMemoryArray(scip, ptr, newnum)
    Definition: scip_mem.h:70
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPfreeMemoryArray(scip, ptr)
    Definition: scip_mem.h:80
    #define SCIPduplicateBufferArray(scip, ptr, source, num)
    Definition: scip_mem.h:132
    #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
    #define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
    Definition: scip_mem.h:105
    SCIP_PROP * SCIPfindProp(SCIP *scip, const char *name)
    Definition: scip_prop.c:333
    void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
    Definition: prop.c:801
    SCIP_RETCODE SCIPsetPropResprop(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPRESPROP((*propresprop)))
    Definition: scip_prop.c:316
    SCIP_PROPDATA * SCIPpropGetData(SCIP_PROP *prop)
    Definition: prop.c:791
    SCIP_RETCODE SCIPsetPropPresol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPPRESOL((*proppresol)), int presolpriority, int presolmaxrounds, SCIP_PRESOLTIMING presoltiming)
    Definition: scip_prop.c:283
    const char * SCIPpropGetName(SCIP_PROP *prop)
    Definition: prop.c:951
    SCIP_RETCODE SCIPsetPropInitpre(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPINITPRE((*propinitpre)))
    Definition: scip_prop.c:251
    SCIP_RETCODE SCIPsetPropFree(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPFREE((*propfree)))
    Definition: scip_prop.c:171
    SCIP_RETCODE SCIPsetPropCopy(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPCOPY((*propcopy)))
    Definition: scip_prop.c:155
    SCIP_RETCODE SCIPsetPropExitsol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPEXITSOL((*propexitsol)))
    Definition: scip_prop.c:235
    SCIP_RETCODE SCIPincludePropBasic(SCIP *scip, SCIP_PROP **propptr, const char *name, const char *desc, int priority, int freq, SCIP_Bool delay, SCIP_PROPTIMING timingmask, SCIP_DECL_PROPEXEC((*propexec)), SCIP_PROPDATA *propdata)
    Definition: scip_prop.c:118
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Real SCIPgetHugeValue(SCIP *scip)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    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)
    SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPinRepropagation(SCIP *scip)
    Definition: scip_tree.c:146
    SCIP_RETCODE SCIPcutoffNode(SCIP *scip, SCIP_NODE *node)
    Definition: scip_tree.c:436
    SCIP_NODE * SCIPgetRootNode(SCIP *scip)
    Definition: scip_tree.c:110
    SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6401
    int SCIPvarGetNVlbs(SCIP_VAR *var)
    Definition: var.c:24514
    SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
    Definition: var.c:24536
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23674
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    SCIP_RETCODE SCIPinferVarUbProp(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_PROP *inferprop, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:7699
    SCIP_RETCODE SCIPtightenVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:8257
    SCIP_Bool SCIPvarHasImplic(SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype)
    Definition: var.c:16486
    int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24600
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23530
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
    Definition: scip_var.c:10550
    SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6651
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
    Definition: scip_var.c:2499
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24617
    SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
    Definition: scip_var.c:2872
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23694
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    int SCIPgetNCliquesCreated(SCIP *scip)
    Definition: scip_var.c:9539
    SCIP_RETCODE SCIPcleanupCliques(SCIP *scip, SCIP_Bool *infeasible)
    Definition: scip_var.c:9469
    SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
    Definition: scip_var.c:5634
    SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
    Definition: var.c:24546
    int * SCIPvarGetImplIds(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24662
    int SCIPvarGetNVubs(SCIP_VAR *var)
    Definition: var.c:24556
    SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
    Definition: scip_var.c:5570
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23522
    SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24646
    int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24674
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    int SCIPgetNCliques(SCIP *scip)
    Definition: scip_var.c:9512
    SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
    Definition: var.c:24526
    SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24685
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
    Definition: scip_var.c:10318
    SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
    Definition: scip_var.c:2736
    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_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24632
    SCIP_RETCODE SCIPtightenVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:8026
    SCIP_RETCODE SCIPinferVarLbProp(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_PROP *inferprop, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:7584
    SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
    Definition: implics.c:3384
    int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
    Definition: implics.c:3374
    SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
    Definition: implics.c:3396
    int SCIPcliqueGetIndex(SCIP_CLIQUE *clique)
    Definition: implics.c:3420
    SCIP_Bool SCIPcliqueIsEquation(SCIP_CLIQUE *clique)
    Definition: implics.c:3440
    memory allocation routines
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    #define PROP_PRESOL_MAXROUNDS
    Definition: prop_vbounds.c:120
    #define PROP_PRESOLTIMING
    Definition: prop_vbounds.c:119
    #define getOtherBoundIndex(idx)
    Definition: prop_vbounds.c:173
    #define PROP_DESC
    Definition: prop_vbounds.c:112
    static SCIP_RETCODE propagateVbounds(SCIP *scip, SCIP_PROP *prop, SCIP_Bool force, SCIP_RESULT *result)
    #define DEFAULT_MINNEWCLIQUES
    Definition: prop_vbounds.c:146
    #define DEFAULT_USEBDWIDENING
    Definition: prop_vbounds.c:139
    static SCIP_RETCODE relaxVbdvar(SCIP *scip, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd)
    static SCIP_RETCODE topologicalSort(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Bool *infeasible)
    #define isIndexLowerbound(idx)
    Definition: prop_vbounds.c:169
    #define getBoundString(lower)
    Definition: prop_vbounds.c:170
    static SCIP_RETCODE extractCycle(SCIP *scip, SCIP_PROPDATA *propdata, int *dfsstack, int *stacknextedge, int stacksize, SCIP_Bool samebound, SCIP_Bool *infeasible)
    Definition: prop_vbounds.c:522
    #define PROP_NAME
    Definition: prop_vbounds.c:111
    static SCIP_DECL_PROPFREE(propFreeVbounds)
    static SCIP_RETCODE dfs(SCIP *scip, SCIP_PROPDATA *propdata, int startnode, int *visited, int *dfsstack, int *stacknextedge, int *dfsnodes, int *ndfsnodes, SCIP_Bool *infeasible)
    Definition: prop_vbounds.c:806
    #define VISITED
    Definition: prop_vbounds.c:802
    static SCIP_Real computeRelaxedLowerbound(SCIP *scip, SCIP_VAR *var, SCIP_Real inferlb, SCIP_Real coef, SCIP_Real constant)
    #define getUbIndex(idx)
    Definition: prop_vbounds.c:166
    #define DEFAULT_MAXCLIQUESMEDIUM
    Definition: prop_vbounds.c:147
    static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_PROPDATA *propdata)
    Definition: prop_vbounds.c:354
    #define ACTIVE
    Definition: prop_vbounds.c:803
    static SCIP_DECL_EVENTEXEC(eventExecVbound)
    #define DEFAULT_USECLIQUES
    Definition: prop_vbounds.c:141
    static SCIP_DECL_SORTPTRCOMP(compVarboundIndices)
    Definition: prop_vbounds.c:510
    static int varGetLbIndex(SCIP_PROPDATA *propdata, SCIP_VAR *var)
    Definition: prop_vbounds.c:302
    static SCIP_RETCODE analyzeConflictUpperbound(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *infervar, SCIP_Real inferub, SCIP_VAR *vbdvar, SCIP_BOUNDTYPE boundtype, SCIP_Real coef, SCIP_Real constant, SCIP_Bool canwide)
    static SCIP_RETCODE addVbound(SCIP *scip, SCIP_PROPDATA *propdata, int startidx, int endidx, SCIP_Real coef, SCIP_Real constant)
    Definition: prop_vbounds.c:463
    #define indexGetBoundString(idx)
    Definition: prop_vbounds.c:172
    static int inferInfoGetPos(INFERINFO inferinfo)
    Definition: prop_vbounds.c:271
    static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_PROPDATA *propdata)
    Definition: prop_vbounds.c:413
    #define PROP_DELAY
    Definition: prop_vbounds.c:116
    static INFERINFO intToInferInfo(int i)
    Definition: prop_vbounds.c:238
    static SCIP_RETCODE applyFixingsAndAggregations(SCIP *scip, SCIP_VAR **vars, int *infeasnodes, int ninfeasnodes, SCIP_Shortbool *nodeinfeasible, int *sccvars, int *sccstarts, int nsccs, SCIP_Bool *infeasible, int *nfixedvars, int *naggrvars, SCIP_RESULT *result)
    #define getLbIndex(idx)
    Definition: prop_vbounds.c:165
    #define getBoundtypeString(type)
    Definition: prop_vbounds.c:171
    static SCIP_DECL_PROPEXITSOL(propExitsolVbounds)
    static SCIP_RETCODE tarjan(SCIP *scip, int startnode, int *startindex, SCIP_Shortbool *nodeonstack, int *nodeindex, int *nodelowlink, SCIP_Shortbool *nodeinfeasible, int *dfsstack, int *predstackidx, int *stacknextclique, int *stacknextcliquevar, int *topoorder, int *nordered, int *cliquefirstentry, int *cliquecurrentexit, int *sccvars, int *sccstarts, int *nsccs, int *infeasnodes, int *ninfeasnodes, SCIP_Bool *infeasible)
    static SCIP_BOUNDTYPE inferInfoGetBoundtype(INFERINFO inferinfo)
    Definition: prop_vbounds.c:260
    #define INITMEMSIZE
    Definition: prop_vbounds.c:459
    #define PROP_TIMING
    Definition: prop_vbounds.c:113
    static SCIP_DECL_PROPINITPRE(propInitpreVbounds)
    static void resetPropdata(SCIP_PROPDATA *propdata)
    Definition: prop_vbounds.c:336
    #define DEFAULT_USEIMPLICS
    Definition: prop_vbounds.c:140
    static int varGetUbIndex(SCIP_PROPDATA *propdata, SCIP_VAR *var)
    Definition: prop_vbounds.c:319
    static SCIP_DECL_PROPRESPROP(propRespropVbounds)
    static SCIP_RETCODE analyzeConflictLowerbound(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *infervar, SCIP_Real inferlb, SCIP_VAR *vbdvar, SCIP_BOUNDTYPE boundtype, SCIP_Real coef, SCIP_Real constant, SCIP_Bool canwide)
    #define getBoundtype(idx)
    Definition: prop_vbounds.c:168
    static SCIP_RETCODE tightenVarUb(SCIP *scip, SCIP_PROP *prop, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_Real newub, SCIP_Bool global, SCIP_VAR *vbdvar, SCIP_BOUNDTYPE boundtype, SCIP_Bool force, SCIP_Real coef, SCIP_Real constant, SCIP_Bool canwide, int *nchgbds, SCIP_RESULT *result)
    #define DEFAULT_MAXCLIQUESEXHAUSTIVE
    Definition: prop_vbounds.c:149
    #define DEFAULT_USEVBOUNDS
    Definition: prop_vbounds.c:142
    #define getVarIndex(idx)
    Definition: prop_vbounds.c:167
    #define DEFAULT_DETECTCYCLES
    Definition: prop_vbounds.c:145
    #define EVENTHDLR_DESC
    Definition: prop_vbounds.c:130
    static SCIP_DECL_PROPEXEC(propExecVbounds)
    static int inferInfoToInt(INFERINFO inferinfo)
    Definition: prop_vbounds.c:251
    #define EVENTHDLR_NAME
    Definition: prop_vbounds.c:129
    static SCIP_DECL_PROPCOPY(propCopyVbounds)
    static SCIP_RETCODE resolvePropagation(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx)
    #define PROP_FREQ
    Definition: prop_vbounds.c:115
    static SCIP_DECL_PROPPRESOL(propPresolVbounds)
    static SCIP_RETCODE tightenVarLb(SCIP *scip, SCIP_PROP *prop, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_Real newlb, SCIP_Bool global, SCIP_VAR *vbdvar, SCIP_BOUNDTYPE boundtype, SCIP_Bool force, SCIP_Real coef, SCIP_Real constant, SCIP_Bool canwide, int *nchgbds, SCIP_RESULT *result)
    #define PROP_PRIORITY
    Definition: prop_vbounds.c:114
    #define DEFAULT_DOTOPOSORT
    Definition: prop_vbounds.c:143
    #define PROP_PRESOL_PRIORITY
    Definition: prop_vbounds.c:118
    static SCIP_RETCODE initData(SCIP *scip, SCIP_PROP *prop, SCIP_Bool *infeasible)
    static INFERINFO getInferInfo(int pos, SCIP_BOUNDTYPE boundtype)
    Definition: prop_vbounds.c:280
    static SCIP_Real computeRelaxedUpperbound(SCIP *scip, SCIP_VAR *var, SCIP_Real inferub, SCIP_Real coef, SCIP_Real constant)
    #define DEFAULT_SORTCLIQUES
    Definition: prop_vbounds.c:144
    variable upper and lower bound propagator
    public methods for managing events
    public methods for implications, variable bounds, and cliques
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    public data structures and miscellaneous methods
    public methods for propagators
    public methods for problem variables
    public methods for conflict handler plugins and conflict analysis
    public methods for event handler plugins and event handlers
    general public methods
    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 propagator plugins
    public methods for the branch-and-bound tree
    public methods for SCIP variables
    @ SCIP_CONFTYPE_PROPAGATION
    Definition: type_conflict.h:62
    #define SCIP_EVENTTYPE_GUBCHANGED
    Definition: type_event.h:76
    struct SCIP_EventData SCIP_EVENTDATA
    Definition: type_event.h:179
    #define SCIP_EVENTTYPE_UBTIGHTENED
    Definition: type_event.h:79
    struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
    Definition: type_event.h:160
    #define SCIP_EVENTTYPE_FORMAT
    Definition: type_event.h:157
    #define SCIP_EVENTTYPE_GLBCHANGED
    Definition: type_event.h:75
    uint64_t SCIP_EVENTTYPE
    Definition: type_event.h:156
    #define SCIP_EVENTTYPE_LBTIGHTENED
    Definition: type_event.h:77
    @ SCIP_BOUNDTYPE_UPPER
    Definition: type_lp.h:58
    @ SCIP_BOUNDTYPE_LOWER
    Definition: type_lp.h:57
    enum SCIP_BoundType SCIP_BOUNDTYPE
    Definition: type_lp.h:60
    struct SCIP_PropData SCIP_PROPDATA
    Definition: type_prop.h:52
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_REDUCEDDOM
    Definition: type_result.h:51
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_SUCCESS
    Definition: type_result.h:58
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ 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_STAGE_PRESOLVING
    Definition: type_set.h:49
    @ SCIP_STAGE_SOLVING
    Definition: type_set.h:53
    #define SCIP_PRESOLTIMING_MEDIUM
    Definition: type_timing.h:53
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64