Scippy

    SCIP

    Solving Constraint Integer Programs

    cons_sos1.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file cons_sos1.c
    26 * @ingroup DEFPLUGINS_CONS
    27 * @brief constraint handler for SOS type 1 constraints
    28 * @author Tobias Fischer
    29 * @author Marc Pfetsch
    30 *
    31 * A specially ordered set of type 1 (SOS1) is a sequence of variables such that at most one
    32 * variable is nonzero. The special case of two variables arises, for instance, from equilibrium or
    33 * complementary conditions like \f$x \cdot y = 0\f$. Note that it is in principle allowed that a
    34 * variables appears twice, but it then can be fixed to 0.
    35 *
    36 * This implementation of this constraint handler is based on classical ideas, see e.g.@n
    37 * "Special Facilities in General Mathematical Programming System for
    38 * Non-Convex Problems Using Ordered Sets of Variables"@n
    39 * E. Beale and J. Tomlin, Proc. 5th IFORS Conference, 447-454 (1970)
    40 *
    41 *
    42 * The order of the variables is determined as follows:
    43 *
    44 * - If the constraint is created with SCIPcreateConsSOS1() and weights are given, the weights
    45 * determine the order (decreasing weights). Additional variables can be added with
    46 * SCIPaddVarSOS1(), which adds a variable with given weight.
    47 *
    48 * - If an empty constraint is created and then variables are added with SCIPaddVarSOS1(), weights
    49 * are needed and stored.
    50 *
    51 * - All other calls ignore the weights, i.e., if a nonempty constraint is created or variables are
    52 * added with SCIPappendVarSOS1().
    53 *
    54 * The validity of the SOS1 constraints can be enforced by different branching rules:
    55 *
    56 * - If classical SOS branching is used, branching is performed on only one SOS1 constraint.
    57 * Depending on the parameters, there are two ways to choose this branching constraint. Either
    58 * the constraint with the most number of nonzeros or the one with the largest nonzero-variable
    59 * weight. The later version allows the user to specify an order for the branching importance of
    60 * the constraints. Constraint branching can also be turned off.
    61 *
    62 * - Another way is to branch on the neighborhood of a single variable @p i, i.e., in one branch
    63 * \f$x_i\f$ is fixed to zero and in the other its neighbors from the conflict graph.
    64 *
    65 * - If bipartite branching is used, then we branch using complete bipartite subgraphs of the
    66 * conflict graph, i.e., in one branch fix the variables from the first bipartite partition and
    67 * the variables from the second bipartite partition in the other.
    68 *
    69 * - In addition to variable domain fixings, it is sometimes also possible to add new SOS1
    70 * constraints to the branching nodes. This results in a nonstatic conflict graph, which may
    71 * change dynamically with every branching node.
    72 *
    73 *
    74 * @todo Possibly allow to generate local cuts via strengthened local cuts (would need to modified coefficients of rows).
    75 *
    76 * @todo Check whether we can avoid turning off multi-aggregation (it is sometimes possible to fix a multi-aggregated
    77 * variable to 0 by fixing the aggregating variables to 0).
    78 */
    79
    80/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    81
    83#include "scip/cons_linear.h"
    84#include "scip/cons_setppc.h"
    85#include "scip/cons_sos1.h"
    86#include "scip/pub_cons.h"
    87#include "scip/pub_event.h"
    88#include "scip/pub_heur.h"
    89#include "scip/pub_lp.h"
    90#include "scip/pub_message.h"
    91#include "scip/pub_misc.h"
    92#include "scip/pub_misc_sort.h"
    93#include "scip/pub_tree.h"
    94#include "scip/pub_var.h"
    95#include "scip/scip_branch.h"
    96#include "scip/scip_conflict.h"
    97#include "scip/scip_cons.h"
    98#include "scip/scip_copy.h"
    99#include "scip/scip_cut.h"
    101#include "scip/scip_event.h"
    102#include "scip/scip_general.h"
    103#include "scip/scip_lp.h"
    104#include "scip/scip_mem.h"
    105#include "scip/scip_message.h"
    106#include "scip/scip_numerics.h"
    107#include "scip/scip_param.h"
    108#include "scip/scip_prob.h"
    109#include "scip/scip_probing.h"
    110#include "scip/scip_sol.h"
    112#include "scip/scip_tree.h"
    113#include "scip/scip_var.h"
    114#include "scip/symmetry_graph.h"
    116#include "tclique/tclique.h"
    117
    118
    119/* constraint handler properties */
    120#define CONSHDLR_NAME "SOS1"
    121#define CONSHDLR_DESC "SOS1 constraint handler"
    122#define CONSHDLR_SEPAPRIORITY 1000 /**< priority of the constraint handler for separation */
    123#define CONSHDLR_ENFOPRIORITY 100 /**< priority of the constraint handler for constraint enforcing */
    124#define CONSHDLR_CHECKPRIORITY -10 /**< priority of the constraint handler for checking feasibility */
    125#define CONSHDLR_SEPAFREQ 10 /**< frequency for separating cuts; zero means to separate only in the root node */
    126#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
    127#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
    128 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
    129#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
    130#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
    131#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
    132#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
    133#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
    134#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM
    135
    136/* adjacency matrix */
    137#define DEFAULT_MAXSOSADJACENCY 10000 /**< do not create an adjacency matrix if number of SOS1 variables is larger than predefined value
    138 * (-1: no limit) */
    139
    140/* presolving */
    141#define DEFAULT_MAXEXTENSIONS 1 /**< maximal number of extensions that will be computed for each SOS1 constraint */
    142#define DEFAULT_MAXTIGHTENBDS 5 /**< maximal number of bound tightening rounds per presolving round (-1: no limit) */
    143#define DEFAULT_PERFIMPLANALYSIS FALSE /**< if TRUE then perform implication graph analysis (might add additional SOS1 constraints) */
    144#define DEFAULT_DEPTHIMPLANALYSIS -1 /**< number of recursive calls of implication graph analysis (-1: no limit) */
    145
    146/* propagation */
    147#define DEFAULT_CONFLICTPROP TRUE /**< whether to use conflict graph propagation */
    148#define DEFAULT_IMPLPROP TRUE /**< whether to use implication graph propagation */
    149#define DEFAULT_SOSCONSPROP FALSE /**< whether to use SOS1 constraint propagation */
    150
    151/* branching rules */
    152#define DEFAULT_BRANCHSTRATEGIES "nbs" /**< possible branching strategies (see parameter DEFAULT_BRANCHINGRULE) */
    153#define DEFAULT_BRANCHINGRULE 'n' /**< which branching rule should be applied ? ('n': neighborhood, 'b': bipartite, 's': SOS1/clique)
    154 * (note: in some cases an automatic switching to SOS1 branching is possible) */
    155#define DEFAULT_AUTOSOS1BRANCH TRUE /**< if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap */
    156#define DEFAULT_FIXNONZERO FALSE /**< if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the
    157 * feasibility tolerance */
    158#define DEFAULT_ADDCOMPS FALSE /**< if TRUE then add complementarity constraints to the branching nodes (can be used in combination with
    159 * neighborhood or bipartite branching) */
    160#define DEFAULT_MAXADDCOMPS -1 /**< maximal number of complementarity constraints added per branching node (-1: no limit) */
    161#define DEFAULT_ADDCOMPSDEPTH 30 /**< only add complementarity constraints to branching nodes for predefined depth (-1: no limit) */
    162#define DEFAULT_ADDCOMPSFEAS -0.6 /**< minimal feasibility value for complementarity constraints in order to be added to the branching node */
    163#define DEFAULT_ADDBDSFEAS 1.0 /**< minimal feasibility value for bound inequalities in order to be added to the branching node */
    164#define DEFAULT_ADDEXTENDEDBDS TRUE /**< should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities */
    165
    166/* selection rules */
    167#define DEFAULT_NSTRONGROUNDS 0 /**< maximal number of strong branching rounds to perform for each node (-1: auto)
    168 * (only available for neighborhood and bipartite branching) */
    169#define DEFAULT_NSTRONGITER 10000 /**< maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit) */
    170
    171/* separation */
    172#define DEFAULT_BOUNDCUTSFROMSOS1 FALSE /**< if TRUE separate bound inequalities from SOS1 constraints */
    173#define DEFAULT_BOUNDCUTSFROMGRAPH TRUE /**< if TRUE separate bound inequalities from the conflict graph */
    174#define DEFAULT_AUTOCUTSFROMSOS1 TRUE /**< if TRUE then automatically switch to separating from SOS1 constraints if the SOS1 constraints do not overlap */
    175#define DEFAULT_BOUNDCUTSFREQ 10 /**< frequency for separating bound cuts; zero means to separate only in the root node */
    176#define DEFAULT_BOUNDCUTSDEPTH 40 /**< node depth of separating bound cuts (-1: no limit) */
    177#define DEFAULT_MAXBOUNDCUTS 50 /**< maximal number of bound cuts separated per branching node */
    178#define DEFAULT_MAXBOUNDCUTSROOT 150 /**< maximal number of bound cuts separated per iteration in the root node */
    179#define DEFAULT_STRTHENBOUNDCUTS TRUE /**< if TRUE then bound cuts are strengthened in case bound variables are available */
    180#define DEFAULT_IMPLCUTSFREQ 0 /**< frequency for separating implied bound cuts; zero means to separate only in the root node */
    181#define DEFAULT_IMPLCUTSDEPTH 40 /**< node depth of separating implied bound cuts (-1: no limit) */
    182#define DEFAULT_MAXIMPLCUTS 50 /**< maximal number of implied bound cuts separated per branching node */
    183#define DEFAULT_MAXIMPLCUTSROOT 150 /**< maximal number of implied bound cuts separated per iteration in the root node */
    184
    185/* event handler properties */
    186#define EVENTHDLR_NAME "SOS1"
    187#define EVENTHDLR_DESC "bound change event handler for SOS1 constraints"
    188
    189#define EVENTHDLR_EVENT_TYPE (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_GBDCHANGED)
    190
    191/* defines */
    192#define DIVINGCUTOFFVALUE 1e6
    193
    194
    195/** constraint data for SOS1 constraints */
    196struct SCIP_ConsData
    197{
    198 int nvars; /**< number of variables in the constraint */
    199 int maxvars; /**< maximal number of variables (= size of storage) */
    200 int nfixednonzeros; /**< number of variables fixed to be nonzero */
    201 SCIP_Bool local; /**< TRUE if constraint is only valid locally */
    202 SCIP_VAR** vars; /**< variables in constraint */
    203 SCIP_ROW* rowlb; /**< row corresponding to lower bounds, or NULL if not yet created */
    204 SCIP_ROW* rowub; /**< row corresponding to upper bounds, or NULL if not yet created */
    205 SCIP_Real* weights; /**< weights determining the order (ascending), or NULL if not used */
    206};
    207
    208
    209/** node data of a given node in the conflict graph */
    210struct SCIP_NodeData
    211{
    212 SCIP_VAR* var; /**< variable belonging to node */
    213 SCIP_VAR* lbboundvar; /**< bound variable @p z from constraint \f$x \geq \mu \cdot z\f$ (or NULL if not existent) */
    214 SCIP_VAR* ubboundvar; /**< bound variable @p z from constraint \f$x \leq \mu \cdot z\f$ (or NULL if not existent) */
    215 SCIP_Real lbboundcoef; /**< value \f$\mu\f$ from constraint \f$x \geq \mu z \f$ (0.0 if not existent) */
    216 SCIP_Real ubboundcoef; /**< value \f$\mu\f$ from constraint \f$x \leq \mu z \f$ (0.0 if not existent) */
    217 SCIP_Bool lbboundcomp; /**< TRUE if the nodes from the connected component of the conflict graph the given node belongs to
    218 * all have the same lower bound variable */
    219 SCIP_Bool ubboundcomp; /**< TRUE if the nodes from the connected component of the conflict graph the given node belongs to
    220 * all have the same lower bound variable */
    221};
    222typedef struct SCIP_NodeData SCIP_NODEDATA;
    223
    224
    225/** successor data of a given nodes successor in the implication graph */
    226struct SCIP_SuccData
    227{
    228 SCIP_Real lbimpl; /**< lower bound implication */
    229 SCIP_Real ubimpl; /**< upper bound implication */
    230};
    231typedef struct SCIP_SuccData SCIP_SUCCDATA;
    232
    233
    234/** tclique data for bound cut generation */
    236{
    237 SCIP* scip; /**< SCIP data structure */
    238 SCIP_CONSHDLR* conshdlr; /**< SOS1 constraint handler */
    239 SCIP_DIGRAPH* conflictgraph; /**< conflict graph */
    240 SCIP_SOL* sol; /**< LP solution to be separated (or NULL) */
    241 SCIP_Real scaleval; /**< factor for scaling weights */
    242 SCIP_Bool cutoff; /**< whether a cutoff occurred */
    243 int ncuts; /**< number of bound cuts found in this iteration */
    244 int nboundcuts; /**< number of bound cuts found so far */
    245 int maxboundcuts; /**< maximal number of clique cuts separated per separation round (-1: no limit) */
    246 SCIP_Bool strthenboundcuts; /**< if TRUE then bound cuts are strengthened in case bound variables are available */
    247};
    248
    249
    250/** SOS1 constraint handler data */
    251struct SCIP_ConshdlrData
    252{
    253 /* conflict graph */
    254 SCIP_DIGRAPH* conflictgraph; /**< conflict graph */
    255 SCIP_DIGRAPH* localconflicts; /**< local conflicts */
    256 SCIP_Bool isconflocal; /**< if TRUE then local conflicts are present and conflict graph has to be updated for each node */
    257 SCIP_HASHMAP* varhash; /**< hash map from variable to node in the conflict graph */
    258 int nsos1vars; /**< number of problem variables that are part of the SOS1 conflict graph */
    259 /* adjacency matrix */
    260 int maxsosadjacency; /**< do not create an adjacency matrix if number of SOS1 variables is larger than predefined
    261 * value (-1: no limit) */
    262 /* implication graph */
    263 SCIP_DIGRAPH* implgraph; /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
    264 int nimplnodes; /**< number of nodes in the implication graph */
    265 /* tclique graph */
    266 TCLIQUE_GRAPH* tcliquegraph; /**< tclique graph data structure */
    267 TCLIQUE_DATA* tcliquedata; /**< tclique data */
    268 /* event handler */
    269 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
    270 SCIP_VAR** fixnonzerovars; /**< stack of variables fixed to nonzero marked by event handler */
    271 int maxnfixnonzerovars; /**< size of stack fixnonzerovars */
    272 int nfixnonzerovars; /**< number of variables fixed to nonzero marked by event handler */
    273 /* presolving */
    274 int cntextsos1; /**< counts number of extended SOS1 constraints */
    275 int maxextensions; /**< maximal number of extensions that will be computed for each SOS1 constraint */
    276 int maxtightenbds; /**< maximal number of bound tightening rounds per presolving round (-1: no limit) */
    277 SCIP_Bool perfimplanalysis; /**< if TRUE then perform implication graph analysis (might add additional SOS1 constraints) */
    278 int depthimplanalysis; /**< number of recursive calls of implication graph analysis (-1: no limit) */
    279 /* propagation */
    280 SCIP_Bool conflictprop; /**< whether to use conflict graph propagation */
    281 SCIP_Bool implprop; /**< whether to use implication graph propagation */
    282 SCIP_Bool sosconsprop; /**< whether to use SOS1 constraint propagation */
    283 /* branching */
    284 char branchingrule; /**< which branching rule should be applied ? ('n': neighborhood, 'b': bipartite, 's': SOS1/clique)
    285 * (note: in some cases an automatic switching to SOS1 branching is possible) */
    286 SCIP_Bool autosos1branch; /**< if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap */
    287 SCIP_Bool fixnonzero; /**< if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the
    288 * feasibility tolerance */
    289 SCIP_Bool addcomps; /**< if TRUE then add complementarity constraints to the branching nodes additionally to domain fixings
    290 * (can be used in combination with neighborhood or bipartite branching) */
    291 int maxaddcomps; /**< maximal number of complementarity cons. and cor. bound ineq. added per branching node (-1: no limit) */
    292 int addcompsdepth; /**< only add complementarity constraints to branching nodes for predefined depth (-1: no limit) */
    293 SCIP_Real addcompsfeas; /**< minimal feasibility value for complementarity constraints in order to be added to the branching node */
    294 SCIP_Real addbdsfeas; /**< minimal feasibility value for bound inequalities in order to be added to the branching node */
    295 SCIP_Bool addextendedbds; /**< should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities */
    296 SCIP_Bool branchsos; /**< Branch on SOS condition in enforcing? This value can only be set to false if all SOS1 variables are binary */
    297 SCIP_Bool branchnonzeros; /**< Branch on SOS cons. with most number of nonzeros? */
    298 SCIP_Bool branchweight; /**< Branch on SOS cons. with highest nonzero-variable weight for branching - needs branchnonzeros to be false */
    299 SCIP_Bool switchsos1branch; /**< whether to switch to SOS1 branching */
    300 /* selection rules */
    301 int nstrongrounds; /**< maximal number of strong branching rounds to perform for each node (-1: auto)
    302 * (only available for neighborhood and bipartite branching) */
    303 int nstrongiter; /**< maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit) */
    304 /* separation */
    305 SCIP_Bool boundcutsfromsos1; /**< if TRUE separate bound inequalities from SOS1 constraints */
    306 SCIP_Bool boundcutsfromgraph; /**< if TRUE separate bound inequalities from the conflict graph */
    307 SCIP_Bool autocutsfromsos1; /**< if TRUE then automatically switch to separating SOS1 constraints if the SOS1 constraints do not overlap */
    308 SCIP_Bool switchcutsfromsos1; /**< whether to switch to separate bound inequalities from SOS1 constraints */
    309 int boundcutsfreq; /**< frequency for separating bound cuts; zero means to separate only in the root node */
    310 int boundcutsdepth; /**< node depth of separating bound cuts (-1: no limit) */
    311 int maxboundcuts; /**< maximal number of bound cuts separated per branching node */
    312 int maxboundcutsroot; /**< maximal number of bound cuts separated per iteration in the root node */
    313 int nboundcuts; /**< number of bound cuts found so far */
    314 SCIP_Bool strthenboundcuts; /**< if TRUE then bound cuts are strengthened in case bound variables are available */
    315 int implcutsfreq; /**< frequency for separating implied bound cuts; zero means to separate only in the root node */
    316 int implcutsdepth; /**< node depth of separating implied bound cuts (-1: no limit) */
    317 int maximplcuts; /**< maximal number of implied bound cuts separated per branching node */
    318 int maximplcutsroot; /**< maximal number of implied bound cuts separated per iteration in the root node */
    319};
    320
    321
    322
    323/*
    324 * local methods
    325 */
    326
    327/** returns whether two vertices are adjacent in the conflict graph */
    328static
    330 SCIP_Bool** adjacencymatrix, /**< adjacency matrix of conflict graph (lower half) (or NULL if an adjacencymatrix is not at hand) */
    331 SCIP_DIGRAPH* conflictgraph, /**< conflict graph (or NULL if an adjacencymatrix is at hand) */
    332 int vertex1, /**< first vertex */
    333 int vertex2 /**< second vertex */
    334 )
    335{
    336 assert( adjacencymatrix != NULL || conflictgraph != NULL );
    337
    338 /* we do not allow self-loops */
    339 if ( vertex1 == vertex2 )
    340 return FALSE;
    341
    342 /* for debugging */
    343 if ( adjacencymatrix == NULL )
    344 {
    345 int succvertex;
    346 int* succ;
    347 int nsucc1;
    348 int nsucc2;
    349 int j;
    350
    351 nsucc1 = SCIPdigraphGetNSuccessors(conflictgraph, vertex1);
    352 nsucc2 = SCIPdigraphGetNSuccessors(conflictgraph, vertex2);
    353
    354 if ( nsucc1 < 1 || nsucc2 < 1 )
    355 return FALSE;
    356
    357 if ( nsucc1 > nsucc2 )
    358 {
    359 SCIPswapInts(&vertex1, &vertex2);
    360 SCIPswapInts(&nsucc1, &nsucc2);
    361 }
    362
    363 succ = SCIPdigraphGetSuccessors(conflictgraph, vertex1);
    364 SCIPsortInt(succ, nsucc1);
    365
    366 for (j = 0; j < nsucc1; ++j)
    367 {
    368 succvertex = succ[j];
    369 if ( succvertex == vertex2 )
    370 return TRUE;
    371 else if ( succvertex > vertex2 )
    372 return FALSE;
    373 }
    374 }
    375 else
    376 {
    377 if ( vertex1 < vertex2 )
    378 return adjacencymatrix[vertex2][vertex1];
    379 else
    380 return adjacencymatrix[vertex1][vertex2];
    381 }
    382
    383 return FALSE;
    384}
    385
    386
    387/** checks whether a variable violates an SOS1 constraint w.r.t. sol together with at least one other variable */
    388static
    390 SCIP* scip, /**< SCIP data structure */
    391 SCIP_DIGRAPH* conflictgraph, /**< conflict graph (or NULL if an adjacencymatrix is at hand) */
    392 int node, /**< node of variable in the conflict graph */
    393 SCIP_SOL* sol /**< solution, or NULL to use current node's solution */
    394 )
    395{
    396 SCIP_Real solval;
    397 SCIP_VAR* var;
    398
    399 assert( scip != NULL );
    400 assert( conflictgraph != NULL );
    401 assert( node >= 0 );
    402
    403 var = SCIPnodeGetVarSOS1(conflictgraph, node);
    404 assert( var != NULL );
    405 solval = SCIPgetSolVal(scip, sol, var);
    406
    407 /* check whether variable is nonzero w.r.t. sol and the bounds have not been fixed to zero by propagation */
    409 {
    410 int* succ;
    411 int nsucc;
    412 int s;
    413
    414 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
    415 succ = SCIPdigraphGetSuccessors(conflictgraph, node);
    416
    417 /* check whether a neighbor variable is nonzero w.r.t. sol */
    418 for (s = 0; s < nsucc; ++s)
    419 {
    420 var = SCIPnodeGetVarSOS1(conflictgraph, succ[s]);
    421 assert( var != NULL );
    422 solval = SCIPgetSolVal(scip, sol, var);
    424 return TRUE;
    425 }
    426 }
    427
    428 return FALSE;
    429}
    430
    431
    432/** returns solution value of imaginary binary big-M variable of a given node from the conflict graph */
    433static
    435 SCIP* scip, /**< SCIP pointer */
    436 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    437 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    438 int node /**< node of the conflict graph */
    439 )
    440{
    442 SCIP_VAR* var;
    443 SCIP_Real val;
    444
    445 assert( scip != NULL );
    446 assert( conflictgraph != NULL );
    447 assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
    448
    449 var = SCIPnodeGetVarSOS1(conflictgraph, node);
    450 val = SCIPgetSolVal(scip, sol, var);
    451
    452 if ( SCIPisFeasNegative(scip, val) )
    453 {
    455 assert( SCIPisFeasNegative(scip, bound) );
    456
    457 if ( SCIPisInfinity(scip, -val) )
    458 return 1.0;
    459 else if ( SCIPisInfinity(scip, -bound) )
    460 return 0.0;
    461 else
    462 return (val/bound);
    463 }
    464 else if ( SCIPisFeasPositive(scip, val) )
    465 {
    467 assert( SCIPisFeasPositive(scip, bound) );
    468 assert( SCIPisFeasPositive(scip, val) );
    469
    470 if ( SCIPisInfinity(scip, val) )
    471 return 1.0;
    472 else if ( SCIPisInfinity(scip, bound) )
    473 return 0.0;
    474 else
    475 return (val/bound);
    476 }
    477 else
    478 return 0.0;
    479}
    480
    481
    482/** gets (variable) lower bound value of current LP relaxation solution for a given node from the conflict graph */
    483static
    485 SCIP* scip, /**< SCIP pointer */
    486 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    487 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    488 int node /**< node of the conflict graph */
    489 )
    490{
    492
    493 assert( scip != NULL );
    494 assert( conflictgraph != NULL );
    495 assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
    496
    497 /* get node data */
    498 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
    499 assert( nodedata != NULL );
    500
    501 /* if variable is not involved in a variable upper bound constraint */
    502 if ( nodedata->lbboundvar == NULL || ! nodedata->lbboundcomp )
    503 return SCIPvarGetLbLocal(nodedata->var);
    504
    505 return nodedata->lbboundcoef * SCIPgetSolVal(scip, sol, nodedata->lbboundvar);
    506}
    507
    508
    509/** gets (variable) upper bound value of current LP relaxation solution for a given node from the conflict graph */
    510static
    512 SCIP* scip, /**< SCIP pointer */
    513 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    514 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    515 int node /**< node of the conflict graph */
    516 )
    517{
    519
    520 assert( scip != NULL );
    521 assert( conflictgraph != NULL );
    522 assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
    523
    524 /* get node data */
    525 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
    526 assert( nodedata != NULL );
    527
    528 /* if variable is not involved in a variable upper bound constraint */
    529 if ( nodedata->ubboundvar == NULL || ! nodedata->ubboundcomp )
    530 return SCIPvarGetUbLocal(nodedata->var);
    531
    532 return nodedata->ubboundcoef * SCIPgetSolVal(scip, sol, nodedata->ubboundvar);
    533}
    534
    535
    536/** returns whether variable is part of the SOS1 conflict graph */
    537static
    539 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler */
    540 SCIP_VAR* var /**< variable */
    541 )
    542{
    543 assert( conshdlrdata != NULL );
    544 assert( var != NULL );
    545
    546 if ( conshdlrdata->varhash == NULL || ! SCIPhashmapExists(conshdlrdata->varhash, var) )
    547 return FALSE;
    548
    549 return TRUE;
    550}
    551
    552
    553/** returns node of variable in the conflict graph or -1 if variable is not part of the SOS1 conflict graph */
    554static
    556 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler */
    557 SCIP_VAR* var /**< variable */
    558 )
    559{
    560 assert( conshdlrdata != NULL );
    561 assert( var != NULL );
    562 assert( conshdlrdata->varhash != NULL );
    563
    564 if ( ! SCIPhashmapExists(conshdlrdata->varhash, var) )
    565 return -1;
    566
    567 return SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
    568}
    569
    570
    571/** fix variable in given node to 0 or add constraint if variable is multi-aggregated
    572 *
    573 * @todo Try to handle multi-aggregated variables as in fixVariableZero() below.
    574 */
    575static
    577 SCIP* scip, /**< SCIP pointer */
    578 SCIP_VAR* var, /**< variable to be fixed to 0*/
    579 SCIP_NODE* node, /**< node */
    580 SCIP_Bool* infeasible /**< if fixing is infeasible */
    581 )
    582{
    583 /* if variable cannot be nonzero */
    584 *infeasible = FALSE;
    586 {
    587 *infeasible = TRUE;
    588 return SCIP_OKAY;
    589 }
    590
    591 /* if variable is multi-aggregated */
    593 {
    594 SCIP_CONS* cons;
    595 SCIP_Real val;
    596
    597 val = 1.0;
    598
    600 {
    601 SCIPdebugMsg(scip, "creating constraint to force multi-aggregated variable <%s> to 0.\n", SCIPvarGetName(var));
    602 /* we have to insert a local constraint var = 0 */
    603 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, "branch", 1, &var, &val, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
    604 TRUE, FALSE, FALSE, FALSE, FALSE) );
    605 SCIP_CALL( SCIPaddConsNode(scip, node, cons, NULL) );
    606 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    607 }
    608 }
    609 else
    610 {
    612 SCIP_CALL( SCIPchgVarLbNode(scip, node, var, 0.0) );
    614 SCIP_CALL( SCIPchgVarUbNode(scip, node, var, 0.0) );
    615 }
    616
    617 return SCIP_OKAY;
    618}
    619
    620
    621/** try to fix variable to 0
    622 *
    623 * Try to treat fixing by special consideration of multiaggregated variables. For a multi-aggregation
    624 * \f[
    625 * x = \sum_{i=1}^n \alpha_i x_i + c,
    626 * \f]
    627 * we can express the fixing \f$x = 0\f$ by fixing all \f$x_i\f$ to 0 if \f$c = 0\f$ and the lower bounds of \f$x_i\f$
    628 * are nonnegative if \f$\alpha_i > 0\f$ or the upper bounds are nonpositive if \f$\alpha_i < 0\f$.
    629 */
    630static
    632 SCIP* scip, /**< SCIP pointer */
    633 SCIP_VAR* var, /**< variable to be fixed to 0*/
    634 SCIP_Bool* infeasible, /**< if fixing is infeasible */
    635 SCIP_Bool* tightened /**< if fixing was performed */
    636 )
    637{
    638 assert( scip != NULL );
    639 assert( var != NULL );
    640 assert( infeasible != NULL );
    641 assert( tightened != NULL );
    642
    643 *infeasible = FALSE;
    644 *tightened = FALSE;
    645
    647 {
    648 SCIP_Real aggrconst;
    649
    650 /* if constant is 0 */
    651 aggrconst = SCIPvarGetMultaggrConstant(var);
    652 if ( SCIPisZero(scip, aggrconst) )
    653 {
    654 SCIP_VAR** aggrvars;
    655 SCIP_Real* aggrvals;
    656 SCIP_Bool allnonnegative = TRUE;
    657 int naggrvars;
    658 int i;
    659
    661
    662 /* check whether all variables are "nonnegative" */
    663 naggrvars = SCIPvarGetMultaggrNVars(var);
    664 aggrvars = SCIPvarGetMultaggrVars(var);
    665 aggrvals = SCIPvarGetMultaggrScalars(var);
    666 for (i = 0; i < naggrvars; ++i)
    667 {
    668 if ( (SCIPisPositive(scip, aggrvals[i]) && SCIPisNegative(scip, SCIPvarGetLbLocal(aggrvars[i]))) ||
    669 (SCIPisNegative(scip, aggrvals[i]) && SCIPisPositive(scip, SCIPvarGetUbLocal(aggrvars[i]))) )
    670 {
    671 allnonnegative = FALSE;
    672 break;
    673 }
    674 }
    675
    676 if ( allnonnegative )
    677 {
    678 /* all variables are nonnegative -> fix variables */
    679 for (i = 0; i < naggrvars; ++i)
    680 {
    681 SCIP_Bool fixed;
    682 SCIP_CALL( SCIPfixVar(scip, aggrvars[i], 0.0, infeasible, &fixed) );
    683 if ( *infeasible )
    684 return SCIP_OKAY;
    685 *tightened = *tightened || fixed;
    686 }
    687 }
    688 }
    689 }
    690 else
    691 {
    692 SCIP_CALL( SCIPfixVar(scip, var, 0.0, infeasible, tightened) );
    693 }
    694
    695 return SCIP_OKAY;
    696}
    697
    698
    699/** fix variable in local node to 0, and return whether the operation was feasible
    700 *
    701 * @note We do not add a linear constraint if the variable is multi-aggregated as in
    702 * fixVariableZeroNode(), since this would be too time consuming.
    703 */
    704static
    706 SCIP* scip, /**< SCIP pointer */
    707 SCIP_VAR* var, /**< variable to be fixed to 0*/
    708 SCIP_CONS* cons, /**< constraint */
    709 int inferinfo, /**< info for reverse prop. */
    710 SCIP_Bool* infeasible, /**< if fixing is infeasible */
    711 SCIP_Bool* tightened, /**< if fixing was performed */
    712 SCIP_Bool* success /**< whether fixing was successful, i.e., variable is not multi-aggregated */
    713 )
    714{
    715 *infeasible = FALSE;
    716 *tightened = FALSE;
    717 *success = FALSE;
    718
    719 /* if variable cannot be nonzero */
    721 {
    722 *infeasible = TRUE;
    723 return SCIP_OKAY;
    724 }
    725
    726 /* directly fix variable if it is not multi-aggregated */
    728 {
    729 SCIP_Bool tighten;
    730
    731 /* fix lower bound */
    732 SCIP_CALL( SCIPinferVarLbCons(scip, var, 0.0, cons, inferinfo, FALSE, infeasible, &tighten) );
    733 *tightened = *tightened || tighten;
    734
    735 /* fix upper bound */
    736 SCIP_CALL( SCIPinferVarUbCons(scip, var, 0.0, cons, inferinfo, FALSE, infeasible, &tighten) );
    737 *tightened = *tightened || tighten;
    738
    739 *success = TRUE;
    740 }
    741
    742 return SCIP_OKAY;
    743}
    744
    745
    746/** add lock on variable */
    747static
    749 SCIP* scip, /**< SCIP data structure */
    750 SCIP_CONS* cons, /**< constraint */
    751 SCIP_VAR* var /**< variable */
    752 )
    753{
    754 assert( scip != NULL );
    755 assert( cons != NULL );
    756 assert( var != NULL );
    757
    758 /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */
    761
    762 return SCIP_OKAY;
    763}
    764
    765
    766/** remove lock on variable */
    767static
    769 SCIP* scip, /**< SCIP data structure */
    770 SCIP_CONS* cons, /**< constraint */
    771 SCIP_VAR* var /**< variable */
    772 )
    773{
    774 assert( scip != NULL );
    775 assert( cons != NULL );
    776 assert( var != NULL );
    777
    778 /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */
    781
    782 return SCIP_OKAY;
    783}
    784
    785
    786/** ensures that the vars and weights array can store at least num entries */
    787static
    789 SCIP* scip, /**< SCIP data structure */
    790 SCIP_CONSDATA* consdata, /**< constraint data */
    791 int num, /**< minimum number of entries to store */
    792 SCIP_Bool reserveWeights /**< whether the weights array is handled */
    793 )
    794{
    795 assert( consdata != NULL );
    796 assert( consdata->nvars <= consdata->maxvars );
    797
    798 if ( num > consdata->maxvars )
    799 {
    800 int newsize;
    801
    802 newsize = SCIPcalcMemGrowSize(scip, num);
    803 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->maxvars, newsize) );
    804 if ( reserveWeights )
    805 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->maxvars, newsize) );
    806 consdata->maxvars = newsize;
    807 }
    808 assert( num <= consdata->maxvars );
    809
    810 return SCIP_OKAY;
    811}
    812
    813
    814/** handle new variable */
    815static
    817 SCIP* scip, /**< SCIP data structure */
    818 SCIP_CONS* cons, /**< constraint */
    819 SCIP_CONSDATA* consdata, /**< constraint data */
    820 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    821 SCIP_VAR* var, /**< variable */
    822 SCIP_Bool transformed /**< whether original variable was transformed */
    823 )
    824{
    825 SCIP_DIGRAPH* conflictgraph;
    826 int node;
    827
    828 assert( scip != NULL );
    829 assert( cons != NULL );
    830 assert( consdata != NULL );
    831 assert( conshdlrdata != NULL );
    832 assert( var != NULL );
    833
    834 /* if we are in transformed problem, catch the variable's events */
    835 if ( transformed )
    836 {
    837 assert( conshdlrdata->eventhdlr != NULL );
    838
    839 /* catch bound change events of variable */
    840 SCIP_CALL( SCIPcatchVarEvent(scip, var, EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr,
    841 (SCIP_EVENTDATA*)cons, NULL) ); /*lint !e740*/
    842
    843 /* if the variable if fixed to nonzero */
    844 assert( consdata->nfixednonzeros >= 0 );
    846 ++consdata->nfixednonzeros;
    847 }
    848
    849 /* install the rounding locks for the new variable */
    850 SCIP_CALL( lockVariableSOS1(scip, cons, var) );
    851
    852 /* branching on multiaggregated variables does not seem to work well, so avoid it */
    854
    855 /* add the new coefficient to the upper bound LP row, if necessary */
    856 if ( consdata->rowub != NULL && ! SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) && ! SCIPisZero(scip, SCIPvarGetUbGlobal(var)) )
    857 {
    858 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rowub, var, 1.0/SCIPvarGetUbGlobal(var)) );
    859 }
    860
    861 /* add the new coefficient to the lower bound LP row, if necessary */
    862 if ( consdata->rowlb != NULL && ! SCIPisInfinity(scip, SCIPvarGetLbGlobal(var)) && ! SCIPisZero(scip, SCIPvarGetLbGlobal(var)) )
    863 {
    864 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rowlb, var, 1.0/SCIPvarGetLbGlobal(var)) );
    865 }
    866
    867 /* return if the conflict graph has not been created yet */
    868 conflictgraph = conshdlrdata->conflictgraph;
    869 if ( conflictgraph == NULL )
    870 return SCIP_OKAY;
    871
    872 /* get node of variable in the conflict graph (or -1) */
    873 node = varGetNodeSOS1(conshdlrdata, var);
    874 assert( node < conshdlrdata->nsos1vars );
    875
    876 /* if the variable is not already a node of the conflict graph */
    877 if ( node < 0 )
    878 {
    879 /* variable does not appear in the conflict graph: switch to SOS1 branching rule, which does not make use of a conflict graph
    880 * @todo: maybe recompute the conflict graph, implication graph and varhash instead */
    881 SCIPdebugMsg(scip, "Switched to SOS1 branching rule, since conflict graph could be infeasible.\n");
    882 conshdlrdata->switchsos1branch = TRUE;
    883 return SCIP_OKAY;
    884 }
    885
    886 /* if the constraint is local, then there is no need to act, since local constraints are handled by the local conflict graph in the
    887 * function enforceConflictgraph() */
    888 if ( ! consdata->local )
    889 {
    890 SCIP_VAR** vars;
    891 int nvars;
    892 int v;
    893
    894 vars = consdata->vars;
    895 nvars = consdata->nvars;
    896
    897 for (v = 0; v < nvars; ++v)
    898 {
    899 int nodev;
    900
    901 if ( var == vars[v] )
    902 continue;
    903
    904 /* get node of variable in the conflict graph (or -1) */
    905 nodev = varGetNodeSOS1(conshdlrdata, vars[v]);
    906 assert( nodev < conshdlrdata->nsos1vars );
    907
    908 /* if the variable is already a node of the conflict graph */
    909 if ( nodev >= 0 )
    910 {
    911 int nsucc;
    912 int nsuccv;
    913
    914 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
    915 nsuccv = SCIPdigraphGetNSuccessors(conflictgraph, nodev);
    916
    917 /* add arcs if not existent */
    918 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, nodev, node, NULL) );
    919 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, node, nodev, NULL) );
    920
    921 /* in case of new arcs: sort successors in ascending order */
    922 if ( nsucc < SCIPdigraphGetNSuccessors(conflictgraph, node) )
    923 {
    924 SCIPdebugMsg(scip, "Added new conflict graph arc from variable %s to variable %s.\n", SCIPvarGetName(var), SCIPvarGetName(vars[v]));
    925 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, node), SCIPdigraphGetNSuccessors(conflictgraph, node));
    926 }
    927
    928 if ( nsuccv < SCIPdigraphGetNSuccessors(conflictgraph, nodev) )
    929 {
    930 SCIPdebugMsg(scip, "Added new conflict graph arc from variable %s to variable %s.\n", SCIPvarGetName(vars[v]), SCIPvarGetName(var));
    931 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, nodev), SCIPdigraphGetNSuccessors(conflictgraph, nodev));
    932 }
    933 }
    934 else
    935 {
    936 /* variable does not appear in the conflict graph: switch to SOS1 branching rule, which does not make use of a conflict graph
    937 * @todo: maybe recompute the conflict graph, implication graph and varhash instead */
    938 SCIPdebugMsg(scip, "Switched to SOS1 branching rule, since conflict graph could be infeasible.\n");
    939 conshdlrdata->switchsos1branch = TRUE;
    940 return SCIP_OKAY;
    941 }
    942 }
    943 }
    944
    945 return SCIP_OKAY;
    946}
    947
    948
    949/** adds a variable to an SOS1 constraint, at position given by weight - ascending order */
    950static
    952 SCIP* scip, /**< SCIP data structure */
    953 SCIP_CONS* cons, /**< constraint */
    954 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    955 SCIP_VAR* var, /**< variable to add to the constraint */
    956 SCIP_Real weight /**< weight to determine position */
    957 )
    958{
    959 SCIP_CONSDATA* consdata;
    960 SCIP_Bool transformed;
    961 int pos;
    962 int j;
    963
    964 assert( var != NULL );
    965 assert( cons != NULL );
    966 assert( conshdlrdata != NULL );
    967
    968 consdata = SCIPconsGetData(cons);
    969 assert( consdata != NULL );
    970
    971 if ( consdata->weights == NULL && consdata->maxvars > 0 )
    972 {
    973 SCIPerrorMessage("cannot add variable to SOS1 constraint <%s> that does not contain weights.\n", SCIPconsGetName(cons));
    974 return SCIP_INVALIDCALL;
    975 }
    976
    977 /* are we in the transformed problem? */
    978 transformed = SCIPconsIsTransformed(cons);
    979
    980 /* always use transformed variables in transformed constraints */
    981 if ( transformed )
    982 {
    983 SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
    984 }
    985 assert( var != NULL );
    986 assert( transformed == SCIPvarIsTransformed(var) );
    987
    988 SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, TRUE) );
    989 assert( consdata->weights != NULL );
    990 assert( consdata->maxvars >= consdata->nvars+1 );
    991
    992 /* find variable position */
    993 for (pos = 0; pos < consdata->nvars; ++pos)
    994 {
    995 if ( consdata->weights[pos] > weight )
    996 break;
    997 }
    998 assert( 0 <= pos && pos <= consdata->nvars );
    999
    1000 /* move other variables, if necessary */
    1001 for (j = consdata->nvars; j > pos; --j)
    1002 {
    1003 consdata->vars[j] = consdata->vars[j-1];
    1004 consdata->weights[j] = consdata->weights[j-1];
    1005 }
    1006
    1007 /* insert variable */
    1008 consdata->vars[pos] = var;
    1009 consdata->weights[pos] = weight;
    1010 ++consdata->nvars;
    1011
    1012 /* handle the new variable */
    1013 SCIP_CALL( handleNewVariableSOS1(scip, cons, consdata, conshdlrdata, var, transformed) );
    1014
    1015 return SCIP_OKAY;
    1016}
    1017
    1018
    1019/** appends a variable to an SOS1 constraint */
    1020static
    1022 SCIP* scip, /**< SCIP data structure */
    1023 SCIP_CONS* cons, /**< constraint */
    1024 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    1025 SCIP_VAR* var /**< variable to add to the constraint */
    1026 )
    1027{
    1028 SCIP_CONSDATA* consdata;
    1029 SCIP_Bool transformed;
    1030
    1031 assert( var != NULL );
    1032 assert( cons != NULL );
    1033 assert( conshdlrdata != NULL );
    1034
    1035 consdata = SCIPconsGetData(cons);
    1036 assert( consdata != NULL );
    1037 assert( consdata->nvars >= 0 );
    1038
    1039 /* are we in the transformed problem? */
    1040 transformed = SCIPconsIsTransformed(cons);
    1041
    1042 /* always use transformed variables in transformed constraints */
    1043 if ( transformed )
    1044 {
    1045 SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
    1046 }
    1047 assert( var != NULL );
    1048 assert( transformed == SCIPvarIsTransformed(var) );
    1049
    1050 if ( consdata->weights != NULL )
    1051 {
    1052 SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, TRUE) );
    1053 }
    1054 else
    1055 {
    1056 SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, FALSE) );
    1057 }
    1058
    1059 /* insert variable */
    1060 consdata->vars[consdata->nvars] = var;
    1061 if ( consdata->weights != NULL )
    1062 {
    1063 if ( consdata->nvars > 0 )
    1064 consdata->weights[consdata->nvars] = consdata->weights[consdata->nvars-1] + 1.0;
    1065 else
    1066 consdata->weights[consdata->nvars] = 0.0;
    1067 }
    1068 ++consdata->nvars;
    1069
    1070 /* handle the new variable */
    1071 SCIP_CALL( handleNewVariableSOS1(scip, cons, consdata, conshdlrdata, var, transformed) );
    1072
    1073 return SCIP_OKAY;
    1074}
    1075
    1076
    1077/** deletes a variable of an SOS1 constraint */
    1078static
    1080 SCIP* scip, /**< SCIP data structure */
    1081 SCIP_CONS* cons, /**< constraint */
    1082 SCIP_CONSDATA* consdata, /**< constraint data */
    1083 SCIP_EVENTHDLR* eventhdlr, /**< corresponding event handler */
    1084 int pos /**< position of variable in array */
    1085 )
    1086{
    1087 int j;
    1088
    1089 assert( 0 <= pos && pos < consdata->nvars );
    1090
    1091 /* remove lock of variable */
    1092 SCIP_CALL( unlockVariableSOS1(scip, cons, consdata->vars[pos]) );
    1093
    1094 /* drop events on variable */
    1095 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos], EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, -1) ); /*lint !e740*/
    1096
    1097 /* delete variable - need to copy since order is important */
    1098 for (j = pos; j < consdata->nvars-1; ++j)
    1099 {
    1100 consdata->vars[j] = consdata->vars[j+1]; /*lint !e679*/
    1101 if ( consdata->weights != NULL )
    1102 consdata->weights[j] = consdata->weights[j+1]; /*lint !e679*/
    1103 }
    1104 --consdata->nvars;
    1105
    1106 return SCIP_OKAY;
    1107}
    1108
    1109
    1110/* ----------------------------- presolving --------------------------------------*/
    1111
    1112/** extends a given clique of the conflict graph
    1113 *
    1114 * Implementation of the Bron-Kerbosch Algorithm from the paper:
    1115 * Algorithm 457: Finding all Cliques of an Undirected Graph, Bron & Kerbosch, Commun. ACM, 1973
    1116 */
    1117static
    1119 SCIP* scip, /**< SCIP pointer */
    1120 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    1121 SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of the conflict graph (only lower half filled) */
    1122 SCIP_DIGRAPH* vertexcliquegraph, /**< graph that contains the information which cliques contain a given vertex
    1123 * vertices of variables = 0, ..., nsos1vars-1; vertices of cliques = nsos1vars, ..., nsos1vars+ncliques-1*/
    1124 int nsos1vars, /**< number of SOS1 variables */
    1125 int nconss, /**< number of SOS1 constraints */
    1126 SCIP_CONS* cons, /**< constraint to be extended */
    1127 SCIP_VAR** vars, /**< variables of extended clique */
    1128 SCIP_Real* weights, /**< weights of extended clique */
    1129 SCIP_Bool firstcall, /**< whether this is the first call of extension operator */
    1130 SCIP_Bool usebacktrack, /**< whether backtracking is needed for the computation */
    1131 int** cliques, /**< all cliques found so far */
    1132 int* ncliques, /**< number of clique found so far */
    1133 int* cliquesizes, /**< number of variables of current clique */
    1134 int* newclique, /**< clique we want to extended*/
    1135 int* workingset, /**< set of vertices that already served as extension and set of candidates that probably will lead to an extension */
    1136 int nworkingset, /**< length of array workingset */
    1137 int nexts, /**< number of vertices that already served as extension */
    1138 int pos, /**< position of potential candidate */
    1139 int* maxextensions, /**< maximal number of extensions */
    1140 int* naddconss, /**< number of added constraints */
    1141 SCIP_Bool* success /**< pointer to store if at least one new clique was found */
    1142 )
    1143{
    1144 int* workingsetnew = NULL;
    1145 int nextsnew;
    1146 int nworkingsetnew;
    1147 int mincands;
    1148 int btriter = 0; /* backtrack iterator */
    1149 int selvertex;
    1150 int selpos = -1;
    1151 int fixvertex = -1;
    1152 int i;
    1153 int j;
    1154
    1155 assert( scip != NULL );
    1156 assert( conshdlrdata != NULL );
    1157 assert( adjacencymatrix != NULL );
    1158 assert( vertexcliquegraph != NULL );
    1159 assert( cons != NULL );
    1160 assert( cliques != NULL );
    1161 assert( cliquesizes != NULL );
    1162 assert( newclique != NULL );
    1163 assert( workingset != NULL );
    1164 assert( maxextensions != NULL );
    1165 assert( naddconss != NULL );
    1166 assert( success != NULL );
    1167
    1168 if ( firstcall )
    1169 *success = FALSE;
    1170
    1171 mincands = nworkingset;
    1172 if ( mincands < 1 )
    1173 return SCIP_OKAY;
    1174
    1175 /* allocate buffer array */
    1176 SCIP_CALL( SCIPallocBufferArray(scip, &workingsetnew, nworkingset) );
    1177
    1178#ifdef SCIP_DEBUG
    1179 for (i = 0; i < nexts; ++i)
    1180 {
    1181 for (j = nexts; j < nworkingset; ++j)
    1182 {
    1183 assert( isConnectedSOS1(adjacencymatrix, NULL, workingset[i], workingset[j]) );
    1184 }
    1185 }
    1186#endif
    1187
    1188 /* determine candidate with minimum number of disconnections */
    1189 for (i = 0; i < nworkingset; ++i)
    1190 {
    1191 int vertex;
    1192 int cnt = 0;
    1193
    1194 vertex = workingset[i];
    1195
    1196 /* count disconnections */
    1197 for (j = nexts; j < nworkingset && cnt < mincands; ++j)
    1198 {
    1199 if ( vertex != workingset[j] && ! isConnectedSOS1(adjacencymatrix, NULL, vertex, workingset[j]) )
    1200 {
    1201 cnt++;
    1202
    1203 /* save position of potential candidate */
    1204 pos = j;
    1205 }
    1206 }
    1207
    1208 /* check whether a new minimum was found */
    1209 if ( cnt < mincands )
    1210 {
    1211 fixvertex = vertex;
    1212 mincands = cnt;
    1213 if ( i < nexts )
    1214 {
    1215 assert( pos >= 0 );
    1216 selpos = pos;
    1217 }
    1218 else
    1219 {
    1220 selpos = i;
    1221
    1222 /* preincrement */
    1223 btriter = 1;
    1224 }
    1225 }
    1226 }
    1227
    1228 /* If fixed point is initially chosen from candidates then number of disconnections will be preincreased by one. */
    1229
    1230 /* backtrackcycle */
    1231 for (btriter = mincands + btriter; btriter >= 1; --btriter)
    1232 {
    1233 assert( selpos >= 0);
    1234 assert( fixvertex >= 0);
    1235
    1236 /* interchange */
    1237 selvertex = workingset[selpos];
    1238 workingset[selpos] = workingset[nexts];
    1239 workingset[nexts] = selvertex;
    1240
    1241 /* create new workingset */
    1242 nextsnew = 0;
    1243 for (j = 0 ; j < nexts; ++j)
    1244 {
    1245 if ( isConnectedSOS1(adjacencymatrix, NULL, selvertex, workingset[j]) )
    1246 workingsetnew[nextsnew++] = workingset[j];
    1247 }
    1248 nworkingsetnew = nextsnew;
    1249 for (j = nexts + 1; j < nworkingset; ++j)
    1250 {
    1251 if ( isConnectedSOS1(adjacencymatrix, NULL, selvertex, workingset[j]) )
    1252 workingsetnew[nworkingsetnew++] = workingset[j];
    1253 }
    1254
    1255 newclique[cliquesizes[*ncliques]++] = selvertex;
    1256
    1257 /* if we found a new clique */
    1258 if ( nworkingsetnew == 0 )
    1259 {
    1260 char consname[SCIP_MAXSTRLEN];
    1261 SCIP_CONSDATA* consdata;
    1262 SCIP_CONS* newcons;
    1263 int cliqueind;
    1264
    1265 cliqueind = nsos1vars + *ncliques; /* index of clique in the vertex-clique graph */
    1266
    1267 /* save new clique */
    1268 assert( cliquesizes[*ncliques] >= 0 && cliquesizes[*ncliques] <= nsos1vars );
    1269 assert( *ncliques < MAX(1, conshdlrdata->maxextensions) * nconss );
    1270 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(cliques[*ncliques]), cliquesizes[*ncliques]) );/*lint !e866*/
    1271 for (j = 0 ; j < cliquesizes[*ncliques]; ++j)
    1272 {
    1273 vars[j] = SCIPnodeGetVarSOS1(conshdlrdata->conflictgraph, newclique[j]);
    1274 weights[j] = j+1;
    1275 cliques[*ncliques][j] = newclique[j];
    1276 }
    1277
    1278 SCIPsortInt(cliques[*ncliques], cliquesizes[*ncliques]);
    1279
    1280 /* create new constraint */
    1281 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "extsos1_%d", conshdlrdata->cntextsos1);
    1282
    1283 SCIP_CALL( SCIPcreateConsSOS1(scip, &newcons, consname, cliquesizes[*ncliques], vars, weights,
    1287 SCIPconsIsDynamic(cons),
    1289
    1290 consdata = SCIPconsGetData(newcons);
    1291
    1292 /* add directed edges to the vertex-clique graph */
    1293 for (j = 0; j < consdata->nvars; ++j)
    1294 {
    1295 /* add arc from clique vertex to clique (needed in presolRoundConssSOS1() to delete redundand cliques) */
    1296 SCIP_CALL( SCIPdigraphAddArcSafe(vertexcliquegraph, cliques[*ncliques][j], cliqueind, NULL) );
    1297 }
    1298
    1299 SCIP_CALL( SCIPaddCons(scip, newcons) );
    1300 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    1301
    1302 ++(*naddconss);
    1303 ++(conshdlrdata->cntextsos1);
    1304 ++(*ncliques);
    1305 cliquesizes[*ncliques] = cliquesizes[*ncliques-1]; /* cliquesizes[*ncliques] = size of newclique */
    1306
    1307 *success = TRUE;
    1308
    1309 --(*maxextensions);
    1310
    1311 if ( *maxextensions <= 0 )
    1312 {
    1313 SCIPfreeBufferArray(scip, &workingsetnew);
    1314 return SCIP_OKAY;
    1315 }
    1316 }
    1317 else if ( nextsnew < nworkingsetnew ) /* else if the number of of candidates equals zero */
    1318 {
    1319 /* if backtracking is used, it is necessary to keep the memory for 'workingsetnew' */
    1320 if ( usebacktrack )
    1321 {
    1322 SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, vars, weights, FALSE, usebacktrack,
    1323 cliques, ncliques, cliquesizes, newclique, workingsetnew, nworkingsetnew, nextsnew, pos, maxextensions, naddconss, success) );
    1324 if ( *maxextensions <= 0 )
    1325 {
    1326 SCIPfreeBufferArrayNull(scip, &workingsetnew);
    1327 return SCIP_OKAY;
    1328 }
    1329 }
    1330 else
    1331 {
    1332 int w;
    1333
    1334 assert( nworkingset >= nworkingsetnew );
    1335 for (w = 0; w < nworkingsetnew; ++w)
    1336 workingset[w] = workingsetnew[w];
    1337 nworkingset = nworkingsetnew;
    1338
    1339 SCIPfreeBufferArrayNull(scip, &workingsetnew);
    1340
    1341 SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, vars, weights, FALSE, usebacktrack,
    1342 cliques, ncliques, cliquesizes, newclique, workingset, nworkingset, nextsnew, pos, maxextensions, naddconss, success) );
    1343 assert( *maxextensions <= 0 );
    1344 return SCIP_OKAY;
    1345 }
    1346 }
    1347 assert( workingsetnew != NULL );
    1348 assert( workingset != NULL );
    1349
    1350 /* remove selvertex from clique */
    1351 --cliquesizes[*ncliques];
    1352
    1353 /* add selvertex to the set of vertices that already served as extension */
    1354 ++nexts;
    1355
    1356 if ( btriter > 1 )
    1357 {
    1358 /* select a candidate that is not connected to the fixed vertex */
    1359 for (j = nexts; j < nworkingset; ++j)
    1360 {
    1361 assert( fixvertex != workingset[j] );
    1362 if ( ! isConnectedSOS1(adjacencymatrix, NULL, fixvertex, workingset[j]) )
    1363 {
    1364 selpos = j;
    1365 break;
    1366 }
    1367 }
    1368 }
    1369 }
    1370
    1371 SCIPfreeBufferArrayNull(scip, &workingsetnew);
    1372
    1373 return SCIP_OKAY;
    1374}
    1375
    1376
    1377/** generates conflict graph that is induced by the variables of a linear constraint */
    1378static
    1380 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    1381 SCIP_DIGRAPH* conflictgraphlin, /**< conflict graph of linear constraint (nodes: 1, ..., nlinvars) */
    1382 SCIP_DIGRAPH* conflictgraphorig, /**< original conflict graph (nodes: 1, ..., nsos1vars) */
    1383 SCIP_VAR** linvars, /**< linear variables in linear constraint */
    1384 int nlinvars, /**< number of linear variables in linear constraint */
    1385 int* posinlinvars /**< posinlinvars[i] = position (index) of SOS1 variable i in linear constraint,
    1386 * posinlinvars[i]= -1 if @p i is not a SOS1 variable or not a variable of the linear constraint */
    1387 )
    1388{
    1389 int indexinsosvars;
    1390 int indexinlinvars;
    1391 int* succ;
    1392 int nsucc;
    1393 int v;
    1394 int s;
    1395
    1396 assert( conflictgraphlin != NULL );
    1397 assert( conflictgraphorig != NULL );
    1398 assert( linvars != NULL );
    1399 assert( posinlinvars != NULL );
    1400
    1401 for (v = 1; v < nlinvars; ++v) /* we start with v = 1, since "indexinlinvars < v" (see below) is never fulfilled for v = 0 */
    1402 {
    1403 indexinsosvars = varGetNodeSOS1(conshdlrdata, linvars[v]);
    1404
    1405 /* if linvars[v] is contained in at least one SOS1 constraint */
    1406 if ( indexinsosvars >= 0 )
    1407 {
    1408 succ = SCIPdigraphGetSuccessors(conflictgraphorig, indexinsosvars);
    1409 nsucc = SCIPdigraphGetNSuccessors(conflictgraphorig, indexinsosvars);
    1410
    1411 for (s = 0; s < nsucc; ++s)
    1412 {
    1413 assert( succ[s] >= 0 );
    1414 indexinlinvars = posinlinvars[succ[s]];
    1415 assert( indexinlinvars < nlinvars );
    1416
    1417 if ( indexinlinvars >= 0 && indexinlinvars < v )
    1418 {
    1419 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraphlin, v, indexinlinvars, NULL) );
    1420 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraphlin, indexinlinvars, v, NULL) );
    1421 }
    1422 }
    1423 }
    1424 }
    1425
    1426 return SCIP_OKAY;
    1427}
    1428
    1429
    1430/** determine the common successors of the vertices from the considered clique */
    1431static
    1433 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    1434 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    1435 int* clique, /**< current clique */
    1436 SCIP_VAR** vars, /**< clique variables */
    1437 int nvars, /**< number of clique variables */
    1438 int* comsucc, /**< pointer to store common successors of clique vertices (size = nvars) */
    1439 int* ncomsucc /**< pointer to store number common successors of clique vertices */
    1440 )
    1441{
    1442 int nsucc;
    1443 int* succ;
    1444 int ind;
    1445 int k = 0;
    1446 int v;
    1447 int i;
    1448 int j;
    1449
    1450 assert( conflictgraph != NULL );
    1451 assert( clique != NULL );
    1452 assert( vars != NULL );
    1453 assert( comsucc != NULL );
    1454 assert( ncomsucc != NULL );
    1455
    1456 *ncomsucc = 0;
    1457
    1458 /* determine the common successors of the vertices from the considered clique */
    1459
    1460 /* determine successors of variable var[0] that are not in the clique */
    1461 assert(vars[0] != NULL );
    1462 ind = varGetNodeSOS1(conshdlrdata, vars[0]);
    1463
    1464 if( ind == -1 )
    1465 return SCIP_INVALIDDATA;
    1466
    1467 assert( ind < SCIPdigraphGetNNodes(conflictgraph) );
    1468 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, ind);
    1469 succ = SCIPdigraphGetSuccessors(conflictgraph, ind);
    1470
    1471 for (j = 0; j < nvars; ++j)
    1472 {
    1473 for (i = k; i < nsucc; ++i)
    1474 {
    1475 if ( succ[i] > clique[j] )
    1476 {
    1477 k = i;
    1478 break;
    1479 }
    1480 else if ( succ[i] == clique[j] )
    1481 {
    1482 k = i + 1;
    1483 break;
    1484 }
    1485 else
    1486 comsucc[(*ncomsucc)++] = succ[i];
    1487 }
    1488 }
    1489
    1490 /* for all variables except the first one */
    1491 for (v = 1; v < nvars; ++v)
    1492 {
    1493 int ncomsuccsave = 0;
    1494 k = 0;
    1495
    1496 assert(vars[v] != NULL );
    1497 ind = varGetNodeSOS1(conshdlrdata, vars[v]);
    1498 assert( ind >= 0 && ind < SCIPdigraphGetNNodes(conflictgraph) );
    1499
    1500 if ( ind >= 0 )
    1501 {
    1502 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, ind);
    1503 succ = SCIPdigraphGetSuccessors(conflictgraph, ind);
    1504
    1505 /* determine successors that are in comsucc */
    1506 for (j = 0; j < *ncomsucc; ++j)
    1507 {
    1508 for (i = k; i < nsucc; ++i)
    1509 {
    1510 if ( succ[i] > comsucc[j] )
    1511 {
    1512 k = i;
    1513 break;
    1514 }
    1515 else if ( succ[i] == comsucc[j] )
    1516 {
    1517 comsucc[ncomsuccsave++] = succ[i];
    1518 k = i + 1;
    1519 break;
    1520 }
    1521 }
    1522 }
    1523 *ncomsucc = ncomsuccsave;
    1524 }
    1525 }
    1526
    1527 return SCIP_OKAY;
    1528}
    1529
    1530
    1531/** get nodes whose corresponding SOS1 variables are nonzero if an SOS1 variable of a given node is nonzero */
    1532static
    1534 SCIP* scip, /**< SCIP pointer */
    1535 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    1536 SCIP_VAR** vars, /**< problem and SOS1 variables */
    1537 SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
    1538 SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */
    1539 SCIP_Bool* implnodes, /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
    1540 int node /**< node of the implication graph */
    1541 )
    1542{
    1543 SCIP_SUCCDATA** succdatas;
    1544 int sos1node;
    1545 int* succ;
    1546 int nsucc;
    1547 int s;
    1548
    1549 assert( scip != NULL );
    1550 assert( implgraph != NULL );
    1551 assert( implnodes != NULL );
    1552 assert( node >= 0 );
    1553 assert( vars[node] != NULL );
    1554 assert( SCIPhashmapGetImageInt(implhash, vars[node]) == node );
    1555
    1556 /* get node of variable in the conflict graph (-1 if variable is no SOS1 variable) */
    1557 sos1node = varGetNodeSOS1(conshdlrdata, vars[node]);
    1558 if ( sos1node < 0 )
    1559 return SCIP_OKAY;
    1560
    1561 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, node);
    1562 nsucc = SCIPdigraphGetNSuccessors(implgraph, node);
    1563 succ = SCIPdigraphGetSuccessors(implgraph, node);
    1564
    1565 for (s = 0; s < nsucc; ++s)
    1566 {
    1567 SCIP_SUCCDATA* data;
    1568 int succnode;
    1569 succnode = succ[s];
    1570 data = succdatas[s];
    1571 sos1node = varGetNodeSOS1(conshdlrdata, vars[succnode]);
    1572
    1573 /* if node is SOS1 and the corresponding variable is implied to be nonzero */
    1574 assert( succdatas[s] != NULL );
    1575 if ( sos1node >= 0 && ! implnodes[sos1node] && ( SCIPisFeasPositive(scip, data->lbimpl) || SCIPisFeasNegative(scip, data->ubimpl) ) )
    1576 {
    1577 assert( sos1node == succnode );
    1578 implnodes[sos1node] = TRUE;
    1579 SCIP_CALL( getSOS1Implications(scip, conshdlrdata, vars, implgraph, implhash, implnodes, succnode) );
    1580 }
    1581 }
    1582
    1583 return SCIP_OKAY;
    1584}
    1585
    1586
    1587/** perform one presolving round for a single SOS1 constraint
    1588 *
    1589 * We perform the following presolving steps.
    1590 *
    1591 * - If the bounds of some variable force it to be nonzero, we can
    1592 * fix all other variables to zero and remove the SOS1 constraints
    1593 * that contain it.
    1594 * - If a variable is fixed to zero, we can remove the variable.
    1595 * - If a variable appears twice, it can be fixed to 0.
    1596 * - We substitute appregated variables.
    1597 */
    1598static
    1600 SCIP* scip, /**< SCIP pointer */
    1601 SCIP_CONS* cons, /**< constraint */
    1602 SCIP_CONSDATA* consdata, /**< constraint data */
    1603 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
    1604 SCIP_Bool* substituted, /**< whether a variable was substituted */
    1605 SCIP_Bool* cutoff, /**< whether a cutoff happened */
    1606 SCIP_Bool* success, /**< whether we performed a successful reduction */
    1607 int* ndelconss, /**< number of deleted constraints */
    1608 int* nupgdconss, /**< number of upgraded constraints */
    1609 int* nfixedvars, /**< number of fixed variables */
    1610 int* nremovedvars /**< number of variables removed */
    1611 )
    1612{
    1613 SCIP_VAR** vars;
    1614 SCIP_Bool allvarsbinary;
    1615 SCIP_Bool infeasible;
    1616 SCIP_Bool fixed;
    1617 int nfixednonzeros;
    1618 int lastFixedNonzero;
    1619 int j;
    1620
    1621 assert( scip != NULL );
    1622 assert( cons != NULL );
    1623 assert( consdata != NULL );
    1624 assert( eventhdlr != NULL );
    1625 assert( cutoff != NULL );
    1626 assert( success != NULL );
    1627 assert( ndelconss != NULL );
    1628 assert( nfixedvars != NULL );
    1629 assert( nremovedvars != NULL );
    1630
    1631 *substituted = FALSE;
    1632 *cutoff = FALSE;
    1633 *success = FALSE;
    1634
    1635 SCIPdebugMsg(scip, "Presolving SOS1 constraint <%s>.\n", SCIPconsGetName(cons) );
    1636
    1637 j = 0;
    1638 nfixednonzeros = 0;
    1639 lastFixedNonzero = -1;
    1640 allvarsbinary = TRUE;
    1641 vars = consdata->vars;
    1642
    1643 /* check for variables fixed to 0 and bounds that fix a variable to be nonzero */
    1644 while ( j < consdata->nvars )
    1645 {
    1646 int l;
    1647 SCIP_VAR* var;
    1648 SCIP_Real lb;
    1649 SCIP_Real ub;
    1650 SCIP_Real scalar;
    1651 SCIP_Real constant;
    1652
    1653 scalar = 1.0;
    1654 constant = 0.0;
    1655
    1656 /* check for aggregation: if the constant is zero the variable is zero iff the aggregated
    1657 * variable is 0 */
    1658 var = vars[j];
    1659 SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
    1660
    1661 /* if constant is zero and we get a different variable, substitute variable */
    1662 if ( SCIPisZero(scip, constant) && ! SCIPisZero(scip, scalar) && var != vars[j] )
    1663 {
    1664 SCIPdebugMsg(scip, "substituted variable <%s> by <%s>.\n", SCIPvarGetName(vars[j]), SCIPvarGetName(var));
    1665 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[j], EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, -1) ); /*lint !e740*/
    1666 SCIP_CALL( SCIPcatchVarEvent(scip, var, EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, NULL) ); /*lint !e740*/
    1667
    1668 /* change the rounding locks */
    1669 SCIP_CALL( unlockVariableSOS1(scip, cons, consdata->vars[j]) );
    1670 SCIP_CALL( lockVariableSOS1(scip, cons, var) );
    1671
    1672 vars[j] = var;
    1673 *substituted = TRUE;
    1674 }
    1675
    1676 /* check whether the variable appears again later */
    1677 for (l = j+1; l < consdata->nvars; ++l)
    1678 {
    1679 /* if variable appeared before, we can fix it to 0 and remove it */
    1680 if ( vars[j] == vars[l] )
    1681 {
    1682 SCIPdebugMsg(scip, "variable <%s> appears twice in constraint, fixing it to 0.\n", SCIPvarGetName(vars[j]));
    1683 SCIP_CALL( SCIPfixVar(scip, vars[j], 0.0, &infeasible, &fixed) );
    1684
    1685 if ( infeasible )
    1686 {
    1687 *cutoff = TRUE;
    1688 return SCIP_OKAY;
    1689 }
    1690 if ( fixed )
    1691 ++(*nfixedvars);
    1692 }
    1693 }
    1694
    1695 /* get bounds */
    1696 lb = SCIPvarGetLbLocal(vars[j]);
    1697 ub = SCIPvarGetUbLocal(vars[j]);
    1698
    1699 /* if the variable if fixed to nonzero */
    1701 {
    1702 ++nfixednonzeros;
    1703 lastFixedNonzero = j;
    1704 }
    1705
    1706 /* if the variable is fixed to 0 */
    1707 if ( SCIPisFeasZero(scip, lb) && SCIPisFeasZero(scip, ub) )
    1708 {
    1709 SCIPdebugMsg(scip, "deleting variable <%s> fixed to 0.\n", SCIPvarGetName(vars[j]));
    1710 SCIP_CALL( deleteVarSOS1(scip, cons, consdata, eventhdlr, j) );
    1711 ++(*nremovedvars);
    1712 }
    1713 else
    1714 {
    1715 /* check whether all variables are binary */
    1716 if ( ! SCIPvarIsBinary(vars[j]) )
    1717 allvarsbinary = FALSE;
    1718
    1719 ++j;
    1720 }
    1721 }
    1722
    1723 /* if the number of variables is less than 2 */
    1724 if ( consdata->nvars < 2 )
    1725 {
    1726 SCIPdebugMsg(scip, "Deleting SOS1 constraint <%s> with < 2 variables.\n", SCIPconsGetName(cons));
    1727
    1728 /* delete constraint */
    1729 assert( ! SCIPconsIsModifiable(cons) );
    1730 SCIP_CALL( SCIPdelCons(scip, cons) );
    1731 ++(*ndelconss);
    1732 *success = TRUE;
    1733 return SCIP_OKAY;
    1734 }
    1735
    1736 /* if more than one variable are fixed to be nonzero, we are infeasible */
    1737 if ( nfixednonzeros > 1 )
    1738 {
    1739 SCIPdebugMsg(scip, "The problem is infeasible: more than one variable has bounds that keep it from being 0.\n");
    1740 assert( lastFixedNonzero >= 0 );
    1741 *cutoff = TRUE;
    1742 return SCIP_OKAY;
    1743 }
    1744
    1745 /* if there is exactly one fixed nonzero variable */
    1746 if ( nfixednonzeros == 1 )
    1747 {
    1748 assert( lastFixedNonzero >= 0 );
    1749
    1750 /* fix all other variables to zero */
    1751 for (j = 0; j < consdata->nvars; ++j)
    1752 {
    1753 if ( j != lastFixedNonzero )
    1754 {
    1755 SCIP_CALL( fixVariableZero(scip, vars[j], &infeasible, &fixed) );
    1756 if ( infeasible )
    1757 {
    1758 *cutoff = TRUE;
    1759 return SCIP_OKAY;
    1760 }
    1761 if ( fixed )
    1762 ++(*nfixedvars);
    1763 }
    1764 }
    1765
    1766 SCIPdebugMsg(scip, "Deleting redundant SOS1 constraint <%s> with one variable.\n", SCIPconsGetName(cons));
    1767
    1768 /* delete original constraint */
    1769 assert( ! SCIPconsIsModifiable(cons) );
    1770 SCIP_CALL( SCIPdelCons(scip, cons) );
    1771 ++(*ndelconss);
    1772 *success = TRUE;
    1773 }
    1774 /* note: there is no need to update consdata->nfixednonzeros, since the constraint is deleted as soon nfixednonzeros > 0. */
    1775 else
    1776 {
    1777 /* if all variables are binary create a set packing constraint */
    1778 if ( allvarsbinary && SCIPfindConshdlr(scip, "setppc") != NULL )
    1779 {
    1780 SCIP_CONS* setpackcons;
    1781
    1782 /* create, add, and release the logicor constraint */
    1783 SCIP_CALL( SCIPcreateConsSetpack(scip, &setpackcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
    1787 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &setpackcons) );
    1788
    1789 SCIPdebugMsg(scip, "Upgrading SOS1 constraint <%s> to set packing constraint.\n", SCIPconsGetName(cons));
    1790
    1791 /* remove the SOS1 constraint globally */
    1792 assert( ! SCIPconsIsModifiable(cons) );
    1793 SCIP_CALL( SCIPdelCons(scip, cons) );
    1794 ++(*nupgdconss);
    1795 *success = TRUE;
    1796 }
    1797 }
    1798
    1799 return SCIP_OKAY;
    1800}
    1801
    1802
    1803
    1804/** perform one presolving round for all SOS1 constraints
    1805 *
    1806 * We perform the following presolving steps.
    1807 *
    1808 * - If the bounds of some variable force it to be nonzero, we can
    1809 * fix all other variables to zero and remove the SOS1 constraints
    1810 * that contain it.
    1811 * - If a variable is fixed to zero, we can remove the variable.
    1812 * - If a variable appears twice, it can be fixed to 0.
    1813 * - We substitute appregated variables.
    1814 * - Remove redundant SOS1 constraints
    1815 *
    1816 * If the adjacency matrix of the conflict graph is present, then
    1817 * we perform the following additional presolving steps
    1818 *
    1819 * - Search for larger SOS1 constraints in the conflict graph
    1820 *
    1821 * @todo Use one long array for storing cliques.
    1822 */
    1823static
    1825 SCIP* scip, /**< SCIP pointer */
    1826 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
    1827 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    1828 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    1829 SCIP_Bool** adjacencymatrix, /**< adjacency matrix of conflict graph (or NULL) */
    1830 SCIP_CONS** conss, /**< SOS1 constraints */
    1831 int nconss, /**< number of SOS1 constraints */
    1832 int nsos1vars, /**< number of SOS1 variables */
    1833 int* naddconss, /**< number of added constraints */
    1834 int* ndelconss, /**< number of deleted constraints */
    1835 int* nupgdconss, /**< number of upgraded constraints */
    1836 int* nfixedvars, /**< number of fixed variables */
    1837 int* nremovedvars, /**< number of variables removed */
    1838 SCIP_RESULT* result /**< result */
    1839 )
    1840{
    1841 SCIP_DIGRAPH* vertexcliquegraph;
    1842 SCIP_VAR** consvars;
    1843 SCIP_Real* consweights;
    1844 int** cliques = NULL;
    1845 int ncliques = 0;
    1846 int* cliquesizes = NULL;
    1847 int* newclique = NULL;
    1848 int* indconss = NULL;
    1849 int* lengthconss = NULL;
    1850 int* comsucc = NULL;
    1851 int csize;
    1852 int iter;
    1853 int c;
    1854
    1855 assert( scip != NULL );
    1856 assert( eventhdlr != NULL );
    1857 assert( conshdlrdata != NULL );
    1858 assert( conflictgraph != NULL );
    1859 assert( conss != NULL );
    1860 assert( naddconss != NULL );
    1861 assert( ndelconss != NULL );
    1862 assert( nupgdconss != NULL );
    1863 assert( nfixedvars != NULL );
    1864 assert( nremovedvars != NULL );
    1865 assert( result != NULL );
    1866
    1867 /* create digraph whose nodes represent variables and cliques in the conflict graph */
    1868 csize = MAX(1, conshdlrdata->maxextensions) * nconss;
    1869 SCIP_CALL( SCIPcreateDigraph(scip, &vertexcliquegraph, nsos1vars + csize) );
    1870
    1871 /* allocate buffer arrays */
    1872 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nsos1vars) );
    1873 SCIP_CALL( SCIPallocBufferArray(scip, &consweights, nsos1vars) );
    1874 SCIP_CALL( SCIPallocBufferArray(scip, &newclique, nsos1vars) );
    1875 SCIP_CALL( SCIPallocBufferArray(scip, &indconss, csize) );
    1876 SCIP_CALL( SCIPallocBufferArray(scip, &lengthconss, csize) );
    1877 SCIP_CALL( SCIPallocBufferArray(scip, &comsucc, MAX(nsos1vars, csize)) );
    1878
    1879 /* Use block memory for cliques, because sizes might be quite different and allocation interfers with workingset. */
    1880 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cliquesizes, csize) );
    1881 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cliques, csize) );
    1882
    1883 /* get constraint indices and sort them in descending order of their lengths */
    1884 for (c = 0; c < nconss; ++c)
    1885 {
    1886 SCIP_CONSDATA* consdata;
    1887
    1888 consdata = SCIPconsGetData(conss[c]);
    1889 assert( consdata != NULL );
    1890
    1891 indconss[c] = c;
    1892 lengthconss[c] = consdata->nvars;
    1893 }
    1894 SCIPsortDownIntInt(lengthconss, indconss, nconss);
    1895
    1896 /* check each constraint */
    1897 for (iter = 0; iter < nconss; ++iter)
    1898 {
    1899 SCIP_CONSDATA* consdata;
    1900 SCIP_CONS* cons;
    1901 SCIP_Bool substituted;
    1902 SCIP_Bool success;
    1903 SCIP_Bool cutoff;
    1904 int savennupgdconss;
    1905 int savendelconss;
    1906
    1907 SCIP_VAR** vars;
    1908 int nvars;
    1909
    1910 c = indconss[iter];
    1911
    1912 assert( conss != NULL );
    1913 assert( conss[c] != NULL );
    1914 cons = conss[c];
    1915 consdata = SCIPconsGetData(cons);
    1916
    1917 assert( consdata != NULL );
    1918 assert( consdata->nvars >= 0 );
    1919 assert( consdata->nvars <= consdata->maxvars );
    1920 assert( ! SCIPconsIsModifiable(cons) );
    1921 assert( ncliques < csize );
    1922
    1923 savendelconss = *ndelconss;
    1924 savennupgdconss = *nupgdconss;
    1925
    1926 /* perform one presolving round for SOS1 constraint */
    1927 SCIP_CALL( presolRoundConsSOS1(scip, cons, consdata, eventhdlr, &substituted, &cutoff, &success, ndelconss, nupgdconss, nfixedvars, nremovedvars) );
    1928
    1929 if ( cutoff )
    1930 {
    1931 *result = SCIP_CUTOFF;
    1932 break;
    1933 }
    1934
    1935 if ( *ndelconss > savendelconss || *nupgdconss > savennupgdconss || substituted )
    1936 {
    1937 *result = SCIP_SUCCESS;
    1938 continue;
    1939 }
    1940
    1941 if ( success )
    1942 *result = SCIP_SUCCESS;
    1943
    1944 /* get number of variables of constraint */
    1945 nvars = consdata->nvars;
    1946
    1947 /* get variables of constraint */
    1948 vars = consdata->vars;
    1949
    1950 if ( nvars > 1 && conshdlrdata->maxextensions != 0 )
    1951 {
    1952 SCIP_Bool extended = FALSE;
    1953 int cliquesize = 0;
    1954 int ncomsucc = 0;
    1955 int varprobind;
    1956 int j;
    1957
    1958 /* get clique and size of clique */
    1959 for (j = 0; j < nvars; ++j)
    1960 {
    1961 varprobind = varGetNodeSOS1(conshdlrdata, vars[j]);
    1962
    1963 if ( varprobind >= 0 )
    1964 newclique[cliquesize++] = varprobind;
    1965 }
    1966
    1967 if ( cliquesize > 1 )
    1968 {
    1969 cliquesizes[ncliques] = cliquesize;
    1970
    1971 /* sort clique vertices */
    1972 SCIPsortInt(newclique, cliquesizes[ncliques]);
    1973
    1974 /* check if clique is contained in an already known clique */
    1975 if ( ncliques > 0 )
    1976 {
    1977 int* succ;
    1978 int nsucc;
    1979 int v;
    1980
    1981 varprobind = newclique[0];
    1982 ncomsucc = SCIPdigraphGetNSuccessors(vertexcliquegraph, varprobind);
    1983 succ = SCIPdigraphGetSuccessors(vertexcliquegraph, varprobind);
    1984
    1985 /* get all (already processed) cliques that contain 'varpropind' */
    1986 for (j = 0; j < ncomsucc; ++j)
    1987 {
    1988 /* successors should have been sorted in a former step of the algorithm */
    1989 assert( j == 0 || succ[j] > succ[j-1] );
    1990 comsucc[j] = succ[j];
    1991 }
    1992
    1993 /* loop through remaining nodes of clique (case v = 0 already processed) */
    1994 for (v = 1; v < cliquesize && ncomsucc > 0; ++v)
    1995 {
    1996 varprobind = newclique[v];
    1997
    1998 /* get all (already processed) cliques that contain 'varpropind' */
    1999 nsucc = SCIPdigraphGetNSuccessors(vertexcliquegraph, varprobind);
    2000 succ = SCIPdigraphGetSuccessors(vertexcliquegraph, varprobind);
    2001 assert( succ != NULL || nsucc == 0 );
    2002
    2003 if ( nsucc < 1 )
    2004 {
    2005 ncomsucc = 0;
    2006 break;
    2007 }
    2008
    2009 /* get intersection with comsucc */
    2010 SCIPcomputeArraysIntersectionInt(comsucc, ncomsucc, succ, nsucc, comsucc, &ncomsucc);
    2011 }
    2012 }
    2013
    2014 /* if constraint is redundand then delete it */
    2015 if ( ncomsucc > 0 )
    2016 {
    2017 assert( ! SCIPconsIsModifiable(cons) );
    2018 SCIP_CALL( SCIPdelCons(scip, cons) );
    2019 ++(*ndelconss);
    2020 *result = SCIP_SUCCESS;
    2021 continue;
    2022 }
    2023
    2024 if ( conshdlrdata->maxextensions != 0 && adjacencymatrix != NULL )
    2025 {
    2026 int maxextensions;
    2027 ncomsucc = 0;
    2028
    2029 /* determine the common successors of the vertices from the considered clique */
    2030 SCIP_CALL( cliqueGetCommonSuccessorsSOS1(conshdlrdata, conflictgraph, newclique, vars, nvars, comsucc, &ncomsucc) );
    2031
    2032 /* find extensions for the clique */
    2033 maxextensions = conshdlrdata->maxextensions;
    2034 extended = FALSE;
    2035 SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, consvars, consweights,
    2036 TRUE, (maxextensions <= 1) ? FALSE : TRUE, cliques, &ncliques, cliquesizes, newclique, comsucc, ncomsucc, 0, -1, &maxextensions,
    2037 naddconss, &extended) );
    2038 }
    2039
    2040 /* if an extension was found for the current clique then free the old SOS1 constraint */
    2041 if ( extended )
    2042 {
    2043 assert( ! SCIPconsIsModifiable(cons) );
    2044 SCIP_CALL( SCIPdelCons(scip, cons) );
    2045 ++(*ndelconss);
    2046 *result = SCIP_SUCCESS;
    2047 }
    2048 else /* if we keep the constraint */
    2049 {
    2050 int cliqueind;
    2051
    2052 cliqueind = nsos1vars + ncliques; /* index of clique in vertex-clique graph */
    2053
    2054 /* add directed edges to the vertex-clique graph */
    2055 assert( cliquesize >= 0 && cliquesize <= nsos1vars );
    2056 assert( ncliques < csize );
    2057 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cliques[ncliques], cliquesize) );/*lint !e866*/
    2058 for (j = 0; j < cliquesize; ++j)
    2059 {
    2060 cliques[ncliques][j] = newclique[j];
    2061 SCIP_CALL( SCIPdigraphAddArcSafe(vertexcliquegraph, cliques[ncliques][j], cliqueind, NULL) );
    2062 }
    2063
    2064 /* update number of maximal cliques */
    2065 ++ncliques;
    2066 }
    2067 }
    2068 }
    2069 }
    2070
    2071 /* free buffer arrays */
    2072 for (c = ncliques-1; c >= 0; --c)
    2073 SCIPfreeBlockMemoryArray(scip, &cliques[c], cliquesizes[c]);
    2074 SCIPfreeBlockMemoryArrayNull(scip, &cliques, csize);
    2075 SCIPfreeBlockMemoryArrayNull(scip, &cliquesizes, csize);
    2076
    2077 SCIPfreeBufferArrayNull(scip, &comsucc);
    2078 SCIPfreeBufferArrayNull(scip, &lengthconss);
    2079 SCIPfreeBufferArrayNull(scip, &indconss);
    2080 SCIPfreeBufferArrayNull(scip, &newclique);
    2081 SCIPfreeBufferArrayNull(scip, &consweights);
    2082 SCIPfreeBufferArrayNull(scip, &consvars);
    2083 SCIPdigraphFree(&vertexcliquegraph);
    2084
    2085 return SCIP_OKAY;
    2086}
    2087
    2088
    2089/** performs implication graph analysis
    2090 *
    2091 * Tentatively fixes a variable to nonzeero and extracts consequences from it:
    2092 * - adds (possibly new) complementarity constraints to the problem if variables are implied to be zero
    2093 * - returns that the subproblem is infeasible if the domain of a variable turns out to be empty
    2094 */
    2095static
    2097 SCIP* scip, /**< SCIP pointer */
    2098 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    2099 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    2100 SCIP_VAR** totalvars, /**< problem and SOS1 variables */
    2101 SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
    2102 SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */
    2103 SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of the conflict graph (only lower half filled) */
    2104 int givennode, /**< node of the conflict graph */
    2105 int nonznode, /**< node of the conflict graph that is implied to be nonzero if given node is nonzero */
    2106 SCIP_Real* impllbs, /**< current lower variable bounds if given node is nonzero (update possible) */
    2107 SCIP_Real* implubs, /**< current upper variable bounds if given node is nonzero (update possible) */
    2108 SCIP_Bool* implnodes, /**< indicates which variables are currently implied to be nonzero if given node is nonzero (update possible) */
    2109 int* naddconss, /**< pointer to store number of added SOS1 constraints */
    2110 int* probingdepth, /**< pointer to store current probing depth */
    2111 SCIP_Bool* infeasible /**< pointer to store whether the subproblem gets infeasible if variable to 'nonznode' is nonzero */
    2112 )
    2113{
    2114 SCIP_SUCCDATA** succdatas;
    2115 int succnode;
    2116 int* succ;
    2117 int nsucc;
    2118 int s;
    2119
    2120 assert( nonznode >= 0 && nonznode < SCIPdigraphGetNNodes(conflictgraph) );
    2121
    2122 /* check probing depth */
    2123 if ( conshdlrdata->depthimplanalysis >= 0 && *probingdepth >= conshdlrdata->depthimplanalysis )
    2124 return SCIP_OKAY;
    2125 ++(*probingdepth);
    2126
    2127 /* get successors of 'nonznode' in the conflict graph */
    2128 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, nonznode);
    2129 succ = SCIPdigraphGetSuccessors(conflictgraph, nonznode);
    2130
    2131 /* loop through neighbors of 'nonznode' in the conflict graph; these variables are implied to be zero */
    2132 for (s = 0; s < nsucc; ++s)
    2133 {
    2134 succnode = succ[s];
    2135
    2136 /* if the current variable domain of the successor node does not contain the value zero then return that the problem is infeasible
    2137 * else if 'succnode' is not already complementary to 'givennode' then add a new complementarity constraint */
    2138 if ( givennode == succnode || SCIPisFeasPositive(scip, impllbs[succnode]) || SCIPisFeasNegative(scip, implubs[succnode]) )
    2139 {
    2140 *infeasible = TRUE;
    2141 return SCIP_OKAY;
    2142 }
    2143 else if ( ! isConnectedSOS1(adjacencymatrix, NULL, givennode, succnode) )
    2144 {
    2145 char namesos[SCIP_MAXSTRLEN];
    2146 SCIP_CONS* soscons = NULL;
    2147 SCIP_VAR* var1;
    2148 SCIP_VAR* var2;
    2149
    2150 /* update implied bounds of succnode */
    2151 impllbs[succnode] = 0;
    2152 implubs[succnode] = 0;
    2153
    2154 /* add arcs to the conflict graph */
    2155 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, givennode, succnode, NULL) );
    2156 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, succnode, givennode, NULL) );
    2157
    2158 /* resort successors */
    2159 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, givennode), SCIPdigraphGetNSuccessors(conflictgraph, givennode));
    2160 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, succnode), SCIPdigraphGetNSuccessors(conflictgraph, succnode));
    2161
    2162 /* update adjacencymatrix */
    2163 if ( givennode > succnode )
    2164 adjacencymatrix[givennode][succnode] = 1;
    2165 else
    2166 adjacencymatrix[succnode][givennode] = 1;
    2167
    2168 var1 = SCIPnodeGetVarSOS1(conflictgraph, givennode);
    2169 var2 = SCIPnodeGetVarSOS1(conflictgraph, succnode);
    2170
    2171 /* create SOS1 constraint */
    2172 assert( SCIPgetDepth(scip) == 0 );
    2173 (void) SCIPsnprintf(namesos, SCIP_MAXSTRLEN, "presolved_sos1_%s_%s", SCIPvarGetName(var1), SCIPvarGetName(var2) );
    2174 SCIP_CALL( SCIPcreateConsSOS1(scip, &soscons, namesos, 0, NULL, NULL, TRUE, TRUE, TRUE, FALSE, TRUE,
    2175 FALSE, FALSE, FALSE, FALSE) );
    2176
    2177 /* add variables to SOS1 constraint */
    2178 SCIP_CALL( addVarSOS1(scip, soscons, conshdlrdata, var1, 1.0) );
    2179 SCIP_CALL( addVarSOS1(scip, soscons, conshdlrdata, var2, 2.0) );
    2180
    2181 /* add constraint */
    2182 SCIP_CALL( SCIPaddCons(scip, soscons) );
    2183
    2184 /* release constraint */
    2185 SCIP_CALL( SCIPreleaseCons(scip, &soscons) );
    2186
    2187 ++(*naddconss);
    2188 }
    2189 }
    2190
    2191 /* by construction: nodes of SOS1 variables are equal for conflict graph and implication graph */
    2192 assert( nonznode == SCIPhashmapGetImageInt(implhash, SCIPnodeGetVarSOS1(conflictgraph, nonznode)) );
    2193 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, nonznode);
    2194 nsucc = SCIPdigraphGetNSuccessors(implgraph, nonznode);
    2195 succ = SCIPdigraphGetSuccessors(implgraph, nonznode);
    2196
    2197 /* go further in implication graph */
    2198 for (s = 0; s < nsucc; ++s)
    2199 {
    2200 SCIP_SUCCDATA* data;
    2201 int oldprobingdepth;
    2202
    2203 succnode = succ[s];
    2204 data = succdatas[s];
    2205 oldprobingdepth = *probingdepth;
    2206
    2207 /* if current lower bound is smaller than implied lower bound */
    2208 if ( SCIPisFeasLT(scip, impllbs[succnode], data->lbimpl) )
    2209 {
    2210 impllbs[succnode] = data->lbimpl;
    2211
    2212 /* if node is SOS1 and implied to be nonzero for the first time, then this recursively may imply further bound changes */
    2213 if ( varGetNodeSOS1(conshdlrdata, totalvars[succnode]) >= 0 && ! implnodes[succnode] && SCIPisFeasPositive(scip, data->lbimpl) )
    2214 {
    2215 /* by construction: nodes of SOS1 variables are equal for conflict graph and implication graph */
    2216 assert( succnode == SCIPhashmapGetImageInt(implhash, SCIPnodeGetVarSOS1(conflictgraph, succnode)) );
    2217 implnodes[succnode] = TRUE; /* in order to avoid cycling */
    2218 SCIP_CALL( performImplicationGraphAnalysis(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, adjacencymatrix, givennode, succnode, impllbs, implubs, implnodes, naddconss, probingdepth, infeasible) );
    2219 *probingdepth = oldprobingdepth;
    2220
    2221 /* return if the subproblem is known to be infeasible */
    2222 if ( *infeasible )
    2223 return SCIP_OKAY;
    2224 }
    2225 }
    2226
    2227 /* if current upper bound is larger than implied upper bound */
    2228 if ( SCIPisFeasGT(scip, implubs[succnode], data->ubimpl) )
    2229 {
    2230 implubs[succnode] = data->ubimpl;
    2231
    2232 /* if node is SOS1 and implied to be nonzero for the first time, then this recursively may imply further bound changes */
    2233 if ( varGetNodeSOS1(conshdlrdata, totalvars[succnode]) >= 0 && ! implnodes[succnode] && SCIPisFeasNegative(scip, data->ubimpl) )
    2234 {
    2235 /* by construction: nodes of SOS1 variables are equal for conflict graph and implication graph */
    2236 assert( succnode == SCIPhashmapGetImageInt(implhash, SCIPnodeGetVarSOS1(conflictgraph, succnode)) );
    2237 implnodes[succnode] = TRUE; /* in order to avoid cycling */
    2238 SCIP_CALL( performImplicationGraphAnalysis(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, adjacencymatrix, givennode, succnode, impllbs, implubs, implnodes, naddconss, probingdepth, infeasible) );
    2239 *probingdepth = oldprobingdepth;
    2240
    2241 /* return if the subproblem is known to be infeasible */
    2242 if ( *infeasible )
    2243 return SCIP_OKAY;
    2244 }
    2245 }
    2246 }
    2247
    2248 return SCIP_OKAY;
    2249}
    2250
    2251
    2252/** returns whether node is implied to be zero; this information is taken from the input array 'implnodes' */
    2253static
    2255 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    2256 SCIP_Bool* implnodes, /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
    2257 int node /**< node of the conflict graph (or -1) */
    2258 )
    2259{
    2260 int* succ;
    2261 int nsucc;
    2262 int s;
    2263
    2264 if ( node < 0 )
    2265 return FALSE;
    2266
    2267 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
    2268 succ = SCIPdigraphGetSuccessors(conflictgraph, node);
    2269
    2270 /* check whether any successor is implied to be nonzero */
    2271 for (s = 0; s < nsucc; ++s)
    2272 {
    2273 if ( implnodes[succ[s]] )
    2274 return TRUE;
    2275 }
    2276
    2277 return FALSE;
    2278}
    2279
    2280
    2281/** updates arc data of implication graph */
    2282static
    2284 SCIP* scip, /**< SCIP pointer */
    2285 SCIP_DIGRAPH* implgraph, /**< implication graph */
    2286 SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */
    2287 SCIP_VAR** totalvars, /**< problem and SOS1 variables */
    2288 SCIP_VAR* varv, /**< variable that is assumed to be nonzero */
    2289 SCIP_VAR* varw, /**< implication variable */
    2290 SCIP_Real lb, /**< old lower bound of \f$x_w\f$ */
    2291 SCIP_Real ub, /**< old upper bound of \f$x_w\f$ */
    2292 SCIP_Real newbound, /**< new bound of \f$x_w\f$ */
    2293 SCIP_Bool lower, /**< whether to consider lower bound implication (otherwise upper bound) */
    2294 int* nchgbds, /**< pointer to store number of changed bounds */
    2295 SCIP_Bool* update, /**< pointer to store whether implication graph has been updated */
    2296 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility has been detected */
    2297 )
    2298{
    2299 SCIP_SUCCDATA** succdatas;
    2300 SCIP_SUCCDATA* data = NULL;
    2301 int nsucc;
    2302 int* succ;
    2303 int indv;
    2304 int indw;
    2305 int s;
    2306
    2307 assert( scip != NULL );
    2308 assert( implgraph != NULL );
    2309 assert( implhash != NULL );
    2310 assert( totalvars != NULL );
    2311 assert( varv != NULL );
    2312 assert( varw != NULL );
    2313
    2314 /* if x_v != 0 turns out to be infeasible then fix x_v = 0 */
    2315 if ( ( lower && SCIPisFeasLT(scip, ub, newbound) ) || ( ! lower && SCIPisFeasGT(scip, lb, newbound) ) )
    2316 {
    2317 SCIP_Bool infeasible1;
    2318 SCIP_Bool infeasible2;
    2319 SCIP_Bool tightened1;
    2320 SCIP_Bool tightened2;
    2321
    2322 SCIP_CALL( SCIPtightenVarLb(scip, varv, 0.0, FALSE, &infeasible1, &tightened1) );
    2323 SCIP_CALL( SCIPtightenVarUb(scip, varv, 0.0, FALSE, &infeasible2, &tightened2) );
    2324
    2325 if ( infeasible1 || infeasible2 )
    2326 {
    2327 SCIPdebugMsg(scip, "detected infeasibility while trying to fix variable <%s> to zero\n", SCIPvarGetName(varv));
    2328 *infeasible = TRUE;
    2329 }
    2330
    2331 if ( tightened1 || tightened2 )
    2332 {
    2333 SCIPdebugMsg(scip, "fixed variable %s from lb = %f and ub = %f to 0.0 \n", SCIPvarGetName(varv), lb, ub);
    2334 ++(*nchgbds);
    2335 }
    2336 }
    2337
    2338 /* get successor information */
    2339 indv = SCIPhashmapGetImageInt(implhash, varv); /* get index of x_v in implication graph */
    2340 assert( SCIPhashmapGetImageInt(implhash, totalvars[indv]) == indv );
    2341 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, indv);
    2342 nsucc = SCIPdigraphGetNSuccessors(implgraph, indv);
    2343 succ = SCIPdigraphGetSuccessors(implgraph, indv);
    2344
    2345 /* search for nodew in existing successors. If this is the case then check whether the lower implication bound may be updated ... */
    2346 indw = SCIPhashmapGetImageInt(implhash, varw);
    2347 assert( SCIPhashmapGetImageInt(implhash, totalvars[indw]) == indw );
    2348 for (s = 0; s < nsucc; ++s)
    2349 {
    2350 if ( succ[s] == indw )
    2351 {
    2352 data = succdatas[s];
    2353 assert( data != NULL );
    2354 if ( lower && SCIPisFeasLT(scip, data->lbimpl, newbound) )
    2355 {
    2356 if ( SCIPvarIsIntegral(varw) )
    2357 data->lbimpl = SCIPceil(scip, newbound);
    2358 else
    2359 data->lbimpl = newbound;
    2360
    2361 *update = TRUE;
    2362 SCIPdebugMsg(scip, "updated to implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
    2363 }
    2364 else if ( ! lower && SCIPisFeasGT(scip, data->ubimpl, newbound) )
    2365 {
    2366 if ( SCIPvarIsIntegral(varw) )
    2367 data->ubimpl = SCIPfloor(scip, newbound);
    2368 else
    2369 data->ubimpl = newbound;
    2370
    2371 *update = TRUE;
    2372 SCIPdebugMsg(scip, "updated to implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
    2373 }
    2374 break;
    2375 }
    2376 }
    2377
    2378 /* ..., otherwise if there does not exist an arc between indv and indw already, then create one and add implication */
    2379 if ( s == nsucc )
    2380 {
    2381 assert( data == NULL );
    2383 if ( lower )
    2384 {
    2385 data->lbimpl = newbound;
    2386 data->ubimpl = ub;
    2387 SCIPdebugMsg(scip, "add implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
    2388 }
    2389 else
    2390 {
    2391 data->lbimpl = lb;
    2392 data->ubimpl = newbound;
    2393 SCIPdebugMsg(scip, "add implication %s != 0 -> %s <= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
    2394 }
    2395 SCIP_CALL( SCIPdigraphAddArc(implgraph, indv, indw, (void*)data) );
    2396 *update = TRUE;
    2397 }
    2398
    2399 return SCIP_OKAY;
    2400}
    2401
    2402
    2403/** updates implication graph
    2404 *
    2405 * Assume the variable from the input is nonzero. If this implies that some other variable is also nonzero, then
    2406 * store this information in an implication graph
    2407 */
    2408static
    2410 SCIP* scip, /**< SCIP pointer */
    2411 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    2412 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    2413 SCIP_Bool** adjacencymatrix, /**< adjacency matrix of conflict graph (lower half) */
    2414 SCIP_DIGRAPH* implgraph, /**< implication graph (\f$j\f$ is successor of \f$i\f$ if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
    2415 SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */
    2416 SCIP_Bool* implnodes, /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
    2417 SCIP_VAR** totalvars, /**< problem and SOS1 variables */
    2418 int** cliquecovers, /**< clique covers of linear constraint */
    2419 int* cliquecoversizes, /**< size of clique covers */
    2420 int* varincover, /**< array with varincover[i] = cover of SOS1 index \f$i\f$ */
    2421 SCIP_VAR** vars, /**< variables to be checked */
    2422 SCIP_Real* coefs, /**< coefficients of variables in linear constraint */
    2423 int nvars, /**< number of variables to be checked */
    2424 SCIP_Real* bounds, /**< bounds of variables */
    2425 SCIP_VAR* var, /**< variable that is assumed to be nonzero */
    2426 SCIP_Real bound, /**< bound of variable */
    2427 SCIP_Real boundnonzero, /**< bound of variable if it is known to be nonzero if infinity values are not summarized */
    2428 int ninftynonzero, /**< number of times infinity/-infinity has to be summarized to boundnonzero */
    2429 SCIP_Bool lower, /**< TRUE if lower bounds are consideres; FALSE for upper bounds */
    2430 int* nchgbds, /**< pointer to store number of changed bounds */
    2431 SCIP_Bool* update, /**< pointer to store whether implication graph has been updated */
    2432 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility has been detected */
    2433 )
    2434{
    2435 int nodev;
    2436 int w;
    2437
    2438 assert( update != NULL );
    2439
    2440 /* update implication graph if possible */
    2441 *update = FALSE;
    2442 *infeasible = FALSE;
    2443 nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */
    2444
    2445 /* if nodev is an index of an SOS1 variable and at least one lower bound of a variable that is not x_v is infinity */
    2446 if ( nodev < 0 || SCIPisInfinity(scip, REALABS(bound)) || ninftynonzero > 1 )
    2447 return SCIP_OKAY;
    2448
    2449 /* for every variable x_w: compute upper bound of a_w * x_w if x_v is known to be nonzero */
    2450 for (w = 0; w < nvars; ++w)
    2451 {
    2452 int newninftynonzero;
    2453 SCIP_Bool implinfty = FALSE;
    2454 int nodew;
    2455
    2456 /* get node of x_w in conflict graph: nodew = -1 if it is no SOS1 variable */
    2457 nodew = varGetNodeSOS1(conshdlrdata, vars[w]);
    2458
    2459 newninftynonzero = ninftynonzero;
    2460
    2461 /* variable should not be fixed to be already zero (note x_v is fixed to be nonzero by assumption) */
    2462 if ( nodew < 0 || ( nodev != nodew && ! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodew) && ! isImpliedZero(conflictgraph, implnodes, nodew) ) )
    2463 {
    2464 SCIP_Real implbound;
    2465 SCIP_Bool implcoverw;
    2466 int nodecliq;
    2467 int indcliq;
    2468 int ind;
    2469 int j;
    2470
    2471 /* boundnonzero is the bound of x_v if x_v is nonzero we use this information to get a bound of x_w if x_v is
    2472 * nonzero; therefore, we have to perform some recomputations */
    2473 implbound = boundnonzero - bound;
    2474 ind = varincover[w];
    2475 assert( cliquecoversizes[ind] > 0 );
    2476
    2477 implcoverw = FALSE;
    2478 for (j = 0; j < cliquecoversizes[ind]; ++j)
    2479 {
    2480 indcliq = cliquecovers[ind][j];
    2481 assert( 0 <= indcliq && indcliq < nvars );
    2482
    2483 nodecliq = varGetNodeSOS1(conshdlrdata, vars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */
    2484
    2485 /* if nodecliq is not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0 */
    2486 if ( nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) )
    2487 {
    2488 if ( indcliq == w )
    2489 {
    2490 if ( !SCIPisInfinity(scip, REALABS(bounds[w])) && !SCIPisInfinity(scip, REALABS(implbound + bounds[w])) )
    2491 implbound += bounds[w];
    2492 else
    2493 --newninftynonzero;
    2494 implcoverw = TRUE;
    2495 }
    2496 else if ( implcoverw )
    2497 {
    2498 if ( SCIPisInfinity(scip, REALABS(bounds[indcliq])) || SCIPisInfinity(scip, REALABS(implbound - bounds[indcliq])) )
    2499 implinfty = TRUE;
    2500 else
    2501 implbound -= bounds[indcliq];
    2502 break;
    2503 }
    2504 else
    2505 {
    2506 if ( SCIPisInfinity(scip, REALABS(bounds[indcliq])) )
    2507 implinfty = TRUE;
    2508 break;
    2509 }
    2510 }
    2511 }
    2512
    2513 /* check whether x_v != 0 implies a bound change of x_w */
    2514 if ( ! implinfty && newninftynonzero == 0 )
    2515 {
    2516 SCIP_Real newbound;
    2517 SCIP_Real coef;
    2518 SCIP_Real lb;
    2519 SCIP_Real ub;
    2520
    2521 lb = SCIPvarGetLbLocal(vars[w]);
    2522 ub = SCIPvarGetUbLocal(vars[w]);
    2523 coef = coefs[w];
    2524
    2525 if ( SCIPisFeasZero(scip, coef) )
    2526 continue;
    2527
    2528 newbound = implbound / coef;
    2529
    2530 if ( SCIPisInfinity(scip, newbound) )
    2531 continue;
    2532
    2533 /* check if an implication can be added/updated or assumption x_v != 0 is infeasible */
    2534 if ( lower )
    2535 {
    2536 if ( SCIPisFeasPositive(scip, coef) && SCIPisFeasLT(scip, lb, newbound) )
    2537 {
    2538 SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, TRUE, nchgbds, update, infeasible) );
    2539 }
    2540 else if ( SCIPisFeasNegative(scip, coef) && SCIPisFeasGT(scip, ub, newbound) )
    2541 {
    2542 SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, FALSE, nchgbds, update, infeasible) );
    2543 }
    2544 }
    2545 else
    2546 {
    2547 if ( SCIPisFeasPositive(scip, coef) && SCIPisFeasGT(scip, ub, newbound) )
    2548 {
    2549 SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, FALSE, nchgbds, update, infeasible) );
    2550 }
    2551 else if ( SCIPisFeasNegative(scip, coef) && SCIPisFeasLT(scip, lb, newbound) )
    2552 {
    2553 SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, TRUE, nchgbds, update, infeasible) );
    2554 }
    2555 }
    2556 }
    2557 }
    2558 }
    2559
    2560 return SCIP_OKAY;
    2561}
    2562
    2563
    2564/** search new disjoint clique that covers given node
    2565 *
    2566 * For a given vertex v search for a clique of the conflict graph induced by the variables of a linear constraint that
    2567 * - covers v and
    2568 * - has an an empty intersection with already computed clique cover.
    2569 */
    2570static
    2572 SCIP* scip, /**< SCIP pointer */
    2573 SCIP_DIGRAPH* conflictgraphroot, /**< conflict graph of the root node (nodes: 1, ..., nsos1vars) */
    2574 SCIP_DIGRAPH* conflictgraphlin, /**< conflict graph of linear constraint (nodes: 1, ..., nlinvars) */
    2575 SCIP_VAR** linvars, /**< variables in linear constraint */
    2576 SCIP_Bool* coveredvars, /**< states which variables of the linear constraint are currently covered by a clique */
    2577 int* clique, /**< array to store new clique in cover */
    2578 int* cliquesize, /**< pointer to store the size of clique */
    2579 int v, /**< position of variable in linear constraint that should be covered */
    2580 SCIP_Bool considersolvals /**< TRUE if largest auxiliary bigM values of variables should be prefered */
    2581 )
    2582{
    2583 int nsucc;
    2584 int s;
    2585
    2586 assert( conflictgraphlin != NULL );
    2587 assert( linvars != NULL );
    2588 assert( coveredvars != NULL );
    2589 assert( clique != NULL );
    2590 assert( cliquesize != NULL );
    2591
    2592 assert( ! coveredvars[v] ); /* we should produce a new clique */
    2593
    2594 /* add index 'v' to the clique cover */
    2595 clique[0] = v;
    2596 *cliquesize = 1;
    2597
    2598 nsucc = SCIPdigraphGetNSuccessors(conflictgraphlin, v);
    2599 if ( nsucc > 0 )
    2600 {
    2601 int* extensions;
    2602 int nextensions = 0;
    2603 int nextensionsnew;
    2604 int succnode;
    2605 int* succ;
    2606
    2607 /* allocate buffer array */
    2608 SCIP_CALL( SCIPallocBufferArray(scip, &extensions, nsucc) );
    2609
    2610 succ = SCIPdigraphGetSuccessors(conflictgraphlin, v);
    2611
    2612 /* compute possible extensions for the clique cover */
    2613 for (s = 0; s < nsucc; ++s)
    2614 {
    2615 succnode = succ[s];
    2616 if ( ! coveredvars[succnode] )
    2617 extensions[nextensions++] = succ[s];
    2618 }
    2619
    2620 /* while there exist possible extensions for the clique cover */
    2621 while ( nextensions > 0 )
    2622 {
    2623 int bestindex = -1;
    2624
    2625 if ( considersolvals )
    2626 {
    2627 SCIP_Real bestbigMval;
    2628 SCIP_Real bigMval;
    2629
    2630 bestbigMval = -SCIPinfinity(scip);
    2631
    2632 /* search for the extension with the largest absolute value of its LP relaxation solution value */
    2633 for (s = 0; s < nextensions; ++s)
    2634 {
    2635 bigMval = nodeGetSolvalBinaryBigMSOS1(scip, conflictgraphroot, NULL, extensions[s]);
    2636 if ( SCIPisFeasLT(scip, bestbigMval, bigMval) )
    2637 {
    2638 bestbigMval = bigMval;
    2639 bestindex = extensions[s];
    2640 }
    2641 }
    2642 }
    2643 else
    2644 bestindex = extensions[0];
    2645
    2646 assert( bestindex != -1 );
    2647
    2648 /* add bestindex to the clique cover */
    2649 clique[(*cliquesize)++] = bestindex;
    2650
    2651 /* compute new 'extensions' array */
    2652 nextensionsnew = 0;
    2653 for (s = 0; s < nextensions; ++s)
    2654 {
    2655 if ( s != bestindex && isConnectedSOS1(NULL, conflictgraphlin, bestindex, extensions[s]) )
    2656 extensions[nextensionsnew++] = extensions[s];
    2657 }
    2658 nextensions = nextensionsnew;
    2659 }
    2660
    2661 /* free buffer array */
    2662 SCIPfreeBufferArray(scip, &extensions);
    2663 }
    2664
    2665 /* mark covered indices */
    2666 for (s = 0; s < *cliquesize; ++s)
    2667 {
    2668 int ind;
    2669
    2670 ind = clique[s];
    2671 assert( 0 <= ind );
    2672 assert( ! coveredvars[ind] );
    2673 coveredvars[ind] = TRUE;
    2674 }
    2675
    2676 return SCIP_OKAY;
    2677}
    2678
    2679
    2680/** try to tighten upper and lower bounds for variables */
    2681static
    2683 SCIP* scip, /**< SCIP pointer */
    2684 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    2685 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    2686 SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \f$ implies a new lower/upper bound for \f$ x_j\f$) */
    2687 SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */
    2688 SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of conflict graph */
    2689 SCIP_VAR** totalvars, /**< problem and SOS1 vars */
    2690 int ntotalvars, /**< number of problem and SOS1 variables*/
    2691 int nsos1vars, /**< number of SOS1 variables */
    2692 int* nchgbds, /**< pointer to store number of changed bounds */
    2693 SCIP_Bool* implupdate, /**< pointer to store whether the implication graph has been updated in this function call */
    2694 SCIP_Bool* cutoff /**< pointer to store if current nodes LP is infeasible */
    2695 )
    2696{
    2697 SCIP_CONSHDLR* conshdlrlinear;
    2698 SCIP_CONS** linearconss;
    2699 int nlinearconss;
    2700
    2701 SCIP_Bool* implnodes = NULL; /* implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
    2702 SCIP_Bool* coveredvars = NULL; /* coveredvars[i] = TRUE if variable with index i is covered by the clique cover */
    2703 int* varindincons = NULL; /* varindincons[i] = position of SOS1 index i in linear constraint (-1 if x_i is not involved in linear constraint) */
    2704
    2705 SCIP_VAR** trafolinvars = NULL; /* variables of transformed linear constraints without (multi)aggregated variables */
    2706 int ntrafolinvars = 0;
    2707 SCIP_Real* trafolinvals = NULL;
    2708 SCIP_Real* trafoubs = NULL;
    2709 SCIP_Real* trafolbs = NULL;
    2710 SCIP_Real traforhs;
    2711 SCIP_Real trafolhs;
    2712
    2713 SCIP_VAR** sos1linvars = NULL; /* variables that are not contained in linear constraint, but are in conflict with a variable from the linear constraint */
    2714 int nsos1linvars;
    2715 int c;
    2716
    2717 assert( scip != NULL );
    2718 assert( conflictgraph != NULL );
    2719 assert( adjacencymatrix != NULL );
    2720 assert( nchgbds != NULL );
    2721 assert( cutoff != NULL );
    2722
    2723 *cutoff = FALSE;
    2724 *implupdate = FALSE;
    2725
    2726 /* get constraint handler data of linear constraints */
    2727 conshdlrlinear = SCIPfindConshdlr(scip, "linear");
    2728 if ( conshdlrlinear == NULL )
    2729 return SCIP_OKAY;
    2730
    2731 /* get linear constraints and number of linear constraints */
    2732 nlinearconss = SCIPconshdlrGetNConss(conshdlrlinear);
    2733 linearconss = SCIPconshdlrGetConss(conshdlrlinear);
    2734
    2735 /* allocate buffer arrays */
    2736 SCIP_CALL( SCIPallocBufferArray(scip, &sos1linvars, nsos1vars) );
    2737 SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) );
    2738 SCIP_CALL( SCIPallocBufferArray(scip, &varindincons, nsos1vars) );
    2739 SCIP_CALL( SCIPallocBufferArray(scip, &coveredvars, ntotalvars) );
    2740 SCIP_CALL( SCIPallocBufferArray(scip, &trafoubs, ntotalvars) );
    2741 SCIP_CALL( SCIPallocBufferArray(scip, &trafolbs, ntotalvars) );
    2742
    2743 /* for every linear constraint and every SOS1 variable */
    2744 for (c = 0; c < nlinearconss + nsos1vars && ! (*cutoff); ++c)
    2745 {
    2746 SCIP_DIGRAPH* conflictgraphlin;
    2747 int** cliquecovers = NULL; /* clique covers of indices of variables in linear constraint */
    2748 int* cliquecoversizes = NULL; /* size of each cover */
    2749 SCIP_VAR* sosvar = NULL;
    2750 SCIP_Real* cliquecovervals = NULL;
    2751 SCIP_Real constant;
    2752 int* varincover = NULL; /* varincover[i] = cover of SOS1 index i */
    2753 int ncliquecovers;
    2754 int requiredsize;
    2755
    2756 int v;
    2757 int i;
    2758 int j;
    2759
    2760 /* get transformed linear constraints (without aggregated variables) */
    2761 if ( c < nlinearconss )
    2762 {
    2763 SCIP_VAR** origlinvars;
    2764 SCIP_Real* origlinvals;
    2765
    2766 /* get data of linear constraint */
    2767 ntrafolinvars = SCIPgetNVarsLinear(scip, linearconss[c]);
    2768 if ( ntrafolinvars < 1 )
    2769 continue;
    2770
    2771 origlinvars = SCIPgetVarsLinear(scip, linearconss[c]);
    2772 origlinvals = SCIPgetValsLinear(scip, linearconss[c]);
    2773 assert( origlinvars != NULL );
    2774 assert( origlinvals != NULL );
    2775
    2776 /* copy variables and coefficients of linear constraint */
    2777 SCIP_CALL( SCIPduplicateBufferArray(scip, &trafolinvars, origlinvars, ntrafolinvars) );
    2778 SCIP_CALL( SCIPduplicateBufferArray(scip, &trafolinvals, origlinvals, ntrafolinvars) );
    2779
    2780 trafolhs = SCIPgetLhsLinear(scip, linearconss[c]);
    2781 traforhs = SCIPgetRhsLinear(scip, linearconss[c]);
    2782 }
    2783 else
    2784 {
    2785 sosvar = SCIPnodeGetVarSOS1(conflictgraph, c - nlinearconss);
    2786
    2790 continue;
    2791
    2792 /* store variable so it will be transformed to active variables below */
    2793 ntrafolinvars = 1;
    2794 SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvars, ntrafolinvars + 1) );
    2795 SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvals, ntrafolinvars + 1) );
    2796
    2797 trafolinvars[0] = sosvar;
    2798 trafolinvals[0] = 1.0;
    2799
    2800 trafolhs = 0.0;
    2801 traforhs = 0.0;
    2802 }
    2803 assert( ntrafolinvars >= 1 );
    2804
    2805 /* transform linear constraint */
    2806 constant = 0.0;
    2807 SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, ntrafolinvars, &constant, &requiredsize) );
    2808 if( requiredsize > ntrafolinvars )
    2809 {
    2810 SCIP_CALL( SCIPreallocBufferArray(scip, &trafolinvars, requiredsize + 1) );
    2811 SCIP_CALL( SCIPreallocBufferArray(scip, &trafolinvals, requiredsize + 1) );
    2812
    2813 SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, requiredsize, &constant, &requiredsize) );
    2814 }
    2815 assert(requiredsize == ntrafolinvars);
    2816 if( !SCIPisInfinity(scip, -trafolhs) )
    2817 trafolhs -= constant;
    2818 if( !SCIPisInfinity(scip, traforhs) )
    2819 traforhs -= constant;
    2820
    2821 if ( ntrafolinvars == 0 )
    2822 {
    2823 SCIPfreeBufferArray(scip, &trafolinvals);
    2824 SCIPfreeBufferArray(scip, &trafolinvars);
    2825 continue;
    2826 }
    2827
    2828 /* possibly add sos1 variable to create aggregation/multiaggregation/negation equality */
    2829 if ( sosvar != NULL )
    2830 {
    2831 trafolinvals[ntrafolinvars] = -1.0;
    2832 trafolinvars[ntrafolinvars] = sosvar;
    2833 ++ntrafolinvars;
    2834 }
    2835
    2836 /* compute lower and upper bounds of each term a_i * x_i of transformed constraint */
    2837 for (v = 0; v < ntrafolinvars; ++v)
    2838 {
    2839 SCIP_Real lb;
    2840 SCIP_Real ub;
    2841
    2842 lb = SCIPvarGetLbLocal(trafolinvars[v]);
    2843 ub = SCIPvarGetUbLocal(trafolinvars[v]);
    2844
    2845 if ( trafolinvals[v] < 0.0 )
    2846 SCIPswapReals(&lb, &ub);
    2847
    2848 assert( ! SCIPisInfinity(scip, REALABS(trafolinvals[v])) );
    2849
    2850 if ( SCIPisInfinity(scip, REALABS(lb)) || SCIPisInfinity(scip, REALABS(lb * trafolinvals[v])) )
    2851 trafolbs[v] = -SCIPinfinity(scip);
    2852 else
    2853 trafolbs[v] = lb * trafolinvals[v];
    2854
    2855 if ( SCIPisInfinity(scip, REALABS(ub)) || SCIPisInfinity(scip, REALABS(ub * trafolinvals[v])) )
    2856 trafoubs[v] = SCIPinfinity(scip);
    2857 else
    2858 trafoubs[v] = ub * trafolinvals[v];
    2859 }
    2860
    2861 /* initialization: mark all the SOS1 variables as 'not a member of the linear constraint' */
    2862 for (v = 0; v < nsos1vars; ++v)
    2863 varindincons[v] = -1;
    2864
    2865 /* save position of SOS1 variables in linear constraint */
    2866 for (v = 0; v < ntrafolinvars; ++v)
    2867 {
    2868 int node;
    2869
    2870 node = varGetNodeSOS1(conshdlrdata, trafolinvars[v]);
    2871
    2872 if ( node >= 0 )
    2873 varindincons[node] = v;
    2874 }
    2875
    2876 /* create conflict graph of linear constraint */
    2877 SCIP_CALL( SCIPcreateDigraph(scip, &conflictgraphlin, ntrafolinvars) );
    2878 SCIP_CALL( genConflictgraphLinearCons(conshdlrdata, conflictgraphlin, conflictgraph, trafolinvars, ntrafolinvars, varindincons) );
    2879
    2880 /* mark all the variables as 'not covered by some clique cover' */
    2881 for (i = 0; i < ntrafolinvars; ++i)
    2882 coveredvars[i] = FALSE;
    2883
    2884 /* allocate buffer array */
    2885 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecovervals, ntrafolinvars) );
    2886 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecoversizes, ntrafolinvars) );
    2887 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecovers, ntrafolinvars) );
    2888
    2889 /* compute distinct cliques that cover all the variables of the linear constraint */
    2890 ncliquecovers = 0;
    2891 for (v = 0; v < ntrafolinvars; ++v)
    2892 {
    2893 /* if variable is not already covered by an already known clique cover */
    2894 if ( ! coveredvars[v] )
    2895 {
    2896 SCIP_CALL( SCIPallocBufferArray(scip, &(cliquecovers[ncliquecovers]), ntrafolinvars) ); /*lint !e866*/
    2897 SCIP_CALL( computeVarsCoverSOS1(scip, conflictgraph, conflictgraphlin, trafolinvars, coveredvars, cliquecovers[ncliquecovers], &(cliquecoversizes[ncliquecovers]), v, FALSE) );
    2898 ++ncliquecovers;
    2899 }
    2900 }
    2901
    2902 /* free conflictgraph */
    2903 SCIPdigraphFree(&conflictgraphlin);
    2904
    2905 /* compute variables that are not contained in transformed linear constraint, but are in conflict with a variable from the transformed linear constraint */
    2906 nsos1linvars = 0;
    2907 for (v = 0; v < ntrafolinvars; ++v)
    2908 {
    2909 int nodev;
    2910
    2911 nodev = varGetNodeSOS1(conshdlrdata, trafolinvars[v]);
    2912
    2913 /* if variable is an SOS1 variable */
    2914 if ( nodev >= 0 )
    2915 {
    2916 int succnode;
    2917 int nsucc;
    2918 int* succ;
    2919 int s;
    2920
    2921 succ = SCIPdigraphGetSuccessors(conflictgraph, nodev);
    2922 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, nodev);
    2923
    2924 for (s = 0; s < nsucc; ++s)
    2925 {
    2926 succnode = succ[s];
    2927
    2928 /* if variable is not a member of linear constraint and not already listed in the array sos1linvars */
    2929 if ( varindincons[succnode] == -1 )
    2930 {
    2931 sos1linvars[nsos1linvars] = SCIPnodeGetVarSOS1(conflictgraph, succnode);
    2932 varindincons[succnode] = -2; /* mark variable as listed in array sos1linvars */
    2933 ++nsos1linvars;
    2934 }
    2935 }
    2936 }
    2937 }
    2938
    2939 /* try to tighten lower bounds */
    2940
    2941 /* sort each cliquecover array in ascending order of the lower bounds of a_i * x_i; fill vector varincover */
    2942 SCIP_CALL( SCIPallocBufferArray(scip, &varincover, ntrafolinvars) );
    2943 for (i = 0; i < ncliquecovers; ++i)
    2944 {
    2945 for (j = 0; j < cliquecoversizes[i]; ++j)
    2946 {
    2947 int ind = cliquecovers[i][j];
    2948
    2949 varincover[ind] = i;
    2950 cliquecovervals[j] = trafoubs[ind];
    2951 }
    2952 SCIPsortDownRealInt(cliquecovervals, cliquecovers[i], cliquecoversizes[i]);
    2953 }
    2954
    2955 /* for every variable in transformed constraint: try lower bound tightening */
    2956 for (v = 0; v < ntrafolinvars + nsos1linvars; ++v)
    2957 {
    2958 SCIP_Real newboundnonzero; /* new bound of a_v * x_v if we assume that x_v != 0 */
    2959 SCIP_Real newboundnores; /* new bound of a_v * x_v if we assume that x_v = 0 is possible */
    2960 SCIP_Real newbound; /* resulting new bound of x_v */
    2961 SCIP_VAR* var;
    2962 SCIP_Real trafoubv;
    2963 SCIP_Real linval;
    2964 SCIP_Real ub;
    2965 SCIP_Real lb;
    2966 SCIP_Bool tightened;
    2967 SCIP_Bool infeasible;
    2968 SCIP_Bool inftynores = FALSE;
    2969 SCIP_Bool update;
    2970 int ninftynonzero = 0;
    2971 int nodev;
    2972 int w;
    2973
    2974 if ( v < ntrafolinvars )
    2975 {
    2976 var = trafolinvars[v];
    2977 trafoubv = trafoubs[v];
    2978 }
    2979 else
    2980 {
    2981 assert( v >= ntrafolinvars );
    2982 var = sos1linvars[v-ntrafolinvars];/*lint !e679*/
    2983 trafoubv = 0.0;
    2984 }
    2985
    2986 ub = SCIPvarGetUbLocal(var);
    2987 lb = SCIPvarGetLbLocal(var);
    2988
    2989 if ( SCIPisInfinity(scip, -trafolhs) || SCIPisZero(scip, ub - lb) )
    2990 continue;
    2991
    2992 newboundnonzero = trafolhs;
    2993 newboundnores = trafolhs;
    2994 nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */
    2995 assert( nodev < nsos1vars );
    2996
    2997 /* determine incidence vector of implication variables */
    2998 for (w = 0; w < nsos1vars; ++w)
    2999 implnodes[w] = FALSE;
    3000 SCIP_CALL( getSOS1Implications(scip, conshdlrdata, totalvars, implgraph, implhash, implnodes, SCIPhashmapGetImageInt(implhash, var)) );
    3001
    3002 /* compute new bound */
    3003 for (i = 0; i < ncliquecovers; ++i)
    3004 {
    3005 int indcliq;
    3006 int nodecliq;
    3007
    3008 assert( cliquecoversizes[i] > 0 );
    3009
    3010 indcliq = cliquecovers[i][0];
    3011 assert( 0 <= indcliq && indcliq < ntrafolinvars );
    3012
    3013 /* determine maximum without index v (note that the array 'cliquecovers' is sorted by the values of trafoub in non-increasing order) */
    3014 if ( v != indcliq )
    3015 {
    3016 if ( SCIPisInfinity(scip, trafoubs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnores - trafoubs[indcliq])) )
    3017 inftynores = TRUE;
    3018 else
    3019 newboundnores -= trafoubs[indcliq];
    3020 }
    3021 else if ( cliquecoversizes[i] > 1 )
    3022 {
    3023 assert( 0 <= cliquecovers[i][1] && cliquecovers[i][1] < ntrafolinvars );
    3024 if ( SCIPisInfinity(scip, trafoubs[cliquecovers[i][1]]) || SCIPisInfinity(scip, REALABS(newboundnores - trafoubs[cliquecovers[i][1]])) )
    3025 inftynores = TRUE;
    3026 else
    3027 newboundnores -= trafoubs[cliquecovers[i][1]];/*lint --e{679}*/
    3028 }
    3029
    3030 /* determine maximum without index v and if x_v is nonzero (note that the array 'cliquecovers' is sorted by the values of trafoub in non-increasing order) */
    3031 for (j = 0; j < cliquecoversizes[i]; ++j)
    3032 {
    3033 indcliq = cliquecovers[i][j];
    3034 assert( 0 <= indcliq && indcliq < ntrafolinvars );
    3035
    3036 nodecliq = varGetNodeSOS1(conshdlrdata, trafolinvars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */
    3037 assert( nodecliq < nsos1vars );
    3038
    3039 if ( v != indcliq )
    3040 {
    3041 /* if nodev or nodecliq are not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0 */
    3042 if ( nodev < 0 || nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) )
    3043 {
    3044 if ( SCIPisInfinity(scip, trafoubs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnonzero - trafoubs[indcliq])) )
    3045 ++ninftynonzero;
    3046 else
    3047 newboundnonzero -= trafoubs[indcliq];
    3048 break; /* break since we are only interested in the maximum upper bound among the variables in the clique cover;
    3049 * the variables in the clique cover form an SOS1 constraint, thus only one of them can be nonzero */
    3050 }
    3051 }
    3052 }
    3053 }
    3054 assert( ninftynonzero == 0 || inftynores );
    3055
    3056 /* if computed upper bound is not infinity and variable is contained in linear constraint */
    3057 if ( ninftynonzero == 0 && v < ntrafolinvars )
    3058 {
    3059 linval = trafolinvals[v];
    3060
    3061 if ( SCIPisFeasZero(scip, linval) )
    3062 continue;
    3063
    3064 /* compute new bound */
    3065 if ( SCIPisFeasPositive(scip, newboundnores) && ! inftynores )
    3066 newbound = newboundnonzero;
    3067 else
    3068 newbound = MIN(0, newboundnonzero);
    3069 newbound /= linval;
    3070
    3071 if ( SCIPisInfinity(scip, newbound) )
    3072 continue;
    3073
    3074 /* check if new bound is tighter than the old one or problem is infeasible */
    3075 if ( SCIPisFeasPositive(scip, linval) && SCIPisFeasLT(scip, lb, newbound) )
    3076 {
    3077 if ( SCIPisFeasLT(scip, ub, newbound) )
    3078 {
    3079 *cutoff = TRUE;
    3080 break;
    3081 }
    3082
    3083 if ( SCIPvarIsIntegral(var) )
    3084 newbound = SCIPceil(scip, newbound);
    3085
    3086 SCIP_CALL( SCIPtightenVarLb(scip, var, newbound, FALSE, &infeasible, &tightened) );
    3087 assert( ! infeasible );
    3088
    3089 if ( tightened )
    3090 {
    3091 SCIPdebugMsg(scip, "changed lower bound of variable %s from %f to %f \n", SCIPvarGetName(var), lb, newbound);
    3092 ++(*nchgbds);
    3093 }
    3094 }
    3095 else if ( SCIPisFeasNegative(scip, linval) && SCIPisFeasGT(scip, ub, newbound) )
    3096 {
    3097 /* if assumption a_i * x_i != 0 was not correct */
    3098 if ( SCIPisFeasGT(scip, SCIPvarGetLbLocal(var), newbound) )
    3099 {
    3100 *cutoff = TRUE;
    3101 break;
    3102 }
    3103
    3104 if ( SCIPvarIsIntegral(var) )
    3105 newbound = SCIPfloor(scip, newbound);
    3106
    3107 SCIP_CALL( SCIPtightenVarUb(scip, var, newbound, FALSE, &infeasible, &tightened) );
    3108 assert( ! infeasible );
    3109
    3110 if ( tightened )
    3111 {
    3112 SCIPdebugMsg(scip, "changed upper bound of variable %s from %f to %f \n", SCIPvarGetName(var), ub, newbound);
    3113 ++(*nchgbds);
    3114 }
    3115 }
    3116 }
    3117
    3118 /* update implication graph if possible */
    3119 SCIP_CALL( updateImplicationGraphSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, implgraph, implhash, implnodes, totalvars, cliquecovers, cliquecoversizes, varincover,
    3120 trafolinvars, trafolinvals, ntrafolinvars, trafoubs, var, trafoubv, newboundnonzero, ninftynonzero, TRUE, nchgbds, &update, &infeasible) );
    3121 if ( infeasible )
    3122 *cutoff = TRUE;
    3123 else if ( update )
    3124 *implupdate = TRUE;
    3125 }
    3126
    3127 if ( *cutoff == TRUE )
    3128 {
    3129 /* free memory */
    3130 SCIPfreeBufferArrayNull(scip, &varincover);
    3131 for (j = ncliquecovers-1; j >= 0; --j)
    3132 SCIPfreeBufferArrayNull(scip, &cliquecovers[j]);
    3133 SCIPfreeBufferArrayNull(scip, &cliquecovers);
    3134 SCIPfreeBufferArrayNull(scip, &cliquecoversizes);
    3135 SCIPfreeBufferArrayNull(scip, &cliquecovervals);
    3136 SCIPfreeBufferArrayNull(scip, &trafolinvals);
    3137 SCIPfreeBufferArrayNull(scip, &trafolinvars);
    3138 break;
    3139 }
    3140
    3141 /* try to tighten upper bounds */
    3142
    3143 /* sort each cliquecover array in ascending order of the lower bounds of a_i * x_i; fill vector varincover */
    3144 for (i = 0; i < ncliquecovers; ++i)
    3145 {
    3146 for (j = 0; j < cliquecoversizes[i]; ++j)
    3147 {
    3148 int ind = cliquecovers[i][j];
    3149
    3150 varincover[ind] = i;
    3151 cliquecovervals[j] = trafolbs[ind];
    3152 }
    3153 SCIPsortRealInt(cliquecovervals, cliquecovers[i], cliquecoversizes[i]);
    3154 }
    3155
    3156 /* for every variable that is in transformed constraint or every variable that is in conflict with some variable from trans. cons.:
    3157 try upper bound tightening */
    3158 for (v = 0; v < ntrafolinvars + nsos1linvars; ++v)
    3159 {
    3160 SCIP_Real newboundnonzero; /* new bound of a_v*x_v if we assume that x_v != 0 */
    3161 SCIP_Real newboundnores; /* new bound of a_v*x_v if there are no restrictions */
    3162 SCIP_Real newbound; /* resulting new bound of x_v */
    3163 SCIP_VAR* var;
    3164 SCIP_Real linval;
    3165 SCIP_Real trafolbv;
    3166 SCIP_Real lb;
    3167 SCIP_Real ub;
    3168 SCIP_Bool tightened;
    3169 SCIP_Bool infeasible;
    3170 SCIP_Bool inftynores = FALSE;
    3171 SCIP_Bool update;
    3172 int ninftynonzero = 0;
    3173 int nodev;
    3174 int w;
    3175
    3176 if ( v < ntrafolinvars )
    3177 {
    3178 var = trafolinvars[v];
    3179 trafolbv = trafolbs[v];
    3180 }
    3181 else
    3182 {
    3183 assert( v-ntrafolinvars >= 0 );
    3184 var = sos1linvars[v-ntrafolinvars];/*lint !e679*/
    3185 trafolbv = 0.0; /* since variable is not a member of linear constraint */
    3186 }
    3187 lb = SCIPvarGetLbLocal(var);
    3188 ub = SCIPvarGetUbLocal(var);
    3189 if ( SCIPisInfinity(scip, traforhs) || SCIPisEQ(scip, lb, ub) )
    3190 continue;
    3191
    3192 newboundnonzero = traforhs;
    3193 newboundnores = traforhs;
    3194 nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */
    3195 assert( nodev < nsos1vars );
    3196
    3197 /* determine incidence vector of implication variables (i.e., which SOS1 variables are nonzero if x_v is nonzero) */
    3198 for (w = 0; w < nsos1vars; ++w)
    3199 implnodes[w] = FALSE;
    3200 SCIP_CALL( getSOS1Implications(scip, conshdlrdata, totalvars, implgraph, implhash, implnodes, SCIPhashmapGetImageInt(implhash, var)) );
    3201
    3202 /* compute new bound */
    3203 for (i = 0; i < ncliquecovers; ++i)
    3204 {
    3205 int indcliq;
    3206 int nodecliq;
    3207
    3208 assert( cliquecoversizes[i] > 0 );
    3209
    3210 indcliq = cliquecovers[i][0];
    3211 assert( 0 <= indcliq && indcliq < ntrafolinvars );
    3212
    3213 /* determine minimum without index v (note that the array 'cliquecovers' is sorted by the values of trafolb in increasing order) */
    3214 if ( v != indcliq )
    3215 {
    3216 /* if bound would be infinity */
    3217 if ( SCIPisInfinity(scip, -trafolbs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnores - trafolbs[indcliq])) )
    3218 inftynores = TRUE;
    3219 else
    3220 newboundnores -= trafolbs[indcliq];
    3221 }
    3222 else if ( cliquecoversizes[i] > 1 )
    3223 {
    3224 assert( 0 <= cliquecovers[i][1] && cliquecovers[i][1] < ntrafolinvars );
    3225 if ( SCIPisInfinity(scip, -trafolbs[cliquecovers[i][1]]) || SCIPisInfinity(scip, REALABS(newboundnores - trafolbs[cliquecovers[i][1]])) )
    3226 inftynores = TRUE;
    3227 else
    3228 newboundnores -= trafolbs[cliquecovers[i][1]]; /*lint --e{679}*/
    3229 }
    3230
    3231 /* determine minimum without index v and if x_v is nonzero (note that the array 'cliquecovers' is sorted by the values of trafolb in increasing order) */
    3232 for (j = 0; j < cliquecoversizes[i]; ++j)
    3233 {
    3234 indcliq = cliquecovers[i][j];
    3235 assert( 0 <= indcliq && indcliq < ntrafolinvars );
    3236
    3237 nodecliq = varGetNodeSOS1(conshdlrdata, trafolinvars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */
    3238 assert( nodecliq < nsos1vars );
    3239
    3240 if ( v != indcliq )
    3241 {
    3242 /* if nodev or nodecliq are not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0 */
    3243 if ( nodev < 0 || nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) )
    3244 {
    3245 /* if bound would be infinity */
    3246 if ( SCIPisInfinity(scip, -trafolbs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnonzero - trafolbs[indcliq])) )
    3247 ++ninftynonzero;
    3248 else
    3249 newboundnonzero -= trafolbs[indcliq];
    3250 break; /* break since we are only interested in the minimum lower bound among the variables in the clique cover;
    3251 * the variables in the clique cover form an SOS1 constraint, thus only one of them can be nonzero */
    3252 }
    3253 }
    3254 }
    3255 }
    3256 assert( ninftynonzero == 0 || inftynores );
    3257
    3258 /* if computed bound is not infinity and variable is contained in linear constraint */
    3259 if ( ninftynonzero == 0 && v < ntrafolinvars )
    3260 {
    3261 linval = trafolinvals[v];
    3262
    3263 if ( SCIPisFeasZero(scip, linval) )
    3264 continue;
    3265
    3266 /* compute new bound */
    3267 if ( SCIPisFeasNegative(scip, newboundnores) && ! inftynores )
    3268 newbound = newboundnonzero;
    3269 else
    3270 newbound = MAX(0, newboundnonzero);
    3271 newbound /= linval;
    3272
    3273 if ( SCIPisInfinity(scip, newbound) )
    3274 continue;
    3275
    3276 /* check if new bound is tighter than the old one or problem is infeasible */
    3277 if ( SCIPisFeasPositive(scip, linval) && SCIPisFeasGT(scip, ub, newbound) )
    3278 {
    3279 /* if new upper bound is smaller than the lower bound, we are infeasible */
    3280 if ( SCIPisFeasGT(scip, lb, newbound) )
    3281 {
    3282 *cutoff = TRUE;
    3283 break;
    3284 }
    3285
    3286 if ( SCIPvarIsIntegral(var) )
    3287 newbound = SCIPfloor(scip, newbound);
    3288
    3289 SCIP_CALL( SCIPtightenVarUb(scip, var, newbound, FALSE, &infeasible, &tightened) );
    3290 assert( ! infeasible );
    3291
    3292 if ( tightened )
    3293 {
    3294 SCIPdebugMsg(scip, "changed upper bound of variable %s from %f to %f \n", SCIPvarGetName(var), ub, newbound);
    3295 ++(*nchgbds);
    3296 }
    3297 }
    3298 else if ( SCIPisFeasNegative(scip, linval) && SCIPisFeasLT(scip, lb, newbound) )
    3299 {
    3300 /* if assumption a_i * x_i != 0 was not correct */
    3301 if ( SCIPisFeasLT(scip, ub, newbound) )
    3302 {
    3303 *cutoff = TRUE;
    3304 break;
    3305 }
    3306
    3307 if ( SCIPvarIsIntegral(var) )
    3308 newbound = SCIPceil(scip, newbound);
    3309
    3310 SCIP_CALL( SCIPtightenVarLb(scip, var, newbound, FALSE, &infeasible, &tightened) );
    3311 assert( ! infeasible );
    3312
    3313 if ( tightened )
    3314 {
    3315 SCIPdebugMsg(scip, "changed lower bound of variable %s from %f to %f \n", SCIPvarGetName(var), lb, newbound);
    3316 ++(*nchgbds);
    3317 }
    3318 }
    3319 }
    3320
    3321 /* update implication graph if possible */
    3322 SCIP_CALL( updateImplicationGraphSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, implgraph, implhash, implnodes, totalvars, cliquecovers, cliquecoversizes, varincover,
    3323 trafolinvars, trafolinvals, ntrafolinvars, trafolbs, var, trafolbv, newboundnonzero, ninftynonzero, FALSE, nchgbds, &update, &infeasible) );
    3324 if ( infeasible )
    3325 *cutoff = TRUE;
    3326 else if ( update )
    3327 *implupdate = TRUE;
    3328 }
    3329
    3330 /* free memory */
    3331 SCIPfreeBufferArrayNull(scip, &varincover);
    3332 for (j = ncliquecovers-1; j >= 0; --j)
    3333 SCIPfreeBufferArrayNull(scip, &cliquecovers[j]);
    3334 SCIPfreeBufferArrayNull(scip, &cliquecovers);
    3335 SCIPfreeBufferArrayNull(scip, &cliquecoversizes);
    3336 SCIPfreeBufferArrayNull(scip, &cliquecovervals);
    3337 SCIPfreeBufferArrayNull(scip, &trafolinvals);
    3338 SCIPfreeBufferArrayNull(scip, &trafolinvars);
    3339
    3340 if ( *cutoff == TRUE )
    3341 break;
    3342 } /* end for every linear constraint */
    3343
    3344 /* free buffer arrays */
    3345 SCIPfreeBufferArrayNull(scip, &trafolbs);
    3346 SCIPfreeBufferArrayNull(scip, &trafoubs);
    3347 SCIPfreeBufferArrayNull(scip, &coveredvars);
    3348 SCIPfreeBufferArrayNull(scip, &varindincons);
    3349 SCIPfreeBufferArrayNull(scip, &implnodes);
    3350 SCIPfreeBufferArrayNull(scip, &sos1linvars);
    3351
    3352 return SCIP_OKAY;
    3353}
    3354
    3355
    3356/** perform one presolving round for variables
    3357 *
    3358 * We perform the following presolving steps:
    3359 * - Tighten the bounds of the variables
    3360 * - Update conflict graph based on bound implications of the variables
    3361 */
    3362static
    3364 SCIP* scip, /**< SCIP pointer */
    3365 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    3366 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    3367 SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of conflict graph */
    3368 int nsos1vars, /**< number of SOS1 variables */
    3369 int* nfixedvars, /**< pointer to store number of fixed variables */
    3370 int* nchgbds, /**< pointer to store number of changed bounds */
    3371 int* naddconss, /**< pointer to store number of addded constraints */
    3372 SCIP_RESULT* result /**< result */
    3373 )
    3374{
    3375 SCIP_DIGRAPH* implgraph;
    3376 SCIP_HASHMAP* implhash;
    3377
    3378 SCIP_Bool cutoff = FALSE;
    3379 SCIP_Bool updateconfl;
    3380
    3381 SCIP_VAR** totalvars;
    3382 SCIP_VAR** probvars;
    3383 int ntotalvars = 0;
    3384 int nprobvars;
    3385 int i;
    3386 int j;
    3387
    3388 /* determine totalvars (union of SOS1 and problem variables) */
    3389 probvars = SCIPgetVars(scip);
    3390 nprobvars = SCIPgetNVars(scip);
    3391 SCIP_CALL( SCIPhashmapCreate(&implhash, SCIPblkmem(scip), nsos1vars + nprobvars) );
    3392 SCIP_CALL( SCIPallocBufferArray(scip, &totalvars, nsos1vars + nprobvars) );
    3393
    3394 for (i = 0; i < nsos1vars; ++i)
    3395 {
    3396 SCIP_VAR* var;
    3397 var = SCIPnodeGetVarSOS1(conflictgraph, i);
    3398
    3399 /* insert node number to hash map */
    3400 assert( ! SCIPhashmapExists(implhash, var) );
    3401 SCIP_CALL( SCIPhashmapInsertInt(implhash, var, ntotalvars) );
    3402 assert( ntotalvars == SCIPhashmapGetImageInt(implhash, var) );
    3403 totalvars[ntotalvars++] = var;
    3404 }
    3405
    3406 for (i = 0; i < nprobvars; ++i)
    3407 {
    3408 SCIP_VAR* var;
    3409 var = probvars[i];
    3410
    3411 /* insert node number to hash map if not existent */
    3412 if ( ! SCIPhashmapExists(implhash, var) )
    3413 {
    3414 SCIP_CALL( SCIPhashmapInsertInt(implhash, var, ntotalvars) );
    3415 assert( ntotalvars == SCIPhashmapGetImageInt(implhash, var) );
    3416 totalvars[ntotalvars++] = var;
    3417 }
    3418 }
    3419
    3420 /* create implication graph */
    3421 SCIP_CALL( SCIPcreateDigraph(scip, &implgraph, ntotalvars) );
    3422
    3423 /* try to tighten the lower and upper bounds of the variables */
    3424 updateconfl = FALSE;
    3425 for (j = 0; (j < conshdlrdata->maxtightenbds || conshdlrdata->maxtightenbds == -1 ) && ! cutoff; ++j)
    3426 {
    3427 SCIP_Bool implupdate;
    3428 int nchgbdssave;
    3429
    3430 nchgbdssave = *nchgbds;
    3431
    3432 assert( ntotalvars > 0 );
    3433 SCIP_CALL( tightenVarsBoundsSOS1(scip, conshdlrdata, conflictgraph, implgraph, implhash, adjacencymatrix, totalvars, ntotalvars, nsos1vars, nchgbds, &implupdate, &cutoff) );
    3434 if ( *nchgbds > nchgbdssave )
    3435 {
    3436 *result = SCIP_SUCCESS;
    3437 if ( implupdate )
    3438 updateconfl = TRUE;
    3439 }
    3440 else if ( implupdate )
    3441 updateconfl = TRUE;
    3442 else
    3443 break;
    3444 }
    3445
    3446 /* perform implication graph analysis */
    3447 if ( updateconfl && conshdlrdata->perfimplanalysis && ! cutoff )
    3448 {
    3449 SCIP_Real* implubs;
    3450 SCIP_Real* impllbs;
    3451 SCIP_Bool* implnodes;
    3452 SCIP_Bool infeasible;
    3453 SCIP_Bool fixed;
    3454 int naddconsssave;
    3455 int probingdepth;
    3456
    3457 /* allocate buffer arrays */
    3458 SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) );
    3459 SCIP_CALL( SCIPallocBufferArray(scip, &impllbs, ntotalvars) );
    3460 SCIP_CALL( SCIPallocBufferArray(scip, &implubs, ntotalvars) );
    3461
    3462 naddconsssave = *naddconss;
    3463 for (i = 0; i < nsos1vars; ++i)
    3464 {
    3465 /* initialize data for implication graph analysis */
    3466 infeasible = FALSE;
    3467 probingdepth = 0;
    3468 for (j = 0; j < nsos1vars; ++j)
    3469 implnodes[j] = FALSE;
    3470 for (j = 0; j < ntotalvars; ++j)
    3471 {
    3472 impllbs[j] = SCIPvarGetLbLocal(totalvars[j]);
    3473 implubs[j] = SCIPvarGetUbLocal(totalvars[j]);
    3474 }
    3475
    3476 /* try to update the conflict graph based on the information of the implication graph */
    3477 SCIP_CALL( performImplicationGraphAnalysis(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, adjacencymatrix, i, i, impllbs, implubs, implnodes, naddconss, &probingdepth, &infeasible) );
    3478
    3479 /* if the subproblem turned out to be infeasible then fix variable to zero */
    3480 if ( infeasible )
    3481 {
    3482 SCIP_CALL( SCIPfixVar(scip, totalvars[i], 0.0, &infeasible, &fixed) );
    3483
    3484 if ( fixed )
    3485 {
    3486 SCIPdebugMsg(scip, "fixed variable %s with lower bound %f and upper bound %f to zero\n",
    3487 SCIPvarGetName(totalvars[i]), SCIPvarGetLbLocal(totalvars[i]), SCIPvarGetUbLocal(totalvars[i]));
    3488 ++(*nfixedvars);
    3489 }
    3490
    3491 if ( infeasible )
    3492 cutoff = TRUE;
    3493 }
    3494 }
    3495
    3496 if ( *naddconss > naddconsssave )
    3497 *result = SCIP_SUCCESS;
    3498
    3499 /* free buffer arrays */
    3500 SCIPfreeBufferArrayNull(scip, &implubs);
    3501 SCIPfreeBufferArrayNull(scip, &impllbs);
    3502 SCIPfreeBufferArrayNull(scip, &implnodes);
    3503 }
    3504
    3505 /* if an infeasibility has been detected */
    3506 if ( cutoff )
    3507 {
    3508 SCIPdebugMsg(scip, "cutoff \n");
    3509 *result = SCIP_CUTOFF;
    3510 }
    3511
    3512 /* free memory */;
    3513 for (j = ntotalvars-1; j >= 0; --j)
    3514 {
    3515 SCIP_SUCCDATA** succdatas;
    3516 int nsucc;
    3517 int s;
    3518
    3519 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, j);
    3520 nsucc = SCIPdigraphGetNSuccessors(implgraph, j);
    3521
    3522 for (s = nsucc-1; s >= 0; --s)
    3523 SCIPfreeBlockMemory(scip, &succdatas[s]);/*lint !e866*/
    3524 }
    3525 SCIPdigraphFree(&implgraph);
    3526 SCIPfreeBufferArrayNull(scip, &totalvars);
    3527 SCIPhashmapFree(&implhash);
    3528
    3529 return SCIP_OKAY;
    3530}
    3531
    3532
    3533/* ----------------------------- propagation -------------------------------------*/
    3534
    3535/** propagate variables of SOS1 constraint */
    3536static
    3538 SCIP* scip, /**< SCIP pointer */
    3539 SCIP_CONS* cons, /**< constraint */
    3540 SCIP_CONSDATA* consdata, /**< constraint data */
    3541 SCIP_Bool* cutoff, /**< whether a cutoff happened */
    3542 int* ngen /**< number of domain changes */
    3543 )
    3544{
    3545 assert( scip != NULL );
    3546 assert( cons != NULL );
    3547 assert( consdata != NULL );
    3548 assert( cutoff != NULL );
    3549 assert( ngen != NULL );
    3550
    3551 *cutoff = FALSE;
    3552
    3553 /* if more than one variable is fixed to be nonzero */
    3554 if ( consdata->nfixednonzeros > 1 )
    3555 {
    3556 SCIPdebugMsg(scip, "the node is infeasible, more than 1 variable is fixed to be nonzero.\n");
    3558 *cutoff = TRUE;
    3559 return SCIP_OKAY;
    3560 }
    3561
    3562 /* if exactly one variable is fixed to be nonzero */
    3563 if ( consdata->nfixednonzeros == 1 )
    3564 {
    3565 SCIP_VAR** vars;
    3566 SCIP_Bool infeasible;
    3567 SCIP_Bool tightened;
    3568 SCIP_Bool success;
    3569 SCIP_Bool allVarFixed;
    3570 int firstFixedNonzero;
    3571 int nvars;
    3572 int j;
    3573
    3574 firstFixedNonzero = -1;
    3575 nvars = consdata->nvars;
    3576 vars = consdata->vars;
    3577 assert( vars != NULL );
    3578
    3579 /* search nonzero variable - is needed for propinfo */
    3580 for (j = 0; j < nvars; ++j)
    3581 {
    3583 {
    3584 firstFixedNonzero = j;
    3585 break;
    3586 }
    3587 }
    3588 assert( firstFixedNonzero >= 0 );
    3589
    3590 SCIPdebugMsg(scip, "variable <%s> is fixed nonzero, fixing other variables to 0.\n", SCIPvarGetName(vars[firstFixedNonzero]));
    3591
    3592 /* fix variables before firstFixedNonzero to 0 */
    3593 allVarFixed = TRUE;
    3594 for (j = 0; j < firstFixedNonzero; ++j)
    3595 {
    3596 /* fix variable */
    3597 SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) );
    3598 assert( ! infeasible );
    3599 allVarFixed = allVarFixed && success;
    3600 if ( tightened )
    3601 ++(*ngen);
    3602 }
    3603
    3604 /* fix variables after firstFixedNonzero to 0 */
    3605 for (j = firstFixedNonzero+1; j < nvars; ++j)
    3606 {
    3607 /* fix variable */
    3608 SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) );
    3609 assert( ! infeasible ); /* there should be no variables after firstFixedNonzero that are fixed to be nonzero */
    3610 allVarFixed = allVarFixed && success;
    3611 if ( tightened )
    3612 ++(*ngen);
    3613 }
    3614
    3615 /* reset constraint age counter */
    3616 if ( *ngen > 0 )
    3617 {
    3619 }
    3620
    3621 /* delete constraint locally */
    3622 if ( allVarFixed )
    3623 {
    3624 assert( !SCIPconsIsModifiable(cons) );
    3626 }
    3627 }
    3628
    3629 return SCIP_OKAY;
    3630}
    3631
    3632
    3633/** propagate a variable that is known to be nonzero */
    3634static
    3636 SCIP* scip, /**< SCIP pointer */
    3637 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    3638 SCIP_DIGRAPH* implgraph, /**< implication graph */
    3639 SCIP_CONS* cons, /**< some arbitrary SOS1 constraint */
    3640 int node, /**< conflict graph node of variable that is known to be nonzero */
    3641 SCIP_Bool implprop, /**< whether implication graph propagation shall be applied */
    3642 SCIP_Bool* cutoff, /**< whether a cutoff happened */
    3643 int* ngen /**< number of domain changes */
    3644 )
    3645{
    3646 int inferinfo;
    3647 int* succ;
    3648 int nsucc;
    3649 int s;
    3650
    3651 assert( scip != NULL );
    3652 assert( conflictgraph != NULL );
    3653 assert( cutoff != NULL );
    3654 assert( ngen != NULL );
    3655 assert( node >= 0 );
    3656
    3657 *cutoff = FALSE;
    3658 inferinfo = -node - 1;
    3659
    3660 /* by assumption zero is outside the domain of variable */
    3662
    3663 /* apply conflict graph propagation (fix all neighbors in the conflict graph to zero) */
    3664 succ = SCIPdigraphGetSuccessors(conflictgraph, node);
    3665 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
    3666 for (s = 0; s < nsucc; ++s)
    3667 {
    3668 SCIP_VAR* succvar;
    3669 SCIP_Real lb;
    3670 SCIP_Real ub;
    3671
    3672 succvar = SCIPnodeGetVarSOS1(conflictgraph, succ[s]);
    3673 lb = SCIPvarGetLbLocal(succvar);
    3674 ub = SCIPvarGetUbLocal(succvar);
    3675
    3676 if ( ! SCIPisFeasZero(scip, lb) || ! SCIPisFeasZero(scip, ub) )
    3677 {
    3678 SCIP_Bool infeasible;
    3679 SCIP_Bool tightened;
    3680 SCIP_Bool success;
    3681
    3682 /* fix variable if it is not multi-aggregated */
    3683 SCIP_CALL( inferVariableZero(scip, succvar, cons, inferinfo, &infeasible, &tightened, &success) );
    3684
    3685 if ( infeasible )
    3686 {
    3687 /* variable cannot be nonzero */
    3688 *cutoff = TRUE;
    3689 return SCIP_OKAY;
    3690 }
    3691 if ( tightened )
    3692 ++(*ngen);
    3693 assert( success || SCIPvarGetStatus(succvar) == SCIP_VARSTATUS_MULTAGGR );
    3694 }
    3695 }
    3696
    3697 /* apply implication graph propagation */
    3698 if ( implprop && implgraph != NULL )
    3699 {
    3700 SCIP_SUCCDATA** succdatas;
    3701
    3702#ifndef NDEBUG
    3703 SCIP_NODEDATA* nodedbgdata;
    3704 nodedbgdata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, node);
    3705 assert( SCIPvarCompare(nodedbgdata->var, SCIPnodeGetVarSOS1(conflictgraph, node)) == 0 );
    3706#endif
    3707
    3708 /* get successor datas */
    3709 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, node);
    3710
    3711 if ( succdatas != NULL )
    3712 {
    3713 succ = SCIPdigraphGetSuccessors(implgraph, node);
    3714 nsucc = SCIPdigraphGetNSuccessors(implgraph, node);
    3715 for (s = 0; s < nsucc; ++s)
    3716 {
    3717 SCIP_SUCCDATA* succdata;
    3719 SCIP_VAR* var;
    3720
    3721 nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, succ[s]);
    3722 assert( nodedata != NULL );
    3723 succdata = succdatas[s];
    3724 assert( succdata != NULL );
    3725 var = nodedata->var;
    3726 assert( var != NULL );
    3727
    3728 /* tighten variable if it is not multi-aggregated */
    3730 {
    3731 /* check for lower bound implication */
    3732 if ( SCIPisFeasLT(scip, SCIPvarGetLbLocal(var), succdata->lbimpl) )
    3733 {
    3734 SCIP_Bool infeasible;
    3735 SCIP_Bool tightened;
    3736
    3737 SCIP_CALL( SCIPinferVarLbCons(scip, var, succdata->lbimpl, cons, inferinfo, FALSE, &infeasible, &tightened) );
    3738 if ( infeasible )
    3739 {
    3740 *cutoff = TRUE;
    3741 return SCIP_OKAY;
    3742 }
    3743 if ( tightened )
    3744 ++(*ngen);
    3745 }
    3746
    3747 /* check for upper bound implication */
    3748 if ( SCIPisFeasGT(scip, SCIPvarGetUbLocal(var), succdata->ubimpl) )
    3749 {
    3750 SCIP_Bool infeasible;
    3751 SCIP_Bool tightened;
    3752
    3753 SCIP_CALL( SCIPinferVarUbCons(scip, var, succdata->ubimpl, cons, inferinfo, FALSE, &infeasible, &tightened) );
    3754 if ( infeasible )
    3755 {
    3756 *cutoff = TRUE;
    3757 return SCIP_OKAY;
    3758 }
    3759 if ( tightened )
    3760 ++(*ngen);
    3761 }
    3762 }
    3763 }
    3764 }
    3765 }
    3766
    3767 return SCIP_OKAY;
    3768}
    3769
    3770
    3771/** initialize implication graph
    3772 *
    3773 * @p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$
    3774 *
    3775 * @note By construction the implication graph is globally valid.
    3776 */
    3777static
    3779 SCIP* scip, /**< SCIP pointer */
    3780 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    3781 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    3782 int nsos1vars, /**< number of SOS1 variables */
    3783 int maxrounds, /**< maximal number of propagation rounds for generating implications */
    3784 int* nchgbds, /**< pointer to store number of bound changes */
    3785 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff occurred */
    3786 SCIP_Bool* success /**< whether initialization was successful */
    3787 )
    3788{
    3789 SCIP_HASHMAP* implhash = NULL;
    3790 SCIP_Bool** adjacencymatrix = NULL;
    3791 SCIP_Bool* implnodes = NULL;
    3792 SCIP_VAR** implvars = NULL;
    3793 SCIP_VAR** probvars;
    3794 int nimplnodes;
    3795 int nprobvars;
    3796 int i;
    3797 int j;
    3798
    3799 assert( scip != NULL );
    3800 assert( conshdlrdata != NULL );
    3801 assert( conflictgraph != NULL );
    3802 assert( conshdlrdata->implgraph == NULL );
    3803 assert( conshdlrdata->nimplnodes == 0 );
    3804 assert( cutoff != NULL );
    3805 assert( nchgbds != NULL );
    3806
    3807 *nchgbds = 0;
    3808 *cutoff = FALSE;
    3809
    3810 /* we do not create the adjacency matrix of the conflict graph if the number of SOS1 variables is larger than a predefined value */
    3811 if ( conshdlrdata->maxsosadjacency != -1 && nsos1vars > conshdlrdata->maxsosadjacency )
    3812 {
    3813 *success = FALSE;
    3814 SCIPdebugMsg(scip, "Implication graph was not created since number of SOS1 variables (%d) is larger than %d.\n", nsos1vars, conshdlrdata->maxsosadjacency);
    3815
    3816 return SCIP_OKAY;
    3817 }
    3818 *success = TRUE;
    3819
    3820 /* only add globally valid implications to implication graph */
    3821 assert ( SCIPgetDepth(scip) == 0 );
    3822
    3823 probvars = SCIPgetVars(scip);
    3824 nprobvars = SCIPgetNVars(scip);
    3825 nimplnodes = 0;
    3826
    3827 /* create implication graph */
    3828 SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->implgraph, nsos1vars + nprobvars) );
    3829
    3830 /* create hashmap */
    3831 SCIP_CALL( SCIPhashmapCreate(&implhash, SCIPblkmem(scip), nsos1vars + nprobvars) );
    3832
    3833 /* determine implvars (union of SOS1 and problem variables)
    3834 * Note: For separation of implied bound cuts it is important that SOS1 variables are enumerated first
    3835 */
    3836 SCIP_CALL( SCIPallocBufferArray(scip, &implvars, nsos1vars + nprobvars) );
    3837 for (i = 0; i < nsos1vars; ++i)
    3838 {
    3839 SCIP_VAR* var;
    3840 var = SCIPnodeGetVarSOS1(conflictgraph, i);
    3841
    3842 /* insert node number to hash map */
    3843 assert( ! SCIPhashmapExists(implhash, var) );
    3844 SCIP_CALL( SCIPhashmapInsertInt(implhash, var, nimplnodes) );
    3845 assert( nimplnodes == SCIPhashmapGetImageInt(implhash, var) );
    3846 implvars[nimplnodes++] = var;
    3847 }
    3848
    3849 for (i = 0; i < nprobvars; ++i)
    3850 {
    3851 SCIP_VAR* var;
    3852 var = probvars[i];
    3853
    3854 /* insert node number to hash map if not existent */
    3855 if ( ! SCIPhashmapExists(implhash, var) )
    3856 {
    3857 SCIP_CALL( SCIPhashmapInsertInt(implhash, var, nimplnodes) );
    3858 assert( nimplnodes == SCIPhashmapGetImageInt(implhash, var) );
    3859 implvars[nimplnodes++] = var;
    3860 }
    3861 }
    3862 conshdlrdata->nimplnodes = nimplnodes;
    3863
    3864 /* add variables to nodes of implication graph */
    3865 for (i = 0; i < nimplnodes; ++i)
    3866 {
    3868
    3869 /* create node data */
    3871 nodedata->var = implvars[i];
    3872
    3873 /* set node data */
    3874 SCIPdigraphSetNodeData(conshdlrdata->implgraph, (void*) nodedata, i);
    3875 }
    3876
    3877 /* allocate buffer arrays */
    3878 SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) );
    3879 SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix, nsos1vars) );
    3880
    3881 for (i = 0; i < nsos1vars; ++i)
    3882 SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix[i], i+1) ); /*lint !e866*/
    3883
    3884 /* create adjacency matrix */
    3885 for (i = 0; i < nsos1vars; ++i)
    3886 {
    3887 for (j = 0; j < i+1; ++j)
    3888 adjacencymatrix[i][j] = 0;
    3889 }
    3890
    3891 for (i = 0; i < nsos1vars; ++i)
    3892 {
    3893 int* succ;
    3894 int nsucc;
    3895 succ = SCIPdigraphGetSuccessors(conflictgraph, i);
    3896 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
    3897
    3898 for (j = 0; j < nsucc; ++j)
    3899 {
    3900 if ( i > succ[j] )
    3901 adjacencymatrix[i][succ[j]] = 1;
    3902 }
    3903 }
    3904
    3905 assert( SCIPgetDepth(scip) == 0 );
    3906
    3907 /* compute SOS1 implications from linear constraints and tighten bounds of variables */
    3908 for (j = 0; (j < maxrounds || maxrounds == -1 ); ++j)
    3909 {
    3910 SCIP_Bool implupdate;
    3911 int nchgbdssave;
    3912
    3913 nchgbdssave = *nchgbds;
    3914
    3915 assert( nimplnodes > 0 );
    3916 SCIP_CALL( tightenVarsBoundsSOS1(scip, conshdlrdata, conflictgraph, conshdlrdata->implgraph, implhash, adjacencymatrix, implvars, nimplnodes, nsos1vars, nchgbds, &implupdate, cutoff) );
    3917 if ( *cutoff || ( ! implupdate && ! ( *nchgbds > nchgbdssave ) ) )
    3918 break;
    3919 }
    3920
    3921 /* free memory */
    3922 for (i = nsos1vars-1; i >= 0; --i)
    3923 SCIPfreeBufferArrayNull(scip, &adjacencymatrix[i]);
    3924 SCIPfreeBufferArrayNull(scip, &adjacencymatrix);
    3925 SCIPfreeBufferArrayNull(scip, &implnodes);
    3926 SCIPfreeBufferArrayNull(scip, &implvars);
    3927 SCIPhashmapFree(&implhash);
    3928
    3929#ifdef SCIP_DEBUG
    3930 /* evaluate results */
    3931 if ( cutoff )
    3932 {
    3933 SCIPdebugMsg(scip, "cutoff \n");
    3934 }
    3935 else if ( *nchgbds > 0 )
    3936 {
    3937 SCIPdebugMsg(scip, "found %d bound changes\n", *nchgbds);
    3938 }
    3939#endif
    3940
    3941 assert( conshdlrdata->implgraph != NULL );
    3942
    3943 return SCIP_OKAY;
    3944}
    3945
    3946
    3947/** deinitialize implication graph */
    3948static
    3950 SCIP* scip, /**< SCIP pointer */
    3951 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
    3952 )
    3953{
    3954 int j;
    3955
    3956 assert( scip != NULL );
    3957 assert( conshdlrdata != NULL );
    3958
    3959 /* free whole memory of implication graph */
    3960 if ( conshdlrdata->implgraph == NULL )
    3961 {
    3962 assert( conshdlrdata->nimplnodes == 0 );
    3963 return SCIP_OKAY;
    3964 }
    3965
    3966 /* free arc data */
    3967 for (j = conshdlrdata->nimplnodes-1; j >= 0; --j)
    3968 {
    3969 SCIP_SUCCDATA** succdatas;
    3970 int nsucc;
    3971 int s;
    3972
    3973 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(conshdlrdata->implgraph, j);
    3974 nsucc = SCIPdigraphGetNSuccessors(conshdlrdata->implgraph, j);
    3975
    3976 for (s = nsucc-1; s >= 0; --s)
    3977 {
    3978 assert( succdatas[s] != NULL );
    3979 SCIPfreeBlockMemory(scip, &succdatas[s]);/*lint !e866*/
    3980 }
    3981 }
    3982
    3983 /* free node data */
    3984 for (j = conshdlrdata->nimplnodes-1; j >= 0; --j)
    3985 {
    3987 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->implgraph, j);
    3988 assert( nodedata != NULL );
    3990 SCIPdigraphSetNodeData(conshdlrdata->implgraph, NULL, j);
    3991 }
    3992
    3993 /* free implication graph */
    3994 SCIPdigraphFree(&conshdlrdata->implgraph);
    3995 conshdlrdata->nimplnodes = 0;
    3996
    3997 return SCIP_OKAY;
    3998}
    3999
    4000
    4001/* ----------------------------- branching -------------------------------------*/
    4002
    4003/** get the vertices whose neighbor set covers a subset of the neighbor set of a given other vertex.
    4004 *
    4005 * This function can be used to compute sets of variables to branch on.
    4006 */
    4007static
    4009 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    4010 SCIP_Bool* verticesarefixed, /**< array that indicates which variables are currently fixed to zero */
    4011 int vertex, /**< vertex (-1 if not needed) */
    4012 int* neightocover, /**< neighbors of given vertex to be covered (or NULL if all neighbors shall be covered) */
    4013 int nneightocover, /**< number of entries of neightocover (or 0 if all neighbors shall be covered )*/
    4014 int* coververtices, /**< array to store the vertices whose neighbor set covers the neighbor set of the given vertex */
    4015 int* ncoververtices /**< pointer to store size of coververtices */
    4016 )
    4017{
    4018 int* succ1;
    4019 int nsucc1;
    4020 int s;
    4021
    4022 assert( conflictgraph != NULL );
    4023 assert( verticesarefixed != NULL );
    4024 assert( coververtices != NULL );
    4025 assert( ncoververtices != NULL );
    4026
    4027 *ncoververtices = 0;
    4028
    4029 /* if all the neighbors shall be covered */
    4030 if ( neightocover == NULL )
    4031 {
    4032 assert( nneightocover == 0 );
    4033 nsucc1 = SCIPdigraphGetNSuccessors(conflictgraph, vertex);
    4034 succ1 = SCIPdigraphGetSuccessors(conflictgraph, vertex);
    4035 }
    4036 else
    4037 {
    4038 nsucc1 = nneightocover;
    4039 succ1 = neightocover;
    4040 }
    4041
    4042 /* determine all the successors of the first unfixed successor */
    4043 for (s = 0; s < nsucc1; ++s)
    4044 {
    4045 int succvertex1 = succ1[s];
    4046
    4047 if ( ! verticesarefixed[succvertex1] )
    4048 {
    4049 int succvertex2;
    4050 int* succ2;
    4051 int nsucc2;
    4052 int j;
    4053
    4054 nsucc2 = SCIPdigraphGetNSuccessors(conflictgraph, succvertex1);
    4055 succ2 = SCIPdigraphGetSuccessors(conflictgraph, succvertex1);
    4056
    4057 /* for the first unfixed vertex */
    4058 if ( *ncoververtices == 0 )
    4059 {
    4060 for (j = 0; j < nsucc2; ++j)
    4061 {
    4062 succvertex2 = succ2[j];
    4063 if ( ! verticesarefixed[succvertex2] )
    4064 coververtices[(*ncoververtices)++] = succvertex2;
    4065 }
    4066 }
    4067 else
    4068 {
    4069 int vv = 0;
    4070 int k = 0;
    4071 int v;
    4072
    4073 /* determine all the successors that are in the set "coververtices" */
    4074 for (v = 0; v < *ncoververtices; ++v)
    4075 {
    4076 assert( vv <= v );
    4077 for (j = k; j < nsucc2; ++j)
    4078 {
    4079 succvertex2 = succ2[j];
    4080 if ( succvertex2 > coververtices[v] )
    4081 {
    4082 /* coververtices[v] does not appear in succ2 list, go to next vertex in coververtices */
    4083 k = j;
    4084 break;
    4085 }
    4086 else if ( succvertex2 == coververtices[v] )
    4087 {
    4088 /* vertices are equal, copy to free position vv */
    4089 coververtices[vv++] = succvertex2;
    4090 k = j + 1;
    4091 break;
    4092 }
    4093 }
    4094 }
    4095 /* store new size of coververtices */
    4096 *ncoververtices = vv;
    4097 }
    4098 }
    4099 }
    4100
    4101#ifdef SCIP_DEBUG
    4102 /* check sorting */
    4103 for (s = 0; s < *ncoververtices; ++s)
    4104 {
    4105 assert( *ncoververtices <= 1 || coververtices[*ncoververtices - 1] > coververtices[*ncoververtices - 2] );
    4106 }
    4107#endif
    4108
    4109 return SCIP_OKAY;
    4110}
    4111
    4112
    4113/** get vertices of variables that will be fixed to zero for each node */
    4114static
    4116 SCIP* scip, /**< SCIP pointer */
    4117 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    4118 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
    4119 SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zero */
    4120 SCIP_Bool bipbranch, /**< TRUE if bipartite branching method should be used */
    4121 int branchvertex, /**< branching vertex */
    4122 int* fixingsnode1, /**< vertices of variables that will be fixed to zero for the first node */
    4123 int* nfixingsnode1, /**< pointer to store number of fixed variables for the first node */
    4124 int* fixingsnode2, /**< vertices of variables that will be fixed to zero for the second node */
    4125 int* nfixingsnode2 /**< pointer to store number of fixed variables for the second node */
    4126 )
    4127{
    4128 SCIP_Bool takeallsucc; /* whether to set fixingsnode1 = neighbors of 'branchvertex' in the conflict graph */
    4129 int* succ;
    4130 int nsucc;
    4131 int j;
    4132
    4133 assert( scip != NULL );
    4134 assert( conflictgraph != NULL );
    4135 assert( verticesarefixed != NULL );
    4136 assert( ! verticesarefixed[branchvertex] );
    4137 assert( fixingsnode1 != NULL );
    4138 assert( fixingsnode2 != NULL );
    4139 assert( nfixingsnode1 != NULL );
    4140 assert( nfixingsnode2 != NULL );
    4141
    4142 *nfixingsnode1 = 0;
    4143 *nfixingsnode2 = 0;
    4144 takeallsucc = TRUE;
    4145
    4146 /* get successors and number of successors of branching vertex */
    4147 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, branchvertex);
    4148 succ = SCIPdigraphGetSuccessors(conflictgraph, branchvertex);
    4149
    4150 /* if bipartite branching method is turned on */
    4151 if ( bipbranch )
    4152 {
    4153 SCIP_Real solval;
    4154 int cnt = 0;
    4155
    4156 /* get all the neighbors of the variable with index 'branchvertex' whose solution value is nonzero */
    4157 for (j = 0; j < nsucc; ++j)
    4158 {
    4159 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, succ[j]))) )
    4160 {
    4161 assert( ! verticesarefixed[succ[j]] );
    4162 fixingsnode1[(*nfixingsnode1)++] = succ[j];
    4163 }
    4164 }
    4165
    4166 /* if one of the sets fixingsnode1 or fixingsnode2 contains only one variable with a nonzero LP value we perform standard neighborhood branching */
    4167 if ( *nfixingsnode1 > 0 )
    4168 {
    4169 /* get the vertices whose neighbor set cover the selected subset of the neighbors of the given branching vertex */
    4170 SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode1, *nfixingsnode1, fixingsnode2, nfixingsnode2) );
    4171
    4172 /* determine the intersection of the neighbors of branchvertex with the intersection of all the neighbors of fixingsnode2 */
    4173 SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode2, *nfixingsnode2, fixingsnode1, nfixingsnode1) );
    4174
    4175 for (j = 0; j < *nfixingsnode2; ++j)
    4176 {
    4177 solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]));
    4178 if( ! SCIPisFeasZero(scip, solval) )
    4179 ++cnt;
    4180 }
    4181
    4182 /* we decide whether to use all successors if one partition of complete bipartite subgraph has only one node */
    4183 if ( cnt >= 2 )
    4184 {
    4185 cnt = 0;
    4186 for (j = 0; j < *nfixingsnode1; ++j)
    4187 {
    4188 solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]));
    4189 if( ! SCIPisFeasZero(scip, solval) )
    4190 ++cnt;
    4191 }
    4192
    4193 if ( cnt >= 2 )
    4194 takeallsucc = FALSE;
    4195 }
    4196 }
    4197 }
    4198
    4199 if ( takeallsucc )
    4200 {
    4201 /* get all the unfixed neighbors of the branching vertex */
    4202 *nfixingsnode1 = 0;
    4203 for (j = 0; j < nsucc; ++j)
    4204 {
    4205 if ( ! verticesarefixed[succ[j]] )
    4206 fixingsnode1[(*nfixingsnode1)++] = succ[j];
    4207 }
    4208
    4209 if ( bipbranch )
    4210 {
    4211 /* get the vertices whose neighbor set covers the neighbor set of a given branching vertex */
    4212 SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode1, *nfixingsnode1, fixingsnode2, nfixingsnode2) );
    4213 }
    4214 else
    4215 {
    4216 /* use neighborhood branching, i.e, for the second node only the branching vertex can be fixed */
    4217 fixingsnode2[0] = branchvertex;
    4218 *nfixingsnode2 = 1;
    4219 }
    4220 }
    4221
    4222 return SCIP_OKAY;
    4223}
    4224
    4225
    4226/** gets branching priorities for SOS1 variables and applies 'most infeasible selection' rule to determine a vertex for the next branching decision */
    4227static
    4229 SCIP* scip, /**< SCIP pointer */
    4230 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    4231 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    4232 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
    4233 int nsos1vars, /**< number of SOS1 variables */
    4234 SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zero */
    4235 SCIP_Bool bipbranch, /**< TRUE if bipartite branching method should be used */
    4236 int* fixingsnode1, /**< vertices of variables that will be fixed to zero for the first node (size = nsos1vars) */
    4237 int* fixingsnode2, /**< vertices of variables that will be fixed to zero for the second node (size = nsos1vars) */
    4238 SCIP_Real* branchpriors, /**< pointer to store branching priorities (size = nsos1vars) or NULL if not needed */
    4239 int* vertexbestprior, /**< pointer to store vertex with the best branching priority or NULL if not needed */
    4240 SCIP_Bool* relsolfeas /**< pointer to store if LP relaxation solution is feasible */
    4241 )
    4242{
    4243 SCIP_Real bestprior;
    4244 int i;
    4245
    4246 assert( scip != NULL );
    4247 assert( conshdlrdata != NULL );
    4248 assert( conflictgraph != NULL );
    4249 assert( verticesarefixed != NULL );
    4250 assert( fixingsnode1 != NULL );
    4251 assert( fixingsnode2 != NULL );
    4252 assert( relsolfeas != NULL );
    4253
    4254 bestprior = -SCIPinfinity(scip);
    4255
    4256 /* make sure data is initialized */
    4257 if ( vertexbestprior != NULL )
    4258 *vertexbestprior = -1;
    4259
    4260 for (i = 0; i < nsos1vars; ++i)
    4261 {
    4262 SCIP_Real prior;
    4263 SCIP_Real solval;
    4264 int nfixingsnode1;
    4265 int nfixingsnode2;
    4266 int nsucc;
    4267 int j;
    4268
    4269 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
    4270
    4271 if ( nsucc == 0 || SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, i))) || verticesarefixed[i] )
    4272 prior = -SCIPinfinity(scip);
    4273 else
    4274 {
    4275 SCIP_Bool iszero1 = TRUE;
    4276 SCIP_Bool iszero2 = TRUE;
    4277 SCIP_Real sum1 = 0.0;
    4278 SCIP_Real sum2 = 0.0;
    4279
    4280 /* get vertices of variables that will be fixed to zero for each strong branching execution */
    4281 assert( ! verticesarefixed[i] );
    4282 SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, sol, verticesarefixed, bipbranch, i, fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) );
    4283
    4284 for (j = 0; j < nfixingsnode1; ++j)
    4285 {
    4286 solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]));
    4287 if ( ! SCIPisFeasZero(scip, solval) )
    4288 {
    4289 sum1 += REALABS( solval );
    4290 iszero1 = FALSE;
    4291 }
    4292 }
    4293
    4294 for (j = 0; j < nfixingsnode2; ++j)
    4295 {
    4296 solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]));
    4297 if ( ! SCIPisFeasZero(scip, solval) )
    4298 {
    4299 sum2 += REALABS( solval );
    4300 iszero2 = FALSE;
    4301 }
    4302 }
    4303
    4304 if ( iszero1 || iszero2 )
    4305 prior = -SCIPinfinity(scip);
    4306 else
    4307 prior = sum1 * sum2;
    4308 }
    4309
    4310 if ( branchpriors != NULL )
    4311 branchpriors[i] = prior;
    4312 if ( bestprior < prior )
    4313 {
    4314 bestprior = prior;
    4315
    4316 if ( vertexbestprior != NULL )
    4317 *vertexbestprior = i;
    4318 }
    4319 }
    4320
    4321 if ( SCIPisInfinity(scip, -bestprior) )
    4322 *relsolfeas = TRUE;
    4323 else
    4324 *relsolfeas = FALSE;
    4325
    4326 return SCIP_OKAY;
    4327}
    4328
    4329
    4330/** performs strong branching with given domain fixings */
    4331static
    4333 SCIP* scip, /**< SCIP pointer */
    4334 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    4335 int* fixingsexec, /**< vertices of variables to be fixed to zero for this strong branching execution */
    4336 int nfixingsexec, /**< number of vertices of variables to be fixed to zero for this strong branching execution */
    4337 int* fixingsop, /**< vertices of variables to be fixed to zero for the opposite strong branching execution */
    4338 int nfixingsop, /**< number of vertices of variables to be fixed to zero for the opposite strong branching execution */
    4339 int inititer, /**< maximal number of LP iterations to perform */
    4340 SCIP_Bool fixnonzero, /**< shall opposite variable (if positive in sign) fixed to the feasibility tolerance
    4341 * (only possible if nfixingsop = 1) */
    4342 int* domainfixings, /**< vertices that can be used to reduce the domain (should have size equal to number of variables) */
    4343 int* ndomainfixings, /**< pointer to store number of vertices that can be used to reduce the domain, could be filled by earlier calls */
    4344 SCIP_Bool* infeasible, /**< pointer to store whether branch is infeasible */
    4345 SCIP_Real* objval, /**< pointer to store objective value of LP with fixed variables (SCIP_INVALID if reddomain = TRUE or lperror = TRUE) */
    4346 SCIP_Bool* lperror /**< pointer to store whether an unresolved LP error or a strange solution status occurred */
    4347 )
    4348{
    4349 SCIP_LPSOLSTAT solstat;
    4350 int i;
    4351
    4352 assert( scip != NULL );
    4353 assert( conflictgraph != NULL );
    4354 assert( fixingsexec != NULL );
    4355 assert( nfixingsop > 0 );
    4356 assert( fixingsop != NULL );
    4357 assert( nfixingsop > 0 );
    4358 assert( inititer >= -1 );
    4359 assert( domainfixings != NULL );
    4360 assert( ndomainfixings != NULL );
    4361 assert( *ndomainfixings >= 0 );
    4362 assert( infeasible != NULL );
    4363 assert( objval != NULL );
    4364 assert( lperror != NULL );
    4365
    4366 *objval = SCIP_INVALID; /* for debugging */
    4367 *lperror = FALSE;
    4368 *infeasible = FALSE;
    4369
    4370 /* start probing */
    4372
    4373 /* perform domain fixings */
    4374 if ( fixnonzero && nfixingsop == 1 )
    4375 {
    4376 SCIP_VAR* var;
    4377 SCIP_Real lb;
    4378 SCIP_Real ub;
    4379
    4380 var = SCIPnodeGetVarSOS1(conflictgraph, fixingsop[0]);
    4381 lb = SCIPvarGetLbLocal(var);
    4382 ub = SCIPvarGetUbLocal(var);
    4383
    4385 {
    4386 if ( SCIPisZero(scip, lb) )
    4387 {
    4388 /* fix variable to some very small, but positive number or to 1.0 if variable is integral */
    4389 if (SCIPvarIsIntegral(var) )
    4390 {
    4391 SCIP_CALL( SCIPchgVarLbProbing(scip, var, 1.0) );
    4392 }
    4393 else
    4394 {
    4396 }
    4397 }
    4398 else if ( SCIPisZero(scip, ub) )
    4399 {
    4400 /* fix variable to some negative number with small absolute value or to -1.0 if variable is integral */
    4401 if (SCIPvarIsIntegral(var) )
    4402 {
    4403 SCIP_CALL( SCIPchgVarUbProbing(scip, var, -1.0) );
    4404 }
    4405 else
    4406 {
    4408 }
    4409 }
    4410 }
    4411 }
    4412
    4413 /* injects variable fixings into current probing node */
    4414 for (i = 0; i < nfixingsexec && ! *infeasible; ++i)
    4415 {
    4416 SCIP_VAR* var;
    4417
    4418 var = SCIPnodeGetVarSOS1(conflictgraph, fixingsexec[i]);
    4419 if ( SCIPisFeasGT(scip, SCIPvarGetLbLocal(var), 0.0) || SCIPisFeasLT(scip, SCIPvarGetUbLocal(var), 0.0) )
    4420 *infeasible = TRUE;
    4421 else
    4422 {
    4423 SCIP_CALL( SCIPfixVarProbing(scip, var, 0.0) );
    4424 }
    4425 }
    4426
    4427 /* apply domain propagation */
    4428 if ( ! *infeasible )
    4429 {
    4430 SCIP_CALL( SCIPpropagateProbing(scip, 0, infeasible, NULL) );
    4431 }
    4432
    4433 if ( *infeasible )
    4434 solstat = SCIP_LPSOLSTAT_INFEASIBLE;
    4435 else
    4436 {
    4437 /* solve the probing LP */
    4438 SCIP_CALL( SCIPsolveProbingLP(scip, inititer, lperror, NULL) );
    4439 if ( *lperror )
    4440 {
    4442 return SCIP_OKAY;
    4443 }
    4444
    4445 /* get solution status */
    4446 solstat = SCIPgetLPSolstat(scip);
    4447 }
    4448
    4449 /* if objective limit was reached, then the domain can be reduced */
    4450 if ( solstat == SCIP_LPSOLSTAT_OBJLIMIT || solstat == SCIP_LPSOLSTAT_INFEASIBLE )
    4451 {
    4452 *infeasible = TRUE;
    4453
    4454 for (i = 0; i < nfixingsop; ++i)
    4455 domainfixings[(*ndomainfixings)++] = fixingsop[i];
    4456 }
    4457 else if ( solstat == SCIP_LPSOLSTAT_OPTIMAL || solstat == SCIP_LPSOLSTAT_TIMELIMIT || solstat == SCIP_LPSOLSTAT_ITERLIMIT )
    4458 {
    4459 /* get objective value of probing LP */
    4460 *objval = SCIPgetLPObjval(scip);
    4461 }
    4462 else
    4463 *lperror = TRUE;
    4464
    4465 /* end probing */
    4467
    4468 return SCIP_OKAY;
    4469}
    4470
    4471
    4472/** apply strong branching to determine the vertex for the next branching decision */
    4473static
    4475 SCIP* scip, /**< SCIP pointer */
    4476 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */
    4477 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    4478 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
    4479 int nsos1vars, /**< number of SOS1 variables */
    4480 SCIP_Real lpobjval, /**< current LP relaxation solution */
    4481 SCIP_Bool bipbranch, /**< TRUE if bipartite branching method should be used */
    4482 int nstrongrounds, /**< number of strong branching rounds */
    4483 SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zero */
    4484 int* fixingsnode1, /**< pointer to store vertices of variables that will be fixed to zero for the first node (size = nsos1vars) */
    4485 int* fixingsnode2, /**< pointer to store vertices of variables that will be fixed to zero for the second node (size = nsos1vars) */
    4486 int* vertexbestprior, /**< pointer to store vertex with the best strong branching priority */
    4487 SCIP_Real* bestobjval1, /**< pointer to store LP objective for left child node of branching decision with best priority */
    4488 SCIP_Real* bestobjval2, /**< pointer to store LP objective for right child node of branching decision with best priority */
    4489 SCIP_RESULT* result /**< pointer to store result of strong branching */
    4490 )
    4491{
    4492 SCIP_Real* branchpriors = NULL;
    4493 int* indsos1vars = NULL;
    4494 int* domainfixings = NULL;
    4495 int ndomainfixings;
    4496 int nfixingsnode1;
    4497 int nfixingsnode2;
    4498
    4499 SCIP_Bool relsolfeas;
    4500 SCIP_Real bestscore;
    4501 int lastscorechange;
    4502 int maxfailures;
    4503
    4504 SCIP_Longint nlpiterations;
    4505 SCIP_Longint nlps;
    4506 int inititer;
    4507 int j;
    4508 int i;
    4509
    4510 assert( scip != NULL );
    4511 assert( conshdlrdata != NULL );
    4512 assert( conflictgraph != NULL );
    4513 assert( verticesarefixed != NULL );
    4514 assert( fixingsnode1 != NULL );
    4515 assert( fixingsnode2 != NULL );
    4516 assert( vertexbestprior != NULL );
    4517 assert( result != NULL );
    4518
    4519 /* allocate buffer arrays */
    4520 SCIP_CALL( SCIPallocBufferArray(scip, &branchpriors, nsos1vars) );
    4521
    4522 /* get branching priorities */
    4523 SCIP_CALL( getBranchingPrioritiesSOS1(scip, conshdlrdata, conflictgraph, sol, nsos1vars, verticesarefixed,
    4524 bipbranch, fixingsnode1, fixingsnode2, branchpriors, NULL, &relsolfeas) );
    4525
    4526 /* if LP relaxation solution is feasible */
    4527 if ( relsolfeas )
    4528 {
    4529 SCIPdebugMsg(scip, "all the SOS1 constraints are feasible.\n");
    4530 *vertexbestprior = -1;
    4531 *result = SCIP_FEASIBLE;
    4532
    4533 /* free memory */
    4534 SCIPfreeBufferArrayNull(scip, &branchpriors);
    4535
    4536 return SCIP_OKAY;
    4537 }
    4538
    4539 /* allocate buffer arrays */
    4540 SCIP_CALL( SCIPallocBufferArray(scip, &indsos1vars, nsos1vars) );
    4541 SCIP_CALL( SCIPallocBufferArray(scip, &domainfixings, nsos1vars) );
    4542
    4543 /* sort branching priorities (descending order) */
    4544 for (j = 0; j < nsos1vars; ++j)
    4545 indsos1vars[j] = j;
    4546 SCIPsortDownRealInt(branchpriors, indsos1vars, nsos1vars);
    4547
    4548 /* determine the number of LP iterations to perform in each strong branch */
    4549 nlpiterations = SCIPgetNDualResolveLPIterations(scip);
    4551 if ( nlps == 0 )
    4552 {
    4553 nlpiterations = SCIPgetNNodeInitLPIterations(scip);
    4554 nlps = SCIPgetNNodeInitLPs(scip);
    4555 if ( nlps == 0 )
    4556 {
    4557 nlpiterations = 1000;
    4558 nlps = 1;
    4559 }
    4560 }
    4561 assert(nlps >= 1);
    4562
    4563 /* compute number of LP iterations performed per strong branching iteration */
    4564 if ( conshdlrdata->nstrongiter == -2 )
    4565 {
    4566 inititer = (int)(2*nlpiterations / nlps);
    4567 inititer = (int)((SCIP_Real)inititer * (1.0 + 20.0/SCIPgetNNodes(scip)));
    4568 inititer = MAX(inititer, 10);
    4569 inititer = MIN(inititer, 500);
    4570 }
    4571 else
    4572 inititer = conshdlrdata->nstrongiter;
    4573
    4574 /* get current LP relaxation solution */
    4575 lpobjval = SCIPgetLPObjval(scip);
    4576
    4577 /* determine branching variable by strong branching or reduce domain */
    4578 ndomainfixings = 0;
    4579 lastscorechange = -1;
    4580 assert( nsos1vars > 0 );
    4581 *vertexbestprior = indsos1vars[0]; /* for the case that nstrongrounds = 0 */
    4582 bestscore = -SCIPinfinity(scip);
    4583 *bestobjval1 = -SCIPinfinity(scip);
    4584 *bestobjval2 = -SCIPinfinity(scip);
    4585 maxfailures = nstrongrounds;
    4586
    4587 /* for each strong branching round */
    4588 for (j = 0; j < nstrongrounds; ++j)
    4589 {
    4590 int testvertex;
    4591
    4592 /* get branching vertex for the current strong branching iteration */
    4593 testvertex = indsos1vars[j];
    4594
    4595 /* if variable with index 'vertex' does not violate any complementarity in its neighborhood for the current LP relaxation solution */
    4596 if ( SCIPisPositive(scip, branchpriors[j]) )
    4597 {
    4598 SCIP_Bool infeasible1;
    4599 SCIP_Bool infeasible2;
    4600 SCIP_Bool lperror;
    4601 SCIP_Real objval1;
    4602 SCIP_Real objval2;
    4603 SCIP_Real score;
    4604
    4605 /* get vertices of variables that will be fixed to zero for each strong branching execution */
    4606 assert( ! verticesarefixed[testvertex] );
    4607 SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, sol, verticesarefixed, bipbranch, testvertex,
    4608 fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) );
    4609
    4610 /* get information for first strong branching execution */
    4611 SCIP_CALL( performStrongbranchSOS1(scip, conflictgraph, fixingsnode1, nfixingsnode1, fixingsnode2, nfixingsnode2,
    4612 inititer, conshdlrdata->fixnonzero, domainfixings, &ndomainfixings, &infeasible1, &objval1, &lperror) );
    4613 if ( lperror )
    4614 continue;
    4615
    4616 /* get information for second strong branching execution */
    4617 SCIP_CALL( performStrongbranchSOS1(scip, conflictgraph, fixingsnode2, nfixingsnode2, fixingsnode1, nfixingsnode1,
    4618 inititer, FALSE, domainfixings, &ndomainfixings, &infeasible2, &objval2, &lperror) );
    4619 if ( lperror )
    4620 continue;
    4621
    4622 /* if both subproblems are infeasible */
    4623 if ( infeasible1 && infeasible2 )
    4624 {
    4625 SCIPdebugMsg(scip, "detected cutoff.\n");
    4626
    4627 /* update result */
    4628 *result = SCIP_CUTOFF;
    4629
    4630 /* free memory */
    4631 SCIPfreeBufferArrayNull(scip, &domainfixings);
    4632 SCIPfreeBufferArrayNull(scip, &indsos1vars);
    4633 SCIPfreeBufferArrayNull(scip, &branchpriors);
    4634
    4635 return SCIP_OKAY;
    4636 }
    4637 else if ( ! infeasible1 && ! infeasible2 ) /* both subproblems are feasible */
    4638 {
    4639 /* if domain has not been reduced in this for-loop */
    4640 if ( ndomainfixings == 0 )
    4641 {
    4642 score = MAX( REALABS(objval1 - lpobjval), SCIPfeastol(scip) ) * MAX( REALABS(objval2 - lpobjval), SCIPfeastol(scip) );/*lint !e666*/
    4643
    4644 if ( SCIPisPositive(scip, score - bestscore) )
    4645 {
    4646 bestscore = score;
    4647 *vertexbestprior = testvertex;
    4648 *bestobjval1 = objval1;
    4649 *bestobjval2 = objval2;
    4650
    4651 lastscorechange = j;
    4652 }
    4653 else if ( j - lastscorechange > maxfailures )
    4654 break;
    4655 }
    4656 }
    4657 }
    4658 }
    4659
    4660 /* if variable fixings have been detected by probing, then reduce domain */
    4661 if ( ndomainfixings > 0 )
    4662 {
    4664 SCIP_Bool infeasible;
    4665
    4666 for (i = 0; i < ndomainfixings; ++i)
    4667 {
    4668 SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, domainfixings[i]), node, &infeasible) );
    4669 assert( ! infeasible );
    4670 }
    4671
    4672 SCIPdebugMsg(scip, "found %d domain fixings.\n", ndomainfixings);
    4673
    4674 /* update result */
    4675 *result = SCIP_REDUCEDDOM;
    4676 }
    4677
    4678 /* free buffer arrays */
    4679 SCIPfreeBufferArrayNull(scip, &domainfixings);
    4680 SCIPfreeBufferArrayNull(scip, &indsos1vars);
    4681 SCIPfreeBufferArrayNull(scip, &branchpriors);
    4682
    4683 return SCIP_OKAY;
    4684}
    4685
    4686
    4687/** for two given vertices @p v1 and @p v2 search for a clique in the conflict graph that contains these vertices. From
    4688 * this clique, we create a bound constraint.
    4689 */
    4690static
    4692 SCIP* scip, /**< SCIP pointer */
    4693 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    4694 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
    4695 int v1, /**< first vertex that shall be contained in bound constraint */
    4696 int v2, /**< second vertex that shall be contained in bound constraint */
    4697 SCIP_VAR* boundvar, /**< bound variable of @p v1 and @p v2 (or NULL if not existent) */
    4698 SCIP_Bool extend, /**< should @p v1 and @p v2 be greedily extended to a clique of larger size */
    4699 SCIP_CONS* cons, /**< bound constraint */
    4700 SCIP_Real* feas /**< feasibility value of bound constraint */
    4701 )
    4702{
    4704 SCIP_Bool addv2 = TRUE;
    4705 SCIP_Real solval;
    4706 SCIP_VAR* var;
    4707 SCIP_Real coef = 0.0;
    4708 int nsucc;
    4709 int s;
    4710
    4711 int* extensions = NULL;
    4712 int nextensions = 0;
    4713 int nextensionsnew;
    4714 int* succ;
    4715
    4716 assert( scip != NULL );
    4717 assert( conflictgraph != NULL );
    4718 assert( cons != NULL );
    4719 assert( feas != NULL );
    4720
    4721 *feas = 0.0;
    4722
    4723 /* add index 'v1' to the clique */
    4724 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, v1);
    4725 var = nodedata->var;
    4726 assert( boundvar == NULL || SCIPvarCompare(boundvar, nodedata->ubboundvar) == 0 );
    4727 solval = SCIPgetSolVal(scip, sol, var);
    4728
    4729 /* if 'v1' and 'v2' have the same bound variable then the bound cut can be strengthened */
    4730 if ( boundvar == NULL )
    4731 {
    4732 if ( SCIPisFeasPositive(scip, solval) )
    4733 {
    4734 SCIP_Real ub;
    4735 ub = SCIPvarGetUbLocal(var);
    4736 assert( SCIPisFeasPositive(scip, ub));
    4737
    4738 if ( ! SCIPisInfinity(scip, ub) )
    4739 coef = 1.0/ub;
    4740 }
    4741 else if ( SCIPisFeasNegative(scip, solval) )
    4742 {
    4743 SCIP_Real lb;
    4744 lb = SCIPvarGetLbLocal(var);
    4745 assert( SCIPisFeasNegative(scip, lb) );
    4746 if ( ! SCIPisInfinity(scip, -lb) )
    4747 coef = 1.0/lb;
    4748 }
    4749 }
    4750 else if ( boundvar == nodedata->ubboundvar )
    4751 {
    4752 if ( SCIPisFeasPositive(scip, solval) )
    4753 {
    4754 SCIP_Real ub;
    4755
    4756 ub = nodedata->ubboundcoef;
    4757 assert( SCIPisFeasPositive(scip, ub) );
    4758 if ( ! SCIPisInfinity(scip, ub) )
    4759 coef = 1.0/ub;
    4760 }
    4761 else if ( SCIPisFeasNegative(scip, solval) )
    4762 {
    4763 SCIP_Real lb;
    4764
    4765 lb = nodedata->lbboundcoef;
    4766 assert( SCIPisFeasPositive(scip, lb) );
    4767 if ( ! SCIPisInfinity(scip, lb) )
    4768 coef = 1.0/lb;
    4769 }
    4770 }
    4771
    4772 if ( ! SCIPisZero(scip, coef) )
    4773 {
    4774 *feas += coef * solval;
    4775 SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, coef) );
    4776 }
    4777
    4778 /* if clique shall be greedily extended to a clique of larger size */
    4779 if ( extend )
    4780 {
    4781 /* get successors */
    4782 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, v1);
    4783 succ = SCIPdigraphGetSuccessors(conflictgraph, v1);
    4784 assert( nsucc > 0 );
    4785
    4786 /* allocate buffer array */
    4787 SCIP_CALL( SCIPallocBufferArray(scip, &extensions, nsucc) );
    4788
    4789 /* get possible extensions for the clique cover */
    4790 for (s = 0; s < nsucc; ++s)
    4791 extensions[s] = succ[s];
    4792 nextensions = nsucc;
    4793 }
    4794 else
    4795 nextensions = 1;
    4796
    4797 /* while there exist possible extensions for the clique cover */
    4798 while ( nextensions > 0 )
    4799 {
    4800 SCIP_Real bestbigMval;
    4801 SCIP_Real bigMval;
    4802 int bestindex = -1;
    4803 int ext;
    4804
    4805 bestbigMval = -SCIPinfinity(scip);
    4806
    4807 /* if v2 has not been added to clique already */
    4808 if ( addv2 )
    4809 {
    4810 bestindex = v2;
    4811 addv2 = FALSE;
    4812 }
    4813 else /* search for the extension with the largest absolute value of its LP relaxation solution value */
    4814 {
    4815 assert( extensions != NULL );
    4816 for (s = 0; s < nextensions; ++s)
    4817 {
    4818 ext = extensions[s];
    4819 bigMval = nodeGetSolvalBinaryBigMSOS1(scip, conflictgraph, sol, ext);
    4820 if ( SCIPisFeasLT(scip, bestbigMval, bigMval) )
    4821 {
    4822 bestbigMval = bigMval;
    4823 bestindex = ext;
    4824 }
    4825 }
    4826 }
    4827 assert( bestindex != -1 );
    4828
    4829 /* add bestindex variable to the constraint */
    4830 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, bestindex);
    4831 var = nodedata->var;
    4832 solval = SCIPgetSolVal(scip, sol, var);
    4833 coef = 0.0;
    4834 if ( boundvar == NULL )
    4835 {
    4836 if ( SCIPisFeasPositive(scip, solval) )
    4837 {
    4838 SCIP_Real ub;
    4839 ub = SCIPvarGetUbLocal(var);
    4840 assert( SCIPisFeasPositive(scip, ub));
    4841
    4842 if ( ! SCIPisInfinity(scip, ub) )
    4843 coef = 1.0/ub;
    4844 }
    4845 else if ( SCIPisFeasNegative(scip, solval) )
    4846 {
    4847 SCIP_Real lb;
    4848 lb = SCIPvarGetLbLocal(var);
    4849 assert( SCIPisFeasNegative(scip, lb) );
    4850 if ( ! SCIPisInfinity(scip, -lb) )
    4851 coef = 1.0/lb;
    4852 }
    4853 }
    4854 else if ( boundvar == nodedata->ubboundvar )
    4855 {
    4856 if ( SCIPisFeasPositive(scip, solval) )
    4857 {
    4858 SCIP_Real ub;
    4859
    4860 ub = nodedata->ubboundcoef;
    4861 assert( SCIPisFeasPositive(scip, ub) );
    4862 if ( ! SCIPisInfinity(scip, ub) )
    4863 coef = 1.0/ub;
    4864 }
    4865 else if ( SCIPisFeasNegative(scip, solval) )
    4866 {
    4867 SCIP_Real lb;
    4868
    4869 lb = nodedata->lbboundcoef;
    4870 assert( SCIPisFeasPositive(scip, lb) );
    4871 if ( ! SCIPisInfinity(scip, -lb) )
    4872 coef = 1.0/lb;
    4873 }
    4874 }
    4875 if ( ! SCIPisZero(scip, coef) )
    4876 {
    4877 *feas += coef * solval;
    4878 SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, coef) );
    4879 }
    4880
    4881 if ( extend )
    4882 {
    4883 assert( extensions != NULL );
    4884 /* compute new 'extensions' array */
    4885 nextensionsnew = 0;
    4886 for (s = 0; s < nextensions; ++s)
    4887 {
    4888 if ( s != bestindex && isConnectedSOS1(NULL, conflictgraph, bestindex, extensions[s]) )
    4889 extensions[nextensionsnew++] = extensions[s];
    4890 }
    4891 nextensions = nextensionsnew;
    4892 }
    4893 else
    4894 nextensions = 0;
    4895 }
    4896
    4897 /* free buffer array */
    4898 if ( extend )
    4899 SCIPfreeBufferArray(scip, &extensions);
    4900
    4901 /* subtract rhs of constraint from feasibility value or add bound variable if existent */
    4902 if ( boundvar == NULL )
    4903 *feas -= 1.0;
    4904 else
    4905 {
    4906 SCIP_CALL( SCIPaddCoefLinear(scip, cons, boundvar, -1.0) );
    4907 *feas -= SCIPgetSolVal(scip, sol, boundvar);
    4908 }
    4909
    4910 return SCIP_OKAY;
    4911}
    4912
    4913
    4914/** tries to add feasible complementarity constraints to a given child branching node.
    4915 *
    4916 * @note In this function the conflict graph is updated to the conflict graph of the considered child branching node.
    4917 */
    4918static
    4920 SCIP* scip, /**< SCIP pointer */
    4921 SCIP_NODE* node, /**< branching node */
    4922 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    4923 SCIP_DIGRAPH* conflictgraph, /**< conflict graph of the current node */
    4924 SCIP_DIGRAPH* localconflicts, /**< local conflicts (updates to local conflicts of child node) */
    4925 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
    4926 int nsos1vars, /**< number of SOS1 variables */
    4927 SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zerox */
    4928 int* fixingsnode1, /**< vertices of variables that will be fixed to zero for the branching node in the input of this function */
    4929 int nfixingsnode1, /**< number of entries of array nfixingsnode1 */
    4930 int* fixingsnode2, /**< vertices of variables that will be fixed to zero for the other branching node */
    4931 int nfixingsnode2, /**< number of entries of array nfixingsnode2 */
    4932 int* naddedconss, /**< pointer to store the number of added SOS1 constraints */
    4933 SCIP_Bool onlyviolsos1 /**< should only SOS1 constraints be added that are violated by the LP solution */
    4934 )
    4935{
    4936 assert( scip != NULL );
    4937 assert( node != NULL );
    4938 assert( conshdlrdata != NULL );
    4939 assert( conflictgraph != NULL );
    4940 assert( verticesarefixed != NULL );
    4941 assert( fixingsnode1 != NULL );
    4942 assert( fixingsnode2 != NULL );
    4943 assert( naddedconss != NULL );
    4944
    4945 *naddedconss = 0;
    4946
    4947 if ( nfixingsnode2 > 1 )
    4948 {
    4949 int* fixingsnode21; /* first partition of fixingsnode2 */
    4950 int* fixingsnode22; /* second partition of fixingsnode2 */
    4951 int nfixingsnode21;
    4952 int nfixingsnode22;
    4953
    4954 int* coverarray; /* vertices, not in fixingsnode1 that cover all the vertices in array fixingsnode22 */
    4955 int ncoverarray;
    4956
    4957 SCIP_Bool* mark;
    4958 int* succarray;
    4959 int nsuccarray;
    4960 int* succ;
    4961 int nsucc;
    4962
    4963 int i;
    4964 int s;
    4965
    4966 /* allocate buffer arrays */
    4967 SCIP_CALL( SCIPallocBufferArray(scip, &succarray, nsos1vars) );
    4968 SCIP_CALL( SCIPallocBufferArray(scip, &mark, nsos1vars) );
    4969 SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode21, nfixingsnode2) );
    4970 SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode22, nfixingsnode2) );
    4971
    4972 /* mark all the unfixed vertices with FALSE */
    4973 for (i = 0; i < nsos1vars; ++i)
    4974 mark[i] = (verticesarefixed[i]);
    4975
    4976 /* mark all the vertices that are in the set fixingsnode1 */
    4977 for (i = 0; i < nfixingsnode1; ++i)
    4978 {
    4979 assert( nfixingsnode1 <= 1 || (fixingsnode1[nfixingsnode1 - 1] > fixingsnode1[nfixingsnode1 - 2]) ); /* test: vertices are sorted */
    4980 mark[fixingsnode1[i]] = TRUE;
    4981 }
    4982
    4983 /* mark all the vertices that are in the set fixingsnode2 */
    4984 for (i = 0; i < nfixingsnode2; ++i)
    4985 {
    4986 assert( nfixingsnode2 <= 1 || (fixingsnode2[nfixingsnode2 - 1] > fixingsnode2[nfixingsnode2 - 2]) ); /* test: vertices are sorted */
    4987 mark[fixingsnode2[i]] = TRUE;
    4988 }
    4989
    4990 /* compute the set of vertices that have a neighbor in the set fixingsnode2, but are not in the set fixingsnode1 or fixingsnode2 and are not already fixed */
    4991 nsuccarray = 0;
    4992 for (i = 0; i < nfixingsnode2; ++i)
    4993 {
    4994 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, fixingsnode2[i]);
    4995 succ = SCIPdigraphGetSuccessors(conflictgraph, fixingsnode2[i]);
    4996
    4997 for (s = 0; s < nsucc; ++s)
    4998 {
    4999 int succnode = succ[s];
    5000
    5001 if ( ! mark[succnode] )
    5002 {
    5003 mark[succnode] = TRUE;
    5004 succarray[nsuccarray++] = succnode;
    5005 }
    5006 }
    5007 }
    5008
    5009 /* allocate buffer array */
    5010 SCIP_CALL( SCIPallocBufferArray(scip, &coverarray, nsos1vars) );
    5011
    5012 /* mark all the vertices with FALSE */
    5013 for (i = 0; i < nsos1vars; ++i)
    5014 mark[i] = FALSE;
    5015
    5016 /* mark all the vertices that are in the set fixingsnode2 */
    5017 for (i = 0; i < nfixingsnode2; ++i)
    5018 mark[fixingsnode2[i]] = TRUE;
    5019
    5020 /* for every node in succarray */
    5021 for (i = 0; i < nsuccarray; ++i)
    5022 {
    5023 SCIP_Real solval1;
    5024 SCIP_VAR* var1;
    5025 int vertex1;
    5026 int j;
    5027
    5028 vertex1 = succarray[i];
    5029 var1 = SCIPnodeGetVarSOS1(conflictgraph, vertex1);
    5030 solval1 = SCIPgetSolVal(scip, sol, var1);
    5031
    5032 /* we only add complementarity constraints if they are violated by the current LP solution */
    5033 if ( ! onlyviolsos1 || ! SCIPisFeasZero(scip, solval1) )
    5034 {
    5035 /* compute first partition of fixingsnode2 that is the intersection of the neighbors of 'vertex1' with the set fixingsnode2 */
    5036 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, vertex1);
    5037 succ = SCIPdigraphGetSuccessors(conflictgraph, vertex1);
    5038 nfixingsnode21 = 0;
    5039
    5040 for (s = 0; s < nsucc; ++s)
    5041 {
    5042 if ( mark[succ[s]] )
    5043 {
    5044 fixingsnode21[nfixingsnode21++] = succ[s];
    5045 assert( nfixingsnode21 == 1 || (fixingsnode21[nfixingsnode21 - 1] > fixingsnode21[nfixingsnode21 - 2]) ); /* test: successor vertices are sorted */
    5046 }
    5047 }
    5048
    5049 /* if variable can be fixed to zero */
    5050 if ( nfixingsnode21 == nfixingsnode2 )
    5051 {
    5052 SCIP_Bool infeasible;
    5053
    5054 SCIP_CALL( fixVariableZeroNode(scip, var1, node, &infeasible) );
    5055 assert( ! infeasible );
    5056 continue;
    5057 }
    5058
    5059 /* compute second partition of fixingsnode2 (that is fixingsnode2 \setminus fixingsnode21 ) */
    5060 SCIPcomputeArraysSetminusInt(fixingsnode2, nfixingsnode2, fixingsnode21, nfixingsnode21, fixingsnode22, &nfixingsnode22);
    5061 assert ( nfixingsnode22 + nfixingsnode21 == nfixingsnode2 );
    5062
    5063 /* compute cover set (that are all the vertices not in fixingsnode1 and fixingsnode21, whose neighborhood covers all the vertices of fixingsnode22) */
    5064 SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, -1, fixingsnode22, nfixingsnode22, coverarray, &ncoverarray) );
    5065 SCIPcomputeArraysSetminusInt(coverarray, ncoverarray, fixingsnode1, nfixingsnode1, coverarray, &ncoverarray);
    5066 SCIPcomputeArraysSetminusInt(coverarray, ncoverarray, fixingsnode21, nfixingsnode21, coverarray, &ncoverarray);
    5067
    5068 for (j = 0; j < ncoverarray; ++j)
    5069 {
    5070 int vertex2;
    5071
    5072 vertex2 = coverarray[j];
    5073 assert( vertex2 != vertex1 );
    5074
    5075 /* prevent double enumeration */
    5076 if ( vertex2 < vertex1 )
    5077 {
    5078 SCIP_VAR* var2;
    5079 SCIP_Real solval2;
    5080
    5081 var2 = SCIPnodeGetVarSOS1(conflictgraph, vertex2);
    5082 solval2 = SCIPgetSolVal(scip, sol, var2);
    5083
    5084 if ( onlyviolsos1 && ( SCIPisFeasZero(scip, solval1) || SCIPisFeasZero(scip, solval2) ) )
    5085 continue;
    5086
    5087 if ( ! isConnectedSOS1(NULL, conflictgraph, vertex1, vertex2) )
    5088 {
    5089 char name[SCIP_MAXSTRLEN];
    5090 SCIP_CONS* conssos1 = NULL;
    5091 SCIP_Bool takebound = FALSE;
    5092 SCIP_Real feas;
    5093
    5095 SCIP_Real lbboundcoef1;
    5096 SCIP_Real lbboundcoef2;
    5097 SCIP_Real ubboundcoef1;
    5098 SCIP_Real ubboundcoef2;
    5099 SCIP_VAR* boundvar1;
    5100 SCIP_VAR* boundvar2;
    5101
    5102 /* get bound variables if available */
    5103 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, vertex1);
    5104 assert( nodedata != NULL );
    5105 boundvar1 = nodedata->ubboundvar;
    5106 lbboundcoef1 = nodedata->lbboundcoef;
    5107 ubboundcoef1 = nodedata->ubboundcoef;
    5108 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, vertex2);
    5109 assert( nodedata != NULL );
    5110 boundvar2 = nodedata->ubboundvar;
    5111 lbboundcoef2 = nodedata->lbboundcoef;
    5112 ubboundcoef2 = nodedata->ubboundcoef;
    5113
    5114 if ( boundvar1 != NULL && boundvar2 != NULL && SCIPvarCompare(boundvar1, boundvar2) == 0 )
    5115 takebound = TRUE;
    5116
    5117 /* add new arc to local conflicts in order to generate tighter bound inequalities */
    5118 if ( conshdlrdata->addextendedbds )
    5119 {
    5120 if ( localconflicts == NULL )
    5121 {
    5122 SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->localconflicts, nsos1vars) );
    5123 localconflicts = conshdlrdata->localconflicts;
    5124 }
    5125 SCIP_CALL( SCIPdigraphAddArc(localconflicts, vertex1, vertex2, NULL) );
    5126 SCIP_CALL( SCIPdigraphAddArc(localconflicts, vertex2, vertex1, NULL) );
    5127 SCIP_CALL( SCIPdigraphAddArc(conflictgraph, vertex1, vertex2, NULL) );
    5128 SCIP_CALL( SCIPdigraphAddArc(conflictgraph, vertex2, vertex1, NULL) );
    5129
    5130 /* can sort successors in place - do not use arcdata */
    5131 SCIPsortInt(SCIPdigraphGetSuccessors(localconflicts, vertex1), SCIPdigraphGetNSuccessors(localconflicts, vertex1));
    5132 SCIPsortInt(SCIPdigraphGetSuccessors(localconflicts, vertex2), SCIPdigraphGetNSuccessors(localconflicts, vertex2));
    5133 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, vertex1), SCIPdigraphGetNSuccessors(conflictgraph, vertex1));
    5134 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, vertex2), SCIPdigraphGetNSuccessors(conflictgraph, vertex2));
    5135
    5136 /* mark conflictgraph as not local such that the new arcs are deleted after currents node processing */
    5137 conshdlrdata->isconflocal = TRUE;
    5138 }
    5139
    5140 /* measure feasibility of complementarity between var1 and var2 */
    5141 if ( ! takebound )
    5142 {
    5143 feas = -1.0;
    5144 if ( SCIPisFeasPositive(scip, solval1) )
    5145 {
    5146 assert( SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var1)));
    5147 if ( ! SCIPisInfinity(scip, SCIPvarGetUbLocal(var1)) )
    5148 feas += solval1/SCIPvarGetUbLocal(var1);
    5149 }
    5150 else if ( SCIPisFeasNegative(scip, solval1) )
    5151 {
    5152 assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var1)));
    5153 if ( ! SCIPisInfinity(scip, -SCIPvarGetLbLocal(var1)) )
    5154 feas += solval1/SCIPvarGetLbLocal(var1);
    5155 }
    5156
    5157 if ( SCIPisFeasPositive(scip, solval2) )
    5158 {
    5159 assert( SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var2)));
    5160 if ( ! SCIPisInfinity(scip, SCIPvarGetUbLocal(var2)) )
    5161 feas += solval2/SCIPvarGetUbLocal(var2);
    5162 }
    5163 else if ( SCIPisFeasNegative(scip, solval2) )
    5164 {
    5165 assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var2)));
    5166 if ( ! SCIPisInfinity(scip, -SCIPvarGetLbLocal(var2)) )
    5167 feas += solval2/SCIPvarGetLbLocal(var2);
    5168 }
    5169 }
    5170 else
    5171 {
    5172 feas = -SCIPgetSolVal(scip, sol, boundvar1);
    5173 if ( SCIPisFeasPositive(scip, solval1) )
    5174 {
    5175 assert( SCIPisFeasPositive(scip, ubboundcoef1));
    5176 if ( ! SCIPisInfinity(scip, ubboundcoef1) )
    5177 feas += solval1/ubboundcoef1;
    5178 }
    5179 else if ( SCIPisFeasNegative(scip, solval1) )
    5180 {
    5181 assert( SCIPisFeasPositive(scip, lbboundcoef1));
    5182 if ( ! SCIPisInfinity(scip, -lbboundcoef1) )
    5183 feas += solval1/lbboundcoef1;
    5184 }
    5185
    5186 if ( SCIPisFeasPositive(scip, solval2) )
    5187 {
    5188 assert( SCIPisFeasPositive(scip, ubboundcoef2));
    5189 if ( ! SCIPisInfinity(scip, ubboundcoef2) )
    5190 feas += solval2/ubboundcoef2;
    5191 }
    5192 else if ( SCIPisFeasNegative(scip, solval2) )
    5193 {
    5194 assert( SCIPisFeasPositive(scip, lbboundcoef2));
    5195 if ( ! SCIPisInfinity(scip, -lbboundcoef2) )
    5196 feas += solval2/lbboundcoef2;
    5197 }
    5198 assert( ! SCIPisFeasNegative(scip, solval2) );
    5199 }
    5200
    5201 if ( SCIPisGT(scip, feas, conshdlrdata->addcompsfeas) )
    5202 {
    5203 /* create SOS1 constraint */
    5204 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sos1_branchnode_%" SCIP_LONGINT_FORMAT "_no_%i", SCIPnodeGetNumber(node), *naddedconss);
    5205 SCIP_CALL( SCIPcreateConsSOS1(scip, &conssos1, name, 0, NULL, NULL, TRUE, TRUE, TRUE, FALSE, TRUE,
    5206 TRUE, FALSE, FALSE, FALSE) );
    5207
    5208 /* add variables to SOS1 constraint */
    5209 SCIP_CALL( addVarSOS1(scip, conssos1, conshdlrdata, var1, 1.0) );
    5210 SCIP_CALL( addVarSOS1(scip, conssos1, conshdlrdata, var2, 2.0) );
    5211
    5212 /* add SOS1 constraint to the branching node */
    5213 SCIP_CALL( SCIPaddConsNode(scip, node, conssos1, NULL) );
    5214 ++(*naddedconss);
    5215
    5216 /* release constraint */
    5217 SCIP_CALL( SCIPreleaseCons(scip, &conssos1) );
    5218 }
    5219
    5220 /* add bound inequality*/
    5221 if ( ! SCIPisFeasZero(scip, solval1) && ! SCIPisFeasZero(scip, solval2) )
    5222 {
    5223 /* possibly create linear constraint of the form x_i/u_i + x_j/u_j <= t if a bound variable t with x_i <= u_i * t and x_j <= u_j * t exists.
    5224 * Otherwise try to create a constraint of the form x_i/u_i + x_j/u_j <= 1. Try the same for the lower bounds. */
    5225 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "boundcons_branchnode_%" SCIP_LONGINT_FORMAT "_no_%i", SCIPnodeGetNumber(node), *naddedconss);
    5226 if ( takebound )
    5227 {
    5228 /* create constraint with right hand side = 0.0 */
    5229 SCIP_CALL( SCIPcreateConsLinear(scip, &conssos1, name, 0, NULL, NULL, -SCIPinfinity(scip), 0.0, TRUE, FALSE, TRUE, FALSE, FALSE,
    5230 TRUE, FALSE, FALSE, FALSE, FALSE) );
    5231
    5232 /* add variables */
    5233 SCIP_CALL( getBoundConsFromVertices(scip, conflictgraph, sol, vertex1, vertex2, boundvar1, conshdlrdata->addextendedbds, conssos1, &feas) );
    5234 }
    5235 else
    5236 {
    5237 /* create constraint with right hand side = 1.0 */
    5238 SCIP_CALL( SCIPcreateConsLinear(scip, &conssos1, name, 0, NULL, NULL, -SCIPinfinity(scip), 1.0, TRUE, FALSE, TRUE, FALSE, FALSE,
    5239 TRUE, FALSE, FALSE, FALSE, FALSE) );
    5240
    5241 /* add variables */
    5242 SCIP_CALL( getBoundConsFromVertices(scip, conflictgraph, sol, vertex1, vertex2, NULL, conshdlrdata->addextendedbds, conssos1, &feas) );
    5243 }
    5244
    5245 /* add linear constraint to the branching node if usefull */
    5246 if ( SCIPisGT(scip, feas, conshdlrdata->addbdsfeas ) )
    5247 {
    5248 SCIP_CALL( SCIPaddConsNode(scip, node, conssos1, NULL) );
    5249 ++(*naddedconss);
    5250 }
    5251
    5252 /* release constraint */
    5253 SCIP_CALL( SCIPreleaseCons(scip, &conssos1) );
    5254 }
    5255
    5256 /* break if number of added constraints exceeds a predefined value */
    5257 if ( conshdlrdata->maxaddcomps >= 0 && *naddedconss > conshdlrdata->maxaddcomps )
    5258 break;
    5259 }
    5260 }
    5261 }
    5262 }
    5263
    5264 /* break if number of added constraints exceeds a predefined value */
    5265 if ( conshdlrdata->maxaddcomps >= 0 && *naddedconss > conshdlrdata->maxaddcomps )
    5266 break;
    5267 }
    5268
    5269 /* free buffer array */
    5270 SCIPfreeBufferArray(scip, &coverarray);
    5271 SCIPfreeBufferArray(scip, &fixingsnode22);
    5272 SCIPfreeBufferArray(scip, &fixingsnode21);
    5273 SCIPfreeBufferArray(scip, &mark);
    5274 SCIPfreeBufferArray(scip, &succarray);
    5275 }
    5276
    5277 return SCIP_OKAY;
    5278}
    5279
    5280
    5281/** resets local conflict graph to the conflict graph of the root node */
    5282static
    5284 SCIP_DIGRAPH* conflictgraph, /**< conflict graph of root node */
    5285 SCIP_DIGRAPH* localconflicts, /**< local conflicts that should be removed from conflict graph */
    5286 int nsos1vars /**< number of SOS1 variables */
    5287 )
    5288{
    5289 int j;
    5290
    5291 for (j = 0; j < nsos1vars; ++j)
    5292 {
    5293 int nsuccloc;
    5294
    5295 nsuccloc = SCIPdigraphGetNSuccessors(localconflicts, j);
    5296 if ( nsuccloc > 0 )
    5297 {
    5298 int* succloc;
    5299 int* succ;
    5300 int nsucc;
    5301 int k = 0;
    5302
    5303 succloc = SCIPdigraphGetSuccessors(localconflicts, j);
    5304 succ = SCIPdigraphGetSuccessors(conflictgraph, j);
    5305 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
    5306
    5307 /* reset number of successors */
    5308 SCIPcomputeArraysSetminusInt(succ, nsucc, succloc, nsuccloc, succ, &k);
    5309 SCIP_CALL( SCIPdigraphSetNSuccessors(conflictgraph, j, k) );
    5310 SCIP_CALL( SCIPdigraphSetNSuccessors(localconflicts, j, 0) );
    5311 }
    5312 }
    5313
    5314 return SCIP_OKAY;
    5315}
    5316
    5317
    5318/** Conflict graph enforcement method
    5319 *
    5320 * The conflict graph can be enforced by different branching rules:
    5321 *
    5322 * - Branch on the neighborhood of a single variable @p i, i.e., in one branch \f$x_i\f$ is fixed to zero and in the
    5323 * other its neighbors from the conflict graph.
    5324 *
    5325 * - Branch on complete bipartite subgraphs of the conflict graph, i.e., in one branch fix the variables from the first
    5326 * bipartite partition and the variables from the second bipartite partition in the other.
    5327 *
    5328 * - In addition to variable domain fixings, it is sometimes also possible to add new SOS1 constraints to the branching
    5329 * nodes. This results in a nonstatic conflict graph, which may change dynamically with every branching node.
    5330 *
    5331 * We make use of different selection rules that define on which system of SOS1 variables to branch next:
    5332 *
    5333 * - Most infeasible branching: Branch on the system of SOS1 variables with largest violation.
    5334 *
    5335 * - Strong branching: Here, the LP-relaxation is partially solved for each branching decision among a candidate list.
    5336 * Then the decision with best progress is chosen.
    5337 */
    5338static
    5340 SCIP* scip, /**< SCIP pointer */
    5341 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    5342 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    5343 int nconss, /**< number of constraints */
    5344 SCIP_CONS** conss, /**< SOS1 constraints */
    5345 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
    5346 SCIP_RESULT* result /**< result */
    5347 )
    5348{
    5349 SCIP_DIGRAPH* conflictgraph;
    5350 int nsos1vars;
    5351
    5352 SCIP_Bool* verticesarefixed = NULL;
    5353 int* fixingsnode1 = NULL;
    5354 int* fixingsnode2 = NULL;
    5355 int nfixingsnode1;
    5356 int nfixingsnode2;
    5357
    5358 SCIP_Real bestobjval1 = -SCIPinfinity(scip);
    5359 SCIP_Real bestobjval2 = -SCIPinfinity(scip);
    5360 SCIP_Real lpobjval = -SCIPinfinity(scip);
    5361
    5362 SCIP_Bool infeasible;
    5363 SCIP_Bool bipbranch = FALSE;
    5364 int nstrongrounds;
    5365
    5366 int branchvertex;
    5367 SCIP_NODE* node1;
    5368 SCIP_NODE* node2;
    5369 SCIP_Real nodeselest;
    5370 SCIP_Real objest;
    5371
    5372 int i;
    5373 int j;
    5374 int c;
    5375
    5376 assert( scip != NULL );
    5377 assert( conshdlrdata != NULL );
    5378 assert( conshdlr != NULL );
    5379 assert( conss != NULL );
    5380 assert( result != NULL );
    5381
    5382 SCIPdebugMsg(scip, "Enforcing SOS1 conflict graph <%s>.\n", SCIPconshdlrGetName(conshdlr) );
    5383 *result = SCIP_DIDNOTRUN;
    5384
    5385 /* get number of SOS1 variables */
    5386 nsos1vars = conshdlrdata->nsos1vars;
    5387
    5388 /* exit for trivial cases */
    5389 if ( nsos1vars == 0 || nconss == 0 )
    5390 {
    5391 *result = SCIP_FEASIBLE;
    5392 return SCIP_OKAY;
    5393 }
    5394
    5395 /* get conflict graph */
    5396 conflictgraph = conshdlrdata->conflictgraph;
    5397 assert( ! conshdlrdata->isconflocal ); /* conflictgraph should be the one of the root node */
    5398
    5399 /* check each constraint and update conflict graph if necessary */
    5400 for (c = 0; c < nconss; ++c)
    5401 {
    5402 SCIP_CONSDATA* consdata;
    5403 SCIP_CONS* cons;
    5404 SCIP_Bool cutoff;
    5405 int ngen = 0;
    5406
    5407 cons = conss[c];
    5408 assert( cons != NULL );
    5409 consdata = SCIPconsGetData(cons);
    5410 assert( consdata != NULL );
    5411
    5412 /* do nothing if there are not enough variables - this is usually eliminated by preprocessing */
    5413 if ( consdata->nvars < 2 )
    5414 continue;
    5415
    5416 /* first perform propagation (it might happen that standard propagation is turned off) */
    5417 SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) );
    5418 SCIPdebugMsg(scip, "propagating <%s> in enforcing (cutoff: %u, domain reductions: %d).\n", SCIPconsGetName(cons), cutoff, ngen);
    5419 if ( cutoff )
    5420 {
    5421 *result = SCIP_CUTOFF;
    5422 break;
    5423 }
    5424 if ( ngen > 0 )
    5425 {
    5426 *result = SCIP_REDUCEDDOM;
    5427 break;
    5428 }
    5429 assert( ngen == 0 );
    5430
    5431 /* add local conflicts to conflict graph and save them in 'localconflicts' */
    5432 if ( consdata->local )
    5433 {
    5434 SCIP_VAR** vars;
    5435 int nvars;
    5436 int indi;
    5437 int indj;
    5438
    5439 if ( conshdlrdata->localconflicts == NULL )
    5440 {
    5441 SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->localconflicts, nsos1vars) );
    5442 }
    5443
    5444 vars = consdata->vars;
    5445 nvars = consdata->nvars;
    5446 for (i = 0; i < nvars-1; ++i)
    5447 {
    5448 SCIP_VAR* var;
    5449
    5450 var = vars[i];
    5451 indi = varGetNodeSOS1(conshdlrdata, var);
    5452
    5453 if( indi == -1 )
    5454 return SCIP_INVALIDDATA;
    5455
    5457 {
    5458 for (j = i+1; j < nvars; ++j)
    5459 {
    5460 var = vars[j];
    5461 indj = varGetNodeSOS1(conshdlrdata, var);
    5462
    5463 if( indj == -1 )
    5464 return SCIP_INVALIDDATA;
    5465
    5467 {
    5468 if ( ! isConnectedSOS1(NULL, conflictgraph, indi, indj) )
    5469 {
    5470 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, indi, indj, NULL) );
    5471 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, indj, indi, NULL) );
    5472
    5473 SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->localconflicts, indi, indj, NULL) );
    5474 SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->localconflicts, indj, indi, NULL) );
    5475
    5476 conshdlrdata->isconflocal = TRUE;
    5477 }
    5478 }
    5479 }
    5480 }
    5481 }
    5482 }
    5483 }
    5484
    5485 /* sort successor list of conflict graph if necessary */
    5486 if ( conshdlrdata->isconflocal )
    5487 {
    5488 for (j = 0; j < nsos1vars; ++j)
    5489 {
    5490 int nsuccloc;
    5491
    5492 nsuccloc = SCIPdigraphGetNSuccessors(conshdlrdata->localconflicts, j);
    5493 if ( nsuccloc > 0 )
    5494 {
    5495 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, j), SCIPdigraphGetNSuccessors(conflictgraph, j));
    5496 SCIPsortInt(SCIPdigraphGetSuccessors(conshdlrdata->localconflicts, j), nsuccloc);
    5497 }
    5498 }
    5499 }
    5500
    5501 if ( *result == SCIP_CUTOFF || *result == SCIP_REDUCEDDOM )
    5502 {
    5503 /* remove local conflicts from conflict graph */
    5504 if ( conshdlrdata->isconflocal )
    5505 {
    5506 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
    5507 conshdlrdata->isconflocal = FALSE;
    5508 }
    5509 return SCIP_OKAY;
    5510 }
    5511
    5512 /* detect fixed variables */
    5513 SCIP_CALL( SCIPallocBufferArray(scip, &verticesarefixed, nsos1vars) );
    5514 for (j = 0; j < nsos1vars; ++j)
    5515 {
    5516 SCIP_VAR* var;
    5517 SCIP_Real ub;
    5518 SCIP_Real lb;
    5519
    5520 var = SCIPnodeGetVarSOS1(conflictgraph, j);
    5521 ub = SCIPvarGetUbLocal(var);
    5522 lb = SCIPvarGetLbLocal(var);
    5523 if ( SCIPisFeasZero(scip, ub) && SCIPisFeasZero(scip, lb) )
    5524 verticesarefixed[j] = TRUE;
    5525 else
    5526 verticesarefixed[j] = FALSE;
    5527 }
    5528
    5529 /* should bipartite branching be used? */
    5530 if ( conshdlrdata->branchingrule == 'b' )
    5531 bipbranch = TRUE;
    5532
    5533 /* determine number of strong branching iterations */
    5534 if ( conshdlrdata->nstrongrounds >= 0 )
    5535 nstrongrounds = MIN(conshdlrdata->nstrongrounds, nsos1vars);
    5536 else
    5537 {
    5538 /* determine number depending on depth, based on heuristical considerations */
    5539 if ( SCIPgetDepth(scip) <= 10 )
    5540 nstrongrounds = MAX(10, (int)SCIPfloor(scip, pow(log((SCIP_Real)nsos1vars), 1.0)));/*lint !e666*/
    5541 else if ( SCIPgetDepth(scip) <= 20 )
    5542 nstrongrounds = MAX(5, (int)SCIPfloor(scip, pow(log((SCIP_Real)nsos1vars), 0.7)));/*lint !e666*/
    5543 else
    5544 nstrongrounds = 0;
    5545 nstrongrounds = MIN(nsos1vars, nstrongrounds);
    5546 }
    5547
    5548 /* allocate buffer arrays */
    5549 SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode1, nsos1vars) );
    5550 if ( bipbranch )
    5551 SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode2, nsos1vars) );
    5552 else
    5553 SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode2, 1) );
    5554
    5555 /* if strongbranching is turned off: use most infeasible branching */
    5556 if ( nstrongrounds == 0 )
    5557 {
    5558 SCIP_Bool relsolfeas;
    5559
    5560 /* get branching vertex using most infeasible branching */
    5561 SCIP_CALL( getBranchingPrioritiesSOS1(scip, conshdlrdata, conflictgraph, sol, nsos1vars, verticesarefixed,
    5562 bipbranch, fixingsnode1, fixingsnode2, NULL, &branchvertex, &relsolfeas) );
    5563
    5564 /* if LP relaxation solution is feasible */
    5565 if ( relsolfeas )
    5566 {
    5567 SCIPdebugMsg(scip, "all the SOS1 constraints are feasible.\n");
    5568
    5569 /* update result */
    5570 *result = SCIP_FEASIBLE;
    5571
    5572 /* remove local conflicts from conflict graph */
    5573 if ( conshdlrdata->isconflocal )
    5574 {
    5575 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
    5576 conshdlrdata->isconflocal = FALSE;
    5577 }
    5578
    5579 /* free memory */
    5580 SCIPfreeBufferArrayNull(scip, &fixingsnode2);
    5581 SCIPfreeBufferArrayNull(scip, &fixingsnode1);
    5582 SCIPfreeBufferArrayNull(scip, &verticesarefixed);
    5583
    5584 return SCIP_OKAY;
    5585 }
    5586 }
    5587 else
    5588 {
    5589 /* get branching vertex using strong branching */
    5590 SCIP_CALL( getBranchingDecisionStrongbranchSOS1(scip, conshdlrdata, conflictgraph, sol, nsos1vars, lpobjval,
    5591 bipbranch, nstrongrounds, verticesarefixed, fixingsnode1, fixingsnode2, &branchvertex, &bestobjval1,
    5592 &bestobjval2, result) );
    5593
    5594 if ( *result == SCIP_CUTOFF || *result == SCIP_FEASIBLE || *result == SCIP_REDUCEDDOM )
    5595 {
    5596 /* remove local conflicts from conflict graph */
    5597 if ( conshdlrdata->isconflocal )
    5598 {
    5599 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
    5600 conshdlrdata->isconflocal = FALSE;
    5601 }
    5602
    5603 /* free memory */
    5604 SCIPfreeBufferArrayNull(scip, &fixingsnode2);
    5605 SCIPfreeBufferArrayNull(scip, &fixingsnode1);
    5606 SCIPfreeBufferArrayNull(scip, &verticesarefixed);
    5607
    5608 return SCIP_OKAY;
    5609 }
    5610 }
    5611
    5612 /* if we should leave branching decision to branching rules */
    5613 if ( ! conshdlrdata->branchsos )
    5614 {
    5615 /* remove local conflicts from conflict graph */
    5616 if ( conshdlrdata->isconflocal )
    5617 {
    5618 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
    5619 conshdlrdata->isconflocal = FALSE;
    5620 }
    5621
    5622 /* free memory */
    5623 SCIPfreeBufferArrayNull(scip, &fixingsnode2);
    5624 SCIPfreeBufferArrayNull(scip, &fixingsnode1);
    5625 SCIPfreeBufferArrayNull(scip, &verticesarefixed);
    5626
    5627 assert( branchvertex >= 0 && branchvertex < nsos1vars );
    5628 if ( SCIPvarIsBinary(SCIPnodeGetVarSOS1(conflictgraph, branchvertex)) )
    5629 {
    5630 *result = SCIP_INFEASIBLE;
    5631 return SCIP_OKAY;
    5632 }
    5633 else
    5634 {
    5635 SCIPerrorMessage("Incompatible parameter setting: branchsos can only be set to false if all SOS1 variables are binary.\n");
    5637 }
    5638 }
    5639
    5640 /* create branching nodes */
    5641
    5642 /* get vertices of variables that will be fixed to zero for each node */
    5643 assert( branchvertex >= 0 && branchvertex < nsos1vars );
    5644 assert( ! verticesarefixed[branchvertex] );
    5645 SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, sol, verticesarefixed, bipbranch, branchvertex,
    5646 fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) );
    5647
    5648 /* calculate node selection and objective estimate for node 1 */
    5649 nodeselest = 0.0;
    5651 for (j = 0; j < nfixingsnode1; ++j)
    5652 {
    5653 SCIP_VAR* var;
    5654
    5655 var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]);
    5656 objest += SCIPcalcChildEstimateIncrease(scip, var, SCIPgetSolVal(scip, sol, var), 0.0);
    5657 nodeselest += SCIPcalcNodeselPriority(scip, var, SCIP_BRANCHDIR_DOWNWARDS, 0.0);
    5658 }
    5659 assert( objest >= SCIPgetLocalTransEstimate(scip) );
    5660
    5661 /* create node 1 */
    5662 SCIP_CALL( SCIPcreateChild(scip, &node1, nodeselest, objest) );
    5663
    5664 /* fix variables for the first node */
    5665 if ( conshdlrdata->fixnonzero && nfixingsnode2 == 1 )
    5666 {
    5667 SCIP_VAR* var;
    5668 SCIP_Real lb;
    5669 SCIP_Real ub;
    5670
    5671 var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[0]);
    5672 lb = SCIPvarGetLbLocal(var);
    5673 ub = SCIPvarGetUbLocal(var);
    5674
    5676 {
    5677 if ( SCIPisZero(scip, lb) )
    5678 {
    5679 /* fix variable to some very small, but positive number or to 1.0 if variable is integral */
    5680 if (SCIPvarIsIntegral(var) )
    5681 {
    5682 SCIP_CALL( SCIPchgVarLbNode(scip, node1, var, 1.0) );
    5683 }
    5684 else
    5685 {
    5686 SCIP_CALL( SCIPchgVarLbNode(scip, node1, var, 1.5 * SCIPfeastol(scip)) );
    5687 }
    5688 }
    5689 else if ( SCIPisZero(scip, ub) )
    5690 {
    5691 if (SCIPvarIsIntegral(var) )
    5692 {
    5693 /* fix variable to some negative number with small absolute value to -1.0 if variable is integral */
    5694 SCIP_CALL( SCIPchgVarUbNode(scip, node1, var, -1.0) );
    5695 }
    5696 else
    5697 {
    5698 /* fix variable to some negative number with small absolute value to -1.0 if variable is integral */
    5699 SCIP_CALL( SCIPchgVarUbNode(scip, node1, var, -1.5 * SCIPfeastol(scip)) );
    5700 }
    5701 }
    5702 }
    5703 }
    5704
    5705 for (j = 0; j < nfixingsnode1; ++j)
    5706 {
    5707 /* fix variable to zero */
    5708 SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]), node1, &infeasible) );
    5709 assert( ! infeasible );
    5710 }
    5711
    5712 /* calculate node selection and objective estimate for node 2 */
    5713 nodeselest = 0.0;
    5715 for (j = 0; j < nfixingsnode2; ++j)
    5716 {
    5717 SCIP_VAR* var;
    5718
    5719 var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]);
    5720 objest += SCIPcalcChildEstimateIncrease(scip, var, SCIPgetSolVal(scip, sol, var), 0.0);
    5721 nodeselest += SCIPcalcNodeselPriority(scip, var, SCIP_BRANCHDIR_DOWNWARDS, 0.0);
    5722 }
    5723 assert( objest >= SCIPgetLocalTransEstimate(scip) );
    5724
    5725 /* create node 2 */
    5726 SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) );
    5727
    5728 /* fix variables to zero */
    5729 for (j = 0; j < nfixingsnode2; ++j)
    5730 {
    5731 SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]), node2, &infeasible) );
    5732 assert( ! infeasible );
    5733 }
    5734
    5735 /* add complementarity constraints to the branching nodes */
    5736 if ( conshdlrdata->addcomps && ( conshdlrdata->addcompsdepth == -1 || conshdlrdata->addcompsdepth >= SCIPgetDepth(scip) ) )
    5737 {
    5738 int naddedconss;
    5739
    5740 assert( ! conshdlrdata->fixnonzero );
    5741
    5742 /* add complementarity constraints to the left branching node */
    5743 SCIP_CALL( addBranchingComplementaritiesSOS1(scip, node1, conshdlrdata, conflictgraph, conshdlrdata->localconflicts, sol,
    5744 nsos1vars, verticesarefixed, fixingsnode1, nfixingsnode1, fixingsnode2, nfixingsnode2, &naddedconss, TRUE) );
    5745
    5746 if ( naddedconss == 0 )
    5747 {
    5748 /* add complementarity constraints to the right branching node */
    5749 SCIP_CALL( addBranchingComplementaritiesSOS1(scip, node2, conshdlrdata, conflictgraph, conshdlrdata->localconflicts, sol,
    5750 nsos1vars, verticesarefixed, fixingsnode2, nfixingsnode2, fixingsnode1, nfixingsnode1, &naddedconss, TRUE) );
    5751 }
    5752 }
    5753
    5754 /* sets node's lower bound to the best known value */
    5755 if ( nstrongrounds > 0 )
    5756 {
    5757 SCIP_CALL( SCIPupdateNodeLowerbound(scip, node1, MAX(lpobjval, bestobjval1) ) );
    5758 SCIP_CALL( SCIPupdateNodeLowerbound(scip, node2, MAX(lpobjval, bestobjval2) ) );
    5759 }
    5760
    5761 /* remove local conflicts from conflict graph */
    5762 if ( conshdlrdata->isconflocal )
    5763 {
    5764 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
    5765 conshdlrdata->isconflocal = FALSE;
    5766 }
    5767
    5768 /* free buffer arrays */
    5769 SCIPfreeBufferArrayNull(scip, &fixingsnode2);
    5770 SCIPfreeBufferArrayNull(scip, &fixingsnode1);
    5771 SCIPfreeBufferArrayNull(scip, &verticesarefixed );
    5772 *result = SCIP_BRANCHED;
    5773
    5774 return SCIP_OKAY;
    5775}
    5776
    5777
    5778/** SOS1 branching enforcement method
    5779 *
    5780 * We check whether the current solution is feasible, i.e., contains at most one nonzero
    5781 * variable. If not, we branch along the lines indicated by Beale and Tomlin:
    5782 *
    5783 * We first compute \f$W = \sum_{j=1}^n |x_i|\f$ and \f$w = \sum_{j=1}^n j\, |x_i|\f$. Then we
    5784 * search for the index \f$k\f$ that satisfies
    5785 * \f[
    5786 * k \leq \frac{w}{W} < k+1.
    5787 * \f]
    5788 * The branches are then
    5789 * \f[
    5790 * x_1 = 0, \ldots, x_k = 0 \qquad \mbox{and}\qquad x_{k+1} = 0, \ldots, x_n = 0.
    5791 * \f]
    5792 *
    5793 * If the constraint contains two variables, the branching of course simplifies.
    5794 *
    5795 * Depending on the parameters (@c branchnonzeros, @c branchweight) there are three ways to choose
    5796 * the branching constraint.
    5797 *
    5798 * <TABLE>
    5799 * <TR><TD>@c branchnonzeros</TD><TD>@c branchweight</TD><TD>constraint chosen</TD></TR>
    5800 * <TR><TD>@c true </TD><TD> ? </TD><TD>most number of nonzeros</TD></TR>
    5801 * <TR><TD>@c false </TD><TD> @c true </TD><TD>maximal weight corresponding to nonzero variable</TD></TR>
    5802 * <TR><TD>@c false </TD><TD> @c true </TD><TD>largest sum of variable values</TD></TR>
    5803 * </TABLE>
    5804 *
    5805 * @c branchnonzeros = @c false, @c branchweight = @c true allows the user to specify an order for
    5806 * the branching importance of the constraints (setting the weights accordingly).
    5807 *
    5808 * Constraint branching can also be turned off using parameter @c branchsos.
    5809 */
    5810static
    5812 SCIP* scip, /**< SCIP pointer */
    5813 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    5814 int nconss, /**< number of constraints */
    5815 SCIP_CONS** conss, /**< indicator constraints */
    5816 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
    5817 SCIP_RESULT* result /**< result */
    5818 )
    5819{
    5820 SCIP_CONSHDLRDATA* conshdlrdata;
    5821 SCIP_CONSDATA* consdata;
    5822 SCIP_NODE* node1;
    5823 SCIP_NODE* node2;
    5825 SCIP_Real maxWeight;
    5826 SCIP_VAR** vars;
    5827 int nvars;
    5828 int c;
    5829
    5830 assert( scip != NULL );
    5831 assert( conshdlr != NULL );
    5832 assert( conss != NULL );
    5833 assert( result != NULL );
    5834
    5835 maxWeight = -SCIP_REAL_MAX;
    5836 branchCons = NULL;
    5837
    5838 SCIPdebugMsg(scip, "Enforcing SOS1 constraints <%s>.\n", SCIPconshdlrGetName(conshdlr) );
    5839 *result = SCIP_FEASIBLE;
    5840
    5841 /* get constraint handler data */
    5842 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5843 assert( conshdlrdata != NULL );
    5844
    5845 /* check each constraint */
    5846 for (c = 0; c < nconss; ++c)
    5847 {
    5848 SCIP_CONS* cons;
    5849 SCIP_Bool cutoff;
    5850 SCIP_Real weight;
    5851 int ngen;
    5852 int cnt;
    5853 int j;
    5854
    5855 cons = conss[c];
    5856 assert( cons != NULL );
    5857 consdata = SCIPconsGetData(cons);
    5858 assert( consdata != NULL );
    5859
    5860 ngen = 0;
    5861 cnt = 0;
    5862 nvars = consdata->nvars;
    5863 vars = consdata->vars;
    5864
    5865 /* do nothing if there are not enough variables - this is usually eliminated by preprocessing */
    5866 if ( nvars < 2 )
    5867 continue;
    5868
    5869 /* first perform propagation (it might happen that standard propagation is turned off) */
    5870 SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) );
    5871 SCIPdebugMsg(scip, "propagating <%s> in enforcing (cutoff: %u, domain reductions: %d).\n", SCIPconsGetName(cons), cutoff, ngen);
    5872 if ( cutoff )
    5873 {
    5874 *result = SCIP_CUTOFF;
    5875 return SCIP_OKAY;
    5876 }
    5877 if ( ngen > 0 )
    5878 {
    5879 *result = SCIP_REDUCEDDOM;
    5880 return SCIP_OKAY;
    5881 }
    5882 assert( ngen == 0 );
    5883
    5884 /* check constraint */
    5885 weight = 0.0;
    5886 for (j = 0; j < nvars; ++j)
    5887 {
    5888 SCIP_Real val = REALABS(SCIPgetSolVal(scip, sol, vars[j]));
    5889
    5890 if ( ! SCIPisFeasZero(scip, val) )
    5891 {
    5892 if ( conshdlrdata->branchnonzeros )
    5893 weight += 1.0;
    5894 else
    5895 {
    5896 if ( conshdlrdata->branchweight && consdata->weights != NULL )
    5897 {
    5898 /* choose maximum nonzero-variable weight */
    5899 if ( consdata->weights[j] > weight )
    5900 weight = consdata->weights[j];
    5901 }
    5902 else
    5903 weight += val;
    5904 }
    5905 ++cnt;
    5906 }
    5907 }
    5908 /* if constraint is violated */
    5909 if ( cnt > 1 && weight > maxWeight )
    5910 {
    5911 maxWeight = weight;
    5912 branchCons = cons;
    5913 }
    5914 }
    5915
    5916 /* if all constraints are feasible */
    5917 if ( branchCons == NULL )
    5918 {
    5919 SCIPdebugMsg(scip, "All SOS1 constraints are feasible.\n");
    5920 return SCIP_OKAY;
    5921 }
    5922
    5923 /* if we should leave branching decision to branching rules */
    5924 if ( ! conshdlrdata->branchsos )
    5925 {
    5926 int j;
    5927
    5928 consdata = SCIPconsGetData(branchCons);
    5929 for (j = 0; j < consdata->nvars; ++j)
    5930 {
    5931 if ( ! SCIPvarIsBinary(consdata->vars[j]) )
    5932 break;
    5933 }
    5934
    5935 if ( j == consdata->nvars )
    5936 {
    5937 *result = SCIP_INFEASIBLE;
    5938 return SCIP_OKAY;
    5939 }
    5940 else
    5941 {
    5942 SCIPerrorMessage("Incompatible parameter setting: branchsos can only be set to false if all SOS1 variables are binary.\n");
    5944 }
    5945 }
    5946
    5947 /* otherwise create branches */
    5948 SCIPdebugMsg(scip, "Branching on constraint <%s> (weight: %f).\n", SCIPconsGetName(branchCons), maxWeight);
    5949 consdata = SCIPconsGetData(branchCons);
    5950 assert( consdata != NULL );
    5951 nvars = consdata->nvars;
    5952 vars = consdata->vars;
    5953
    5954 if ( nvars == 2 )
    5955 {
    5956 SCIP_Bool infeasible;
    5957
    5958 /* constraint is infeasible: */
    5959 assert( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, vars[0])) && ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, vars[1])) );
    5960
    5961 /* create branches */
    5962 SCIPdebugMsg(scip, "Creating two branches.\n");
    5963
    5965 SCIP_CALL( fixVariableZeroNode(scip, vars[0], node1, &infeasible) );
    5966 assert( ! infeasible );
    5967
    5969 SCIP_CALL( fixVariableZeroNode(scip, vars[1], node2, &infeasible) );
    5970 assert( ! infeasible );
    5971 }
    5972 else
    5973 {
    5974 SCIP_Bool infeasible;
    5975 SCIP_Real weight1;
    5976 SCIP_Real weight2;
    5977 SCIP_Real nodeselest;
    5978 SCIP_Real objest;
    5979 SCIP_Real w;
    5980 int j;
    5981 int ind;
    5982#ifndef NDEBUG
    5983 int cnt = 0;
    5984#endif
    5985
    5986 weight1 = 0.0;
    5987 weight2 = 0.0;
    5988
    5989 /* compute weight */
    5990 for (j = 0; j < nvars; ++j)
    5991 {
    5992 SCIP_Real val = REALABS(SCIPgetSolVal(scip, sol, vars[j]));
    5993 weight1 += val * (SCIP_Real) j;
    5994 weight2 += val;
    5995
    5996#ifndef NDEBUG
    5997 if ( ! SCIPisFeasZero(scip, val) )
    5998 ++cnt;
    5999#endif
    6000 }
    6001
    6002 assert( cnt >= 2 );
    6003 assert( !SCIPisFeasZero(scip, weight2) );
    6004 w = weight1/weight2; /*lint !e795*/
    6005
    6006 ind = (int) SCIPfloor(scip, w);
    6007 assert( 0 <= ind && ind < nvars-1 );
    6008
    6009 /* branch on variable ind: either all variables up to ind or all variables after ind are zero */
    6010 SCIPdebugMsg(scip, "Branching on variable <%s>.\n", SCIPvarGetName(vars[ind]));
    6011
    6012 /* calculate node selection and objective estimate for node 1 */
    6013 nodeselest = 0.0;
    6015 for (j = 0; j <= ind; ++j)
    6016 {
    6017 objest += SCIPcalcChildEstimateIncrease(scip, vars[j], SCIPgetSolVal(scip, sol, vars[j]), 0.0);
    6018 nodeselest += SCIPcalcNodeselPriority(scip, vars[j], SCIP_BRANCHDIR_DOWNWARDS, 0.0);
    6019 }
    6020 assert( objest >= SCIPgetLocalTransEstimate(scip) );
    6021
    6022 /* create node 1 */
    6023 SCIP_CALL( SCIPcreateChild(scip, &node1, nodeselest, objest) );
    6024 for (j = 0; j <= ind; ++j)
    6025 {
    6026 SCIP_CALL( fixVariableZeroNode(scip, vars[j], node1, &infeasible) );
    6027 assert( ! infeasible );
    6028 }
    6029
    6030 /* calculate node selection and objective estimate for node 1 */
    6031 nodeselest = 0.0;
    6033 for (j = ind+1; j < nvars; ++j)
    6034 {
    6035 objest += SCIPcalcChildEstimateIncrease(scip, vars[j], SCIPgetSolVal(scip, sol, vars[j]), 0.0);
    6036 nodeselest += SCIPcalcNodeselPriority(scip, vars[j], SCIP_BRANCHDIR_DOWNWARDS, 0.0);
    6037 }
    6038 assert( objest >= SCIPgetLocalTransEstimate(scip) );
    6039
    6040 /* create node 2 */
    6041 SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) );
    6042 for (j = ind+1; j < nvars; ++j)
    6043 {
    6044 SCIP_CALL( fixVariableZeroNode(scip, vars[j], node2, &infeasible) );
    6045 assert( ! infeasible );
    6046 }
    6047 }
    6049 *result = SCIP_BRANCHED;
    6050
    6051 return SCIP_OKAY;
    6052}
    6053
    6054
    6055/** constraint enforcing method of constraint handler */
    6056static
    6058 SCIP* scip, /**< SCIP pointer */
    6059 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6060 int nconss, /**< number of constraints */
    6061 SCIP_CONS** conss, /**< indicator constraints */
    6062 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
    6063 SCIP_RESULT* result /**< result */
    6064 )
    6065{
    6066 SCIP_CONSHDLRDATA* conshdlrdata;
    6067
    6068 assert( scip != NULL );
    6069 assert( conshdlr != NULL );
    6070 assert( conss != NULL );
    6071 assert( result != NULL );
    6072
    6073 /* get constraint handler data */
    6074 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6075 assert( conshdlrdata != NULL );
    6076
    6077 if ( conshdlrdata->addcomps && conshdlrdata->fixnonzero )
    6078 {
    6079 SCIPerrorMessage("Incompatible parameter setting: addcomps = TRUE and fixnonzero = TRUE.\n");
    6081 }
    6082
    6083 if ( conshdlrdata->fixnonzero && ( conshdlrdata->branchingrule == 'b' || conshdlrdata->branchingrule == 's' ) )
    6084 {
    6085 SCIPerrorMessage("Incompatible parameter setting: nonzero fixing is not compatible with bipartite or sos1 branching.\n");
    6087 }
    6088
    6089 if ( conshdlrdata->branchingrule == 's' && conshdlrdata->nstrongrounds != 0 )
    6090 {
    6091 SCIPerrorMessage("Strong branching is not available for SOS1 branching.\n");
    6093 }
    6094
    6095 if ( conshdlrdata->branchingrule == 's' || conshdlrdata->switchsos1branch )
    6096 {
    6097 /* enforce SOS1 constraints */
    6098 SCIP_CALL( enforceConssSOS1(scip, conshdlr, nconss, conss, sol, result) );
    6099 }
    6100 else
    6101 {
    6102 if ( conshdlrdata->branchingrule != 'n' && conshdlrdata->branchingrule != 'b' )
    6103 {
    6104 SCIPerrorMessage("branching rule %c unknown\n", conshdlrdata->branchingrule);
    6106 }
    6107
    6108 /* enforce conflict graph */
    6109 SCIP_CALL( enforceConflictgraph(scip, conshdlrdata, conshdlr, nconss, conss, sol, result) );
    6110 }
    6111
    6112 return SCIP_OKAY;
    6113}
    6114
    6115
    6116/* ----------------------------- separation ------------------------------------*/
    6117
    6118/** initialitze tclique graph and create clique data */
    6119static
    6121 SCIP* scip, /**< SCIP pointer */
    6122 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6123 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    6124 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    6125 int nsos1vars /**< number of SOS1 variables */
    6126 )
    6127{
    6128 TCLIQUE_DATA* tcliquedata;
    6129 int j;
    6130
    6131 /* try to generate bound cuts */
    6132 if ( ! tcliqueCreate(&conshdlrdata->tcliquegraph) )
    6133 return SCIP_NOMEMORY;
    6134
    6135 /* add nodes */
    6136 for (j = 0; j < nsos1vars; ++j)
    6137 {
    6138 if ( ! tcliqueAddNode(conshdlrdata->tcliquegraph, j, 0 ) )
    6139 return SCIP_NOMEMORY;
    6140 }
    6141
    6142 /* add edges */
    6143 for (j = 0; j < nsos1vars; ++j)
    6144 {
    6145 int* succ;
    6146 int nsucc;
    6147 int succnode;
    6148 int i;
    6149
    6150 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
    6151 succ = SCIPdigraphGetSuccessors(conflictgraph, j);
    6152
    6153 for (i = 0; i < nsucc; ++i)
    6154 {
    6155 succnode = succ[i];
    6156
    6157 if ( succnode > j && SCIPvarIsActive(SCIPnodeGetVarSOS1(conflictgraph, succnode)) )
    6158 {
    6159 if ( ! tcliqueAddEdge(conshdlrdata->tcliquegraph, j, succnode) )
    6160 return SCIP_NOMEMORY;
    6161 }
    6162 }
    6163 }
    6164
    6165 if ( ! tcliqueFlush(conshdlrdata->tcliquegraph) )
    6166 return SCIP_NOMEMORY;
    6167
    6168 /* allocate clique data */
    6169 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata->tcliquedata) );
    6170 tcliquedata = conshdlrdata->tcliquedata;
    6171
    6172 /* initialize clique data */
    6173 tcliquedata->scip = scip;
    6174 tcliquedata->sol = NULL;
    6175 tcliquedata->conshdlr = conshdlr;
    6176 tcliquedata->conflictgraph = conflictgraph;
    6177 tcliquedata->scaleval = 1000.0;
    6178 tcliquedata->ncuts = 0;
    6179 tcliquedata->nboundcuts = conshdlrdata->nboundcuts;
    6180 tcliquedata->strthenboundcuts = conshdlrdata->strthenboundcuts;
    6181 tcliquedata->maxboundcuts = conshdlrdata->maxboundcutsroot;
    6182
    6183 return SCIP_OKAY;
    6184}
    6185
    6186
    6187/** update weights of tclique graph */
    6188static
    6190 SCIP* scip, /**< SCIP pointer */
    6191 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    6192 TCLIQUE_DATA* tcliquedata, /**< tclique data */
    6193 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    6194 SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */
    6195 int nsos1vars /**< number of SOS1 variables */
    6196 )
    6197{
    6198 SCIP_Real scaleval;
    6199 int j;
    6200
    6201 scaleval = tcliquedata->scaleval;
    6202
    6203 for (j = 0; j < nsos1vars; ++j)
    6204 {
    6205 SCIP_Real solval;
    6207 SCIP_VAR* var;
    6208
    6209 var = SCIPnodeGetVarSOS1(conflictgraph, j);
    6210 solval = SCIPgetSolVal(scip, sol, var);
    6211
    6212 if ( SCIPisFeasPositive(scip, solval) )
    6213 {
    6214 if ( conshdlrdata->strthenboundcuts )
    6215 bound = REALABS( nodeGetSolvalVarboundUbSOS1(scip, conflictgraph, sol, j) );
    6216 else
    6218 }
    6219 else if ( SCIPisFeasNegative(scip, solval) )
    6220 {
    6221 if ( conshdlrdata->strthenboundcuts )
    6222 bound = REALABS( nodeGetSolvalVarboundLbSOS1(scip, conflictgraph, sol, j) );
    6223 else
    6225 }
    6226 else
    6227 bound = 0.0;
    6228
    6229 solval = REALABS( solval );
    6230
    6232 {
    6233 SCIP_Real nodeweight;
    6234 nodeweight = REALABS( solval/bound ) * scaleval;/*lint !e414*/
    6235 tcliqueChangeWeight(conshdlrdata->tcliquegraph, j, (int)nodeweight);
    6236 }
    6237 else
    6238 {
    6239 tcliqueChangeWeight(conshdlrdata->tcliquegraph, j, 0);
    6240 }
    6241 }
    6242
    6243 return SCIP_OKAY;
    6244}
    6245
    6246
    6247/** adds bound cut(s) to separation storage */
    6248static
    6250 SCIP* scip, /**< SCIP pointer */
    6251 TCLIQUE_DATA* tcliquedata, /**< clique data */
    6252 SCIP_ROW* rowlb, /**< row for lower bounds (or NULL) */
    6253 SCIP_ROW* rowub, /**< row for upper bounds (or NULL) */
    6254 SCIP_Bool* success, /**< pointer to store if bound cut was added */
    6255 SCIP_Bool* cutoff /**< pointer to store if a cutoff occurred */
    6256 )
    6257{
    6258 assert( scip != NULL );
    6259 assert( tcliquedata != NULL );
    6260 assert( success != NULL);
    6261 assert( cutoff != NULL );
    6262
    6263 *success = FALSE;
    6264 *cutoff = FALSE;
    6265
    6266 /* add cut for lower bounds */
    6267 if ( rowlb != NULL )
    6268 {
    6269 if ( ! SCIProwIsInLP(rowlb) && SCIPisCutEfficacious(scip, NULL, rowlb) )
    6270 {
    6271 SCIP_Bool infeasible;
    6272
    6273 SCIP_CALL( SCIPaddRow(scip, rowlb, FALSE, &infeasible) );
    6274 if ( infeasible )
    6275 *cutoff = TRUE;
    6276 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowlb, NULL) ) );
    6277 ++tcliquedata->nboundcuts;
    6278 ++tcliquedata->ncuts;
    6279 *success = TRUE;
    6280 }
    6281 }
    6282
    6283 /* add cut for upper bounds */
    6284 if ( rowub != NULL )
    6285 {
    6286 if ( ! SCIProwIsInLP(rowub) && SCIPisCutEfficacious(scip, NULL, rowub) )
    6287 {
    6288 SCIP_Bool infeasible;
    6289
    6290 SCIP_CALL( SCIPaddRow(scip, rowub, FALSE, &infeasible) );
    6291 if ( infeasible )
    6292 *cutoff = TRUE;
    6293 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowub, NULL) ) );
    6294 ++tcliquedata->nboundcuts;
    6295 ++tcliquedata->ncuts;
    6296 *success = TRUE;
    6297 }
    6298 }
    6299
    6300 return SCIP_OKAY;
    6301}
    6302
    6303
    6304/** Generate bound constraint
    6305 *
    6306 * We generate the row corresponding to the following simple valid inequalities:
    6307 * \f[
    6308 * \frac{x_1}{u_1} + \ldots + \frac{x_n}{u_n} \leq 1\qquad\mbox{and}\qquad
    6309 * \frac{x_1}{\ell_1} + \ldots + \frac{x_n}{\ell_1} \leq 1,
    6310 * \f]
    6311 * where \f$\ell_1, \ldots, \ell_n\f$ and \f$u_1, \ldots, u_n\f$ are the nonzero and finite lower and upper bounds of
    6312 * the variables \f$x_1, \ldots, x_n\f$. If an upper bound < 0 or a lower bound > 0, the constraint itself is
    6313 * redundant, so the cut is not applied (lower bounds > 0 and upper bounds < 0 are usually detected in presolving or
    6314 * propagation). Infinite bounds and zero are skipped. Thus \f$\ell_1, \ldots, \ell_n\f$ are all negative, which
    6315 * results in the \f$\leq\f$ inequality. In case of the presence of variable upper bounds, the bound inequality can
    6316 * be further strengthened.
    6317 *
    6318 * Note that in fact, any mixture of nonzero finite lower and upper bounds would lead to a valid inequality as
    6319 * above. However, usually either the lower or upper bound is nonzero. Thus, the above inequalities are the most
    6320 * interesting.
    6321 */
    6322static
    6324 SCIP* scip, /**< SCIP pointer */
    6325 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6326 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    6327 int* nodes, /**< conflict graph nodes for bound constraint */
    6328 int nnodes, /**< number of conflict graph nodes for bound constraint */
    6329 SCIP_Real rhs, /**< right hand side of bound constraint */
    6330 SCIP_Bool local, /**< in any case produce a local cut (even if local bounds of variables are valid globally) */
    6331 SCIP_Bool global, /**< in any case produce a global cut */
    6332 SCIP_Bool strengthen, /**< whether trying to strengthen bound constraint */
    6333 SCIP_Bool removable, /**< should the inequality be removed from the LP due to aging or cleanup? */
    6334 const char* nameext, /**< part of name of bound constraints */
    6335 SCIP_ROW** rowlb, /**< output: row for lower bounds (or NULL if not needed) */
    6336 SCIP_ROW** rowub /**< output: row for upper bounds (or NULL if not needed) */
    6337 )
    6338{
    6339 char name[SCIP_MAXSTRLEN];
    6340 SCIP_VAR* lbboundvar = NULL;
    6341 SCIP_VAR* ubboundvar = NULL;
    6342 SCIP_Bool locallbs;
    6343 SCIP_Bool localubs;
    6344 SCIP_VAR** vars;
    6345 SCIP_Real* vals;
    6346
    6347 assert( scip != NULL );
    6348 assert( conshdlr != NULL );
    6349 assert( conflictgraph != NULL );
    6350 assert( ! local || ! global );
    6351 assert( nodes != NULL );
    6352
    6353 /* allocate buffer array */
    6356
    6357 /* take care of upper bounds */
    6358 if ( rowub != NULL )
    6359 {
    6360 SCIP_Bool useboundvar;
    6361 int cnt = 0;
    6362 int j;
    6363
    6364 /* Loop through all variables. We check whether all bound variables (if existent) are equal; if this is the
    6365 * case then the bound constraint can be strengthened */
    6366 localubs = local;
    6367 useboundvar = strengthen;
    6368 for (j = 0; j < nnodes; ++j)
    6369 {
    6371 SCIP_VAR* var;
    6372 SCIP_Real val;
    6373
    6374 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, nodes[j]);
    6375 assert( nodedata != NULL );
    6376 var = nodedata->var;
    6377 assert( var != NULL );
    6378
    6379 /* if variable is not involved in a variable bound constraint */
    6380 if ( ! useboundvar || nodedata->ubboundvar == NULL )
    6381 {
    6382 useboundvar = FALSE;
    6383 if ( localubs )
    6384 {
    6385 assert( ! global );
    6386 val = SCIPvarGetUbLocal(var);
    6387 }
    6388 else
    6389 {
    6390 val = SCIPvarGetUbGlobal(var);
    6391 if ( ! global && ! SCIPisFeasEQ(scip, val, SCIPvarGetUbLocal(var)) )
    6392 {
    6393 localubs = TRUE;
    6394 val = SCIPvarGetUbLocal(var);
    6395 }
    6396 }
    6397 }
    6398 else
    6399 {
    6400 /* in this case the cut is always valid globally */
    6401
    6402 /* if we have a bound variable for the first time */
    6403 if ( ubboundvar == NULL )
    6404 {
    6405 ubboundvar = nodedata->ubboundvar;
    6406 val = nodedata->ubboundcoef;
    6407 }
    6408 /* else if the bound variable equals the stored bound variable */
    6409 else if ( ubboundvar == nodedata->ubboundvar )
    6410 val = nodedata->ubboundcoef;
    6411 else /* else use bounds on the variables */
    6412 {
    6413 useboundvar = FALSE;
    6414
    6415 /* restart 'for'-loop */
    6416 j = -1; /*lint !e850*/
    6417 cnt = 0;
    6418 continue;
    6419 }
    6420 }
    6421
    6422 /* should not apply the cut if a variable is fixed to be negative -> constraint is redundant */
    6423 if ( SCIPisNegative(scip, val) )
    6424 break;
    6425
    6426 /* store variable if relevant for bound inequality */
    6427 if ( ! SCIPisInfinity(scip, val) && ! SCIPisZero(scip, val) )
    6428 {
    6429 vars[cnt] = var;
    6430
    6431 /* if only two nodes then we scale the cut differently */
    6432 if ( nnodes == 2 )
    6433 vals[cnt++] = val;
    6434 else
    6435 vals[cnt++] = 1.0/val;
    6436 }
    6437 }
    6438
    6439 /* if cut is meaningful */
    6440 if ( j == nnodes && cnt >= 2 )/*lint !e850*/
    6441 {
    6442 /* if only two nodes then we scale the cut differently */
    6443 if ( nnodes == 2 )
    6444 {
    6445 SCIP_Real save;
    6446
    6447 save = vals[0];
    6448 vals[0] = vals[1];
    6449 vals[1] = save;
    6450 rhs = rhs * vals[0] * vals[1];
    6451 assert( (! useboundvar && cnt == 2 ) || (useboundvar && cnt == 3 ) );
    6452 }
    6453
    6454 if ( useboundvar )
    6455 {
    6456 /* add bound variable to array */
    6457 vars[cnt] = ubboundvar;
    6458 vals[cnt++] = -rhs;
    6459 assert(ubboundvar != NULL );
    6460
    6461 /* create upper bound inequality if at least two of the bounds are finite and nonzero */
    6462 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sosub#%s", nameext);
    6463 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowub, conshdlr, name, -SCIPinfinity(scip), 0.0, localubs, FALSE, removable) );
    6464 SCIP_CALL( SCIPaddVarsToRow(scip, *rowub, cnt, vars, vals) );
    6465 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowub, NULL) ) );
    6466 }
    6467 else
    6468 {
    6469 /* create upper bound inequality if at least two of the bounds are finite and nonzero */
    6470 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sosub#%s", nameext);
    6471 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowub, conshdlr, name, -SCIPinfinity(scip), rhs, localubs, FALSE, removable) );
    6472 SCIP_CALL( SCIPaddVarsToRow(scip, *rowub, cnt, vars, vals) );
    6473 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowub, NULL) ) );
    6474 }
    6475 }
    6476 }
    6477
    6478 /* take care of lower bounds */
    6479 if ( rowlb != NULL )
    6480 {
    6481 SCIP_Bool useboundvar;
    6482 int cnt = 0;
    6483 int j;
    6484
    6485 /* loop through all variables. We check whether all bound variables (if existent) are equal; if this is the
    6486 * case then the bound constraint can be strengthened */
    6487 locallbs = local;
    6488 useboundvar = strengthen;
    6489 for (j = 0; j < nnodes; ++j)
    6490 {
    6492 SCIP_VAR* var;
    6493 SCIP_Real val;
    6494
    6495 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, nodes[j]);
    6496 assert( nodedata != NULL );
    6497 var = nodedata->var;
    6498 assert( var != NULL );
    6499
    6500 /* if variable is not involved in a variable bound constraint */
    6501 if ( ! useboundvar || nodedata->lbboundvar == NULL )
    6502 {
    6503 useboundvar = FALSE;
    6504 if ( locallbs )
    6505 {
    6506 assert( ! global );
    6507 val = SCIPvarGetLbLocal(var);
    6508 }
    6509 else
    6510 {
    6511 val = SCIPvarGetLbGlobal(var);
    6512 if ( ! global && ! SCIPisFeasEQ(scip, val, SCIPvarGetLbLocal(var)) )
    6513 {
    6514 locallbs = TRUE;
    6515 val = SCIPvarGetLbLocal(var);
    6516 }
    6517 }
    6518 }
    6519 else
    6520 {
    6521 /* in this case the cut is always valid globally */
    6522
    6523 /* if we have a bound variable for the first time */
    6524 if ( lbboundvar == NULL )
    6525 {
    6526 lbboundvar = nodedata->lbboundvar;
    6527 val = nodedata->lbboundcoef;
    6528 }
    6529 /* else if the bound variable equals the stored bound variable */
    6530 else if ( SCIPvarCompare(lbboundvar, nodedata->lbboundvar) == 0 )
    6531 {
    6532 val = nodedata->lbboundcoef;
    6533 }
    6534 else /* else use bounds on the variables */
    6535 {
    6536 useboundvar = FALSE;
    6537
    6538 /* restart 'for'-loop */
    6539 j = -1; /*lint !e850*/
    6540 cnt = 0;
    6541 continue;
    6542 }
    6543 }
    6544
    6545 /* should not apply the cut if a variable is fixed to be positive -> constraint is redundant */
    6546 if ( SCIPisPositive(scip, val) )
    6547 break;
    6548
    6549 /* store variable if relevant for bound inequality */
    6550 if ( ! SCIPisInfinity(scip, -val) && ! SCIPisZero(scip, val) )
    6551 {
    6552 vars[cnt] = var;
    6553
    6554 /* if only two nodes then we scale the cut differently */
    6555 if ( nnodes == 2 )
    6556 vals[cnt++] = val;
    6557 else
    6558 vals[cnt++] = 1.0/val;
    6559 }
    6560 }
    6561
    6562 /* if cut is meaningful */
    6563 if ( j == nnodes && cnt >= 2 )/*lint !e850*/
    6564 {
    6565 /* if only two nodes then we scale the cut differently */
    6566 if ( nnodes == 2 )
    6567 {
    6568 SCIP_Real save;
    6569
    6570 save = vals[0];
    6571 vals[0] = vals[1];
    6572 vals[1] = save;
    6573 rhs = rhs * vals[0] * vals[1];
    6574 assert( (! useboundvar && cnt == 2 ) || (useboundvar && cnt == 3 ) );
    6575 }
    6576
    6577 if ( useboundvar )
    6578 {
    6579 /* add bound variable to array */
    6580 vars[cnt] = lbboundvar;
    6581 vals[cnt++] = -rhs;
    6582 assert(lbboundvar != NULL );
    6583
    6584 /* create upper bound inequality if at least two of the bounds are finite and nonzero */
    6585 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "soslb#%s", nameext);
    6586 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowlb, conshdlr, name, -SCIPinfinity(scip), 0.0, locallbs, FALSE, TRUE) );
    6587 SCIP_CALL( SCIPaddVarsToRow(scip, *rowlb, cnt, vars, vals) );
    6588 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowlb, NULL) ) );
    6589 }
    6590 else
    6591 {
    6592 /* create upper bound inequality if at least two of the bounds are finite and nonzero */
    6593 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "soslb#%s", nameext);
    6594 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowlb, conshdlr, name, -SCIPinfinity(scip), rhs, locallbs, FALSE, TRUE) );
    6595 SCIP_CALL( SCIPaddVarsToRow(scip, *rowlb, cnt, vars, vals) );
    6596 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowlb, NULL) ) );
    6597 }
    6598 }
    6599 }
    6600
    6601 /* free buffer array */
    6602 SCIPfreeBufferArray(scip, &vals);
    6603 SCIPfreeBufferArray(scip, &vars);
    6604
    6605 return SCIP_OKAY;
    6606}
    6607
    6608
    6609/** generates bound cuts using a clique found by algorithm for maximum weight clique
    6610 * and decides whether to stop generating cliques with the algorithm for maximum weight clique
    6611 */
    6612static
    6613TCLIQUE_NEWSOL(tcliqueNewsolClique)
    6614{
    6615 TCLIQUE_WEIGHT minweightinc;
    6616
    6617 assert( acceptsol != NULL );
    6618 assert( stopsolving != NULL );
    6619 assert( tcliquedata != NULL );
    6620
    6621 /* we don't accept the solution as new incumbent, because we want to find many violated clique inequalities */
    6622 *acceptsol = FALSE;
    6623 *stopsolving = FALSE;
    6624
    6625 /* slightly increase the minimal weight for additional cliques */
    6626 minweightinc = (cliqueweight - *minweight)/10;
    6627 minweightinc = MAX(minweightinc, 1);
    6628 *minweight += minweightinc;
    6629
    6630 /* adds cut if weight of the clique is greater than 1 */
    6631 if( cliqueweight > tcliquedata->scaleval )
    6632 {
    6633 SCIP* scip;
    6634 SCIP_SOL* sol;
    6635 SCIP_Real unscaledweight;
    6636 SCIP_Real solval;
    6638 SCIP_VAR* var;
    6639 int node;
    6640 int i;
    6641
    6642 scip = tcliquedata->scip;
    6643 sol = tcliquedata->sol;
    6644 assert( scip != NULL );
    6645
    6646 /* calculate the weight of the clique in unscaled fractional variable space */
    6647 unscaledweight = 0.0;
    6648 for( i = 0; i < ncliquenodes; i++ )
    6649 {
    6650 node = cliquenodes[i];
    6651 var = SCIPnodeGetVarSOS1(tcliquedata->conflictgraph, node);
    6652 solval = SCIPgetSolVal(scip, sol, var);
    6653
    6654 if ( SCIPisFeasPositive(scip, solval) )
    6655 {
    6656 if ( tcliquedata->strthenboundcuts )
    6657 bound = REALABS( nodeGetSolvalVarboundUbSOS1(scip, tcliquedata->conflictgraph, sol, node) );
    6658 else
    6660 }
    6661 else if ( SCIPisFeasNegative(scip, solval) )
    6662 {
    6663 if ( tcliquedata->strthenboundcuts )
    6664 bound = REALABS( nodeGetSolvalVarboundLbSOS1(scip, tcliquedata->conflictgraph, sol, node) );
    6665 else
    6667 }
    6668 else
    6669 bound = 0.0;
    6670
    6671 solval = REALABS( solval );
    6672
    6674 unscaledweight += REALABS( solval/bound );/*lint !e414*/
    6675 }
    6676
    6677 if ( SCIPisEfficacious(scip, unscaledweight - 1.0) )
    6678 {
    6679 char nameext[SCIP_MAXSTRLEN];
    6680 SCIP_ROW* rowlb = NULL;
    6681 SCIP_ROW* rowub = NULL;
    6682 SCIP_Bool success;
    6683 SCIP_Bool cutoff;
    6684
    6685 /* generate bound inequalities for lower and upper bound case
    6686 * NOTE: tests have shown that non-removable rows give the best results */
    6687 (void) SCIPsnprintf(nameext, SCIP_MAXSTRLEN, "%d", tcliquedata->nboundcuts);
    6688 if ( generateBoundInequalityFromSOS1Nodes(scip, tcliquedata->conshdlr, tcliquedata->conflictgraph,
    6689 cliquenodes, ncliquenodes, 1.0, FALSE, FALSE, tcliquedata->strthenboundcuts, FALSE, nameext, &rowlb, &rowub) != SCIP_OKAY )
    6690 {
    6691 SCIPerrorMessage("Unexpected error in bound cut creation.\n");
    6692 SCIPABORT();
    6693 return; /*lint !e527*/
    6694 }
    6695
    6696 /* add bound cut(s) to separation storage if existent */
    6697 if ( addBoundCutSepa(scip, tcliquedata, rowlb, rowub, &success, &cutoff) != SCIP_OKAY )
    6698 {
    6699 SCIPerrorMessage("Unexpected error in bound cut creation.\n");
    6700 SCIPABORT();
    6701 return; /*lint !e527*/
    6702 }
    6703
    6704 if ( rowlb != NULL )
    6705 {
    6706 if ( SCIPreleaseRow(scip, &rowlb) != SCIP_OKAY )
    6707 {
    6708 SCIPerrorMessage("Cannot release row,\n");
    6709 SCIPABORT();
    6710 return; /*lint !e527*/
    6711 }
    6712 }
    6713 if ( rowub != NULL )
    6714 {
    6715 if ( SCIPreleaseRow(scip, &rowub) != SCIP_OKAY )
    6716 {
    6717 SCIPerrorMessage("Cannot release row,\n");
    6718 SCIPABORT();
    6719 return; /*lint !e527*/
    6720 }
    6721 }
    6722
    6723 /* if at least one cut has been added */
    6724 if ( success )
    6725 {
    6726 SCIPdebugMsg(scip, " -> found bound cut corresponding to clique (act=%g)\n", unscaledweight);
    6727
    6728 /* if we found more than half the cuts we are allowed to generate, we accept the clique as new incumbent,
    6729 * such that only more violated cuts are generated afterwards
    6730 */
    6731 if( tcliquedata->maxboundcuts >= 0 )
    6732 {
    6733 if ( tcliquedata->ncuts > tcliquedata->maxboundcuts/2 )
    6734 *acceptsol = TRUE;
    6735 if ( tcliquedata->ncuts >= tcliquedata->maxboundcuts )
    6736 *stopsolving = TRUE;
    6737 }
    6738 }
    6739 else
    6740 *stopsolving = TRUE;
    6741 } /*lint !e438*/
    6742 }
    6743}
    6744
    6745
    6746/** separate bound inequalities from conflict graph */
    6747static
    6749 SCIP* scip, /**< SCIP pointer */
    6750 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6751 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    6752 SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */
    6753 int maxboundcuts, /**< maximal number of bound cuts separated per separation round (-1: no limit) */
    6754 int* ngen, /**< pointer to store number of cuts generated */
    6755 SCIP_Bool* cutoff /**< pointer whether a cutoff occurred */
    6756 )
    6757{
    6758 SCIP_DIGRAPH* conflictgraph;
    6759 TCLIQUE_DATA* tcliquedata;
    6760 TCLIQUE_WEIGHT cliqueweight;
    6761 TCLIQUE_STATUS tcliquestatus;
    6762 int nsos1vars;
    6763
    6764 SCIP_Real scaleval = 1000.0; /* factor for scaling weights */
    6765 int maxtreenodes = 10000; /* maximal number of nodes of b&b tree */
    6766 int maxzeroextensions = 1000; /* maximal number of zero-valued variables extending the clique (-1: no limit) */
    6767 int backtrackfreq = 1000; /* frequency for premature backtracking up to tree level 1 (0: no backtracking) */
    6768 int ntreenodes;
    6769 int* cliquenodes;
    6770 int ncliquenodes;
    6771
    6772 assert( scip != NULL );
    6773 assert( conshdlr != NULL );
    6774 assert( conshdlrdata != NULL );
    6775 assert( ngen != NULL );
    6776
    6777 /* get conflict graph */
    6778 conflictgraph = SCIPgetConflictgraphSOS1(conshdlr);
    6779 assert( conflictgraph != NULL );
    6780
    6781 /* get number of SOS1 variables */
    6782 nsos1vars = SCIPgetNSOS1Vars(conshdlr);
    6783
    6784 /* initialize data of tclique graph*/
    6785 tcliquedata = conshdlrdata->tcliquedata;
    6786 tcliquedata->scaleval = scaleval;
    6787 tcliquedata->maxboundcuts = maxboundcuts;
    6788 tcliquedata->sol = sol;
    6789 tcliquedata->ncuts = 0;
    6790 tcliquedata->cutoff = FALSE;
    6791
    6792 /* update the weights of the tclique graph */
    6793 SCIP_CALL( updateWeightsTCliquegraph(scip, conshdlrdata, tcliquedata, conflictgraph, sol, nsos1vars) );
    6794
    6795 /* allocate buffer array */
    6796 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nsos1vars) );
    6797
    6798 /* start algorithm to find maximum weight cliques and use them to generate bound cuts */
    6799 tcliqueMaxClique(tcliqueGetNNodes, tcliqueGetWeights, tcliqueIsEdge, tcliqueSelectAdjnodes,
    6800 conshdlrdata->tcliquegraph, tcliqueNewsolClique, tcliquedata,
    6801 cliquenodes, &ncliquenodes, &cliqueweight, (int)scaleval-1, (int)scaleval+1,
    6802 maxtreenodes, backtrackfreq, maxzeroextensions, -1, &ntreenodes, &tcliquestatus);
    6803
    6804 /* free buffer array */
    6805 SCIPfreeBufferArray(scip, &cliquenodes);
    6806
    6807 /* get number of cuts of current separation round */
    6808 *ngen = tcliquedata->ncuts;
    6809
    6810 /* store whether a cutoff occurred */
    6811 *cutoff = tcliquedata->cutoff;
    6812
    6813 /* update number of bound cuts in separator data */
    6814 conshdlrdata->nboundcuts = tcliquedata->nboundcuts;
    6815
    6816 return SCIP_OKAY;
    6817}
    6818
    6819
    6820/** Generate a bound constraint from the variables of an SOS1 constraint (see generateBoundInequalityFromSOS1Nodes() for more information) */
    6821static
    6823 SCIP* scip, /**< SCIP pointer */
    6824 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6825 SCIP_CONS* cons, /**< SOS1 constraint */
    6826 SCIP_Bool local, /**< in any case produce a local cut (even if local bounds of variables are valid globally) */
    6827 SCIP_Bool global, /**< in any case produce a global cut */
    6828 SCIP_Bool strengthen, /**< whether trying to strengthen bound constraint */
    6829 SCIP_Bool removable, /**< should the inequality be removed from the LP due to aging or cleanup? */
    6830 SCIP_ROW** rowlb, /**< output: row for lower bounds (or NULL if not needed) */
    6831 SCIP_ROW** rowub /**< output: row for upper bounds (or NULL if not needed) */
    6832 )
    6833{
    6834 SCIP_CONSHDLRDATA* conshdlrdata;
    6835 SCIP_CONSDATA* consdata;
    6836 int* nodes;
    6837 int nvars;
    6838 int cnt = 0;
    6839 int j;
    6840
    6841 assert( scip != NULL );
    6842 assert( conshdlr != NULL );
    6843 assert( cons != NULL );
    6844
    6845 /* get constraint data */
    6846 consdata = SCIPconsGetData(cons);
    6847 assert( consdata != NULL );
    6848 assert( consdata->vars != NULL );
    6849 nvars = consdata->nvars;
    6850
    6851 /* get constraint handler data */
    6852 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6853 assert( conshdlrdata != NULL );
    6854 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6855
    6856 /* allocate buffer array */
    6857 SCIP_CALL( SCIPallocBufferArray(scip, &nodes, nvars) );
    6858
    6859 /* get nodes in the conflict graph */
    6860 for (j = 0; j < nvars; ++j)
    6861 {
    6862 if ( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(consdata->vars[j])) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(consdata->vars[j])) )
    6863 {
    6864 assert( varGetNodeSOS1(conshdlrdata, consdata->vars[j]) >= 0 );
    6865 nodes[cnt++] = varGetNodeSOS1(conshdlrdata, consdata->vars[j]);
    6866 }
    6867 }
    6868
    6869 /* generate bound constraint from conflict graph nodes */
    6870 if ( cnt > 0 )
    6871 {
    6872 SCIP_CALL( generateBoundInequalityFromSOS1Nodes(scip, conshdlr, conshdlrdata->conflictgraph, nodes, cnt, 1.0, local, global,
    6873 strengthen, removable, SCIPconsGetName(cons), rowlb, rowub) );
    6874 }
    6875
    6876 /* free buffer array */
    6877 SCIPfreeBufferArray(scip, &nodes);
    6878
    6879 return SCIP_OKAY;
    6880}
    6881
    6882
    6883/** initialize or separate bound inequalities from SOS1 constraints */
    6884static
    6886 SCIP* scip, /**< SCIP pointer */
    6887 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6888 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    6889 SCIP_CONS** conss, /**< SOS1 constraints */
    6890 int nconss, /**< number of SOS1 constraints */
    6891 SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */
    6892 SCIP_Bool solvedinitlp, /**< TRUE if initial LP relaxation at a node is solved */
    6893 int maxboundcuts, /**< maximal number of bound cuts separated per separation round (-1: no limit) */
    6894 int* ngen, /**< pointer to store number of cuts generated (or NULL) */
    6895 SCIP_Bool* cutoff /**< pointer to store whether a cutoff occurred */
    6896 )
    6897{
    6898 int cnt = 0;
    6899 int c;
    6900
    6901 assert( scip != NULL );
    6902 assert( conshdlrdata != NULL );
    6903 assert( conss != NULL );
    6904
    6905 *cutoff = FALSE;
    6906
    6907 for (c = 0; c < nconss; ++c)
    6908 {
    6909 SCIP_CONSDATA* consdata;
    6910 SCIP_ROW* rowub = NULL;
    6911 SCIP_ROW* rowlb = NULL;
    6912 SCIP_Bool release = FALSE;
    6913
    6914 assert( conss != NULL );
    6915 assert( conss[c] != NULL );
    6916 consdata = SCIPconsGetData(conss[c]);
    6917 assert( consdata != NULL );
    6918
    6919 if ( solvedinitlp )
    6920 {
    6921 SCIPdebugMsg(scip, "Separating inequalities for SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
    6922 }
    6923 else
    6924 {
    6925 SCIPdebugMsg(scip, "Checking for initial rows for SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
    6926 }
    6927
    6928 /* in case that the SOS1 constraint is local, we always generate new rows - the former rows might be invalid;
    6929 * otherwise if the SOS1 constraint is global, we only generate rows if not yet done */
    6930 if ( consdata->local )
    6931 {
    6932 SCIP_CALL( generateBoundInequalityFromSOS1Cons(scip, conshdlr, conss[c], TRUE, FALSE, TRUE, FALSE, &rowlb, &rowub) );
    6933 release = TRUE;
    6934 }
    6935 else
    6936 {
    6937 if ( consdata->rowub == NULL || consdata->rowlb == NULL )
    6938 {
    6940 (consdata->rowlb == NULL) ? &consdata->rowlb : NULL,
    6941 (consdata->rowub == NULL) ? &consdata->rowub : NULL) ); /*lint !e826*/
    6942 }
    6943 rowub = consdata->rowub;
    6944 rowlb = consdata->rowlb;
    6945 }
    6946
    6947 /* put corresponding rows into LP */
    6948 if ( rowub != NULL && ! SCIProwIsInLP(rowub) && ( solvedinitlp || SCIPisCutEfficacious(scip, sol, rowub) ) )
    6949 {
    6950 SCIP_CALL( SCIPaddRow(scip, rowub, FALSE, cutoff) );
    6951 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowub, NULL) ) );
    6952
    6953 if ( solvedinitlp )
    6954 {
    6955 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
    6956 }
    6957 ++cnt;
    6958 }
    6959
    6960 if ( ! (*cutoff) && rowlb != NULL && ! SCIProwIsInLP(rowlb) && ( solvedinitlp || SCIPisCutEfficacious(scip, sol, rowlb) ) )
    6961 {
    6962 SCIP_CALL( SCIPaddRow(scip, rowlb, FALSE, cutoff) );
    6963 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowlb, NULL) ) );
    6964
    6965 if ( solvedinitlp )
    6966 {
    6967 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
    6968 }
    6969 ++cnt;
    6970 }
    6971
    6972 /* release rows if they are local */
    6973 if ( release )
    6974 {
    6975 if ( rowlb != NULL )
    6976 {
    6977 SCIP_CALL( SCIPreleaseRow(scip, &rowlb) );
    6978 }
    6979 if ( rowub != NULL )
    6980 {
    6981 SCIP_CALL( SCIPreleaseRow(scip, &rowub) );
    6982 }
    6983 }
    6984
    6985 if ( *cutoff || ( maxboundcuts >= 0 && cnt >= maxboundcuts ) )
    6986 break;
    6987 }
    6988
    6989 /* store number of generated cuts */
    6990 if ( ngen != NULL )
    6991 *ngen = cnt;
    6992
    6993 return SCIP_OKAY;
    6994}
    6995
    6996
    6997/** separate implied bound cuts */
    6998static
    7000 SCIP* scip, /**< SCIP pointer */
    7001 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7002 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    7003 SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */
    7004 int maxcuts, /**< maximal number of implied bound cuts separated per separation round (-1: no limit) */
    7005 int* ngen, /**< pointer to store number of cuts generated */
    7006 SCIP_Bool* cutoff /**< pointer whether a cutoff occurred */
    7007 )
    7008{
    7009 SCIP_DIGRAPH* implgraph;
    7010 SCIP_Bool genbreak;
    7011 int nimplnodes;
    7012 int i;
    7013
    7014 assert( scip != NULL);
    7015 assert( conshdlrdata != NULL);
    7016 assert( conshdlr != NULL);
    7017 assert( ngen != NULL);
    7018 assert( cutoff != NULL);
    7019
    7020 *cutoff = FALSE;
    7021 *ngen = 0;
    7022
    7023 /* return if conflict graph is not available */
    7024 if ( conshdlrdata->conflictgraph == NULL )
    7025 return SCIP_OKAY;
    7026
    7027 /* get implication graph */
    7028 implgraph = conshdlrdata->implgraph;
    7029
    7030 /* create implication graph if not done already */
    7031 if ( implgraph == NULL )
    7032 {
    7033 int nchbds;
    7034
    7035 if ( SCIPgetDepth(scip) == 0 )
    7036 {
    7037 SCIP_Bool success;
    7038 SCIP_CALL( initImplGraphSOS1(scip, conshdlrdata, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, conshdlrdata->maxtightenbds, &nchbds, cutoff, &success) );
    7039 if ( *cutoff || ! success )
    7040 return SCIP_OKAY;
    7041 implgraph = conshdlrdata->implgraph;
    7042 }
    7043 else
    7044 {
    7045 return SCIP_OKAY;
    7046 }
    7047 }
    7048 nimplnodes = conshdlrdata->nimplnodes;
    7049 assert( implgraph != NULL );
    7050 assert( nimplnodes > 0);
    7051
    7052 /* exit if implication graph has no arcs between its nodes */
    7053 if ( SCIPdigraphGetNArcs(implgraph) < 1 )
    7054 return SCIP_OKAY;
    7055
    7056 /* loop through all nodes of the implication graph */
    7057 genbreak = FALSE;
    7058 for (i = 0; i < nimplnodes && ! genbreak; ++i)
    7059 {
    7060 SCIP_SUCCDATA** succdatas;
    7062 SCIP_Real solval;
    7063 SCIP_VAR* var;
    7064 int* succ;
    7065 int nsucc;
    7066 int s;
    7067
    7068 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, i);
    7070 assert( nodedata != NULL );
    7071 var = nodedata->var;
    7072 assert( var != NULL );
    7073 solval = SCIPgetSolVal(scip, sol, var);
    7074
    7075 if ( succdatas != NULL && ! SCIPisFeasZero(scip, solval) )
    7076 {
    7077 succ = SCIPdigraphGetSuccessors(implgraph, i);
    7078 nsucc = SCIPdigraphGetNSuccessors(implgraph, i);
    7079
    7080 for (s = 0; s < nsucc && ! genbreak; ++s)
    7081 {
    7082 SCIP_SUCCDATA* succdata;
    7083 SCIP_VAR* succvar;
    7084 SCIP_ROW* cut = NULL;
    7085 SCIP_Bool bound1lower;
    7086 SCIP_Bool bound2lower;
    7087 SCIP_Real solvalsucc;
    7088 SCIP_Real bound1;
    7089 SCIP_Real bound2;
    7090 SCIP_Real lhsrhs;
    7091 SCIP_Real impl;
    7092 int k;
    7093
    7094 nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, succ[s]);
    7095 succdata = succdatas[s];
    7096 assert( nodedata != NULL && succdata != NULL && nodedata->var != NULL );
    7097 succvar = nodedata->var;
    7098 solvalsucc = SCIPgetSolVal(scip, sol, succvar);
    7099
    7100 /* determine coefficients for bound inequality */
    7101 assert( ! SCIPisFeasZero(scip, solval) );
    7102 if ( SCIPisFeasNegative(scip, solval) )
    7103 {
    7104 bound1lower = TRUE;
    7105 bound1 = SCIPvarGetLbGlobal(var);
    7106 }
    7107 else
    7108 {
    7109 bound1lower = FALSE;
    7110 bound1 = SCIPvarGetUbGlobal(var);
    7111 }
    7112
    7113 /* handle lower bound upper bound implications */
    7114 for (k = 0; k < 2; ++k)
    7115 {
    7116 if ( k == 0 )
    7117 {
    7118 SCIP_Real lbsucc;
    7119 lbsucc = SCIPvarGetLbGlobal(succvar);
    7120 if ( SCIPisFeasLT(scip, lbsucc, succdata->lbimpl) )
    7121 {
    7122 impl = succdata->lbimpl;
    7123 bound2 = lbsucc;
    7124 }
    7125 else
    7126 continue;
    7127 }
    7128 else
    7129 {
    7130 SCIP_Real ubsucc;
    7131 ubsucc = SCIPvarGetUbGlobal(succvar);
    7132 if ( SCIPisFeasGT(scip, ubsucc, succdata->ubimpl) )
    7133 {
    7134 impl = succdata->ubimpl;
    7135 bound2 = ubsucc;
    7136 }
    7137 else
    7138 continue;
    7139 }
    7140
    7141 if ( SCIPisInfinity(scip, REALABS(bound1)) || SCIPisInfinity(scip, REALABS(bound2)) )
    7142 continue;
    7143 assert( ! SCIPisInfinity(scip, REALABS(impl)) );
    7144
    7145 if ( SCIPisFeasNegative(scip, bound2-impl) )
    7146 bound2lower = TRUE;
    7147 else
    7148 bound2lower = FALSE;
    7149
    7150 /* determine left/right hand side of bound inequality */
    7151 lhsrhs = bound1 * bound2;
    7152
    7153 /* create cut */
    7154 if ( bound1lower == bound2lower )
    7155 {
    7156 if ( SCIPisFeasGT(scip, solval * (bound2-impl) + solvalsucc * bound1, lhsrhs) )
    7157 {
    7158 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &cut, conshdlr, "", -SCIPinfinity(scip), lhsrhs, FALSE, FALSE, TRUE) );
    7159 }
    7160 else
    7161 continue;
    7162 }
    7163 else
    7164 {
    7165 if ( SCIPisFeasLT(scip, solval * (bound2-impl) + solvalsucc * bound1, lhsrhs) )
    7166 {
    7167 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &cut, conshdlr, "", lhsrhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
    7168 }
    7169 else
    7170 continue;
    7171 }
    7172
    7173 /* add coefficients of variables */
    7175 SCIP_CALL( SCIPaddVarToRow(scip, cut, var, bound2-impl) );
    7176 SCIP_CALL( SCIPaddVarToRow(scip, cut, succvar, bound1) );
    7178
    7179 /* add cut if useful */
    7180 if ( ! SCIProwIsInLP(cut) && SCIPisCutEfficacious(scip, NULL, cut) )
    7181 {
    7182 SCIP_Bool infeasible;
    7183 SCIP_CALL( SCIPaddRow(scip, cut, FALSE, &infeasible) );
    7184 if ( infeasible )
    7185 {
    7186 genbreak = TRUE;
    7187 *cutoff = TRUE;
    7188 break;
    7189 }
    7191#ifdef SCIP_DEBUG
    7192 if ( k == 0 )
    7193 {
    7194 SCIPdebugMsg(scip, "added cut for implication %s != 0 -> %s >= %f \n", SCIPvarGetName(var), SCIPvarGetName(succvar), succdata->lbimpl);
    7195 }
    7196 else
    7197 {
    7198 SCIPdebugMsg(scip, "added cut for implication %s != 0 -> %s <= %f \n", SCIPvarGetName(var), SCIPvarGetName(succvar), succdata->ubimpl);
    7199 }
    7200#endif
    7201
    7202 ++(*ngen);
    7203 }
    7204
    7205 if ( maxcuts >= 0 && *ngen > maxcuts )
    7206 {
    7207 genbreak = TRUE;
    7208 break;
    7209 }
    7210 }
    7211
    7212 if ( cut != NULL )
    7213 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
    7214 }
    7215 }
    7216 }
    7217
    7218 return SCIP_OKAY;
    7219}
    7220
    7221
    7222/** separates SOS1 constraints for arbitrary solutions */
    7223static
    7225 SCIP* scip, /**< SCIP pointer */
    7226 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7227 SCIP_SOL* sol, /**< solution to be separated (or NULL) */
    7228 int nconss, /**< number of constraints */
    7229 SCIP_CONS** conss, /**< SOS1 constraints */
    7230 SCIP_RESULT* result /**< result */
    7231 )
    7232{
    7233 SCIP_CONSHDLRDATA* conshdlrdata;
    7234 int depth;
    7235
    7236 assert( scip != NULL );
    7237 assert( conshdlr != NULL );
    7238 assert( conss != NULL );
    7239 assert( result != NULL );
    7240
    7241 *result = SCIP_DIDNOTRUN;
    7242
    7243 if ( nconss == 0 )
    7244 return SCIP_OKAY;
    7245
    7246 /* only separate cuts if we are not close to terminating */
    7247 if( SCIPisStopped(scip) )
    7248 return SCIP_OKAY;
    7249
    7250 *result = SCIP_DIDNOTFIND;
    7251
    7252 /* get constraint handler data */
    7253 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7254 assert( conshdlrdata != NULL );
    7255
    7256 /* get node depth */
    7257 depth = SCIPgetDepth(scip);
    7258
    7259 /* separate bound (clique) inequalities */
    7260 if ( conshdlrdata->boundcutsfreq >= 0 &&
    7261 ( (conshdlrdata->boundcutsfreq == 0 && depth == 0) || (conshdlrdata->boundcutsfreq > 0 && depth % conshdlrdata->boundcutsfreq == 0)) )
    7262 {
    7263 int maxboundcuts;
    7264 int ngen = 0;
    7265
    7266 /* determine maximal number of cuts*/
    7267 if ( depth == 0 )
    7268 maxboundcuts = conshdlrdata->maxboundcutsroot;
    7269 else
    7270 maxboundcuts = conshdlrdata->maxboundcuts;
    7271
    7272 if ( maxboundcuts >= 1 )
    7273 {
    7274 /* separate bound inequalities from SOS1 constraints */
    7275 if( conshdlrdata->boundcutsfromsos1 || conshdlrdata->switchcutsfromsos1 )
    7276 {
    7277 SCIP_Bool cutoff;
    7278
    7279 SCIP_CALL( initsepaBoundInequalityFromSOS1Cons(scip, conshdlr, conshdlrdata, conss, nconss, sol, TRUE, maxboundcuts, &ngen, &cutoff) );
    7280 if ( cutoff )
    7281 {
    7282 *result = SCIP_CUTOFF;
    7283 return SCIP_OKAY;
    7284 }
    7285 }
    7286
    7287 /* separate bound inequalities from the conflict graph */
    7288 if( conshdlrdata->boundcutsfromgraph && ! conshdlrdata->switchcutsfromsos1 )
    7289 {
    7290 SCIP_Bool cutoff;
    7291 SCIP_CALL( sepaBoundInequalitiesFromGraph(scip, conshdlr, conshdlrdata, sol, maxboundcuts, &ngen, &cutoff) );
    7292 if ( cutoff )
    7293 {
    7294 *result = SCIP_CUTOFF;
    7295 return SCIP_OKAY;
    7296 }
    7297 }
    7298 }
    7299
    7300 /* evaluate results */
    7301 if ( ngen > 0 )
    7302 *result = SCIP_SEPARATED;
    7303 SCIPdebugMsg(scip, "Separated %d bound (clique) inequalities.\n", ngen);
    7304 }
    7305
    7306 /* separate implied bound inequalities */
    7307 if ( conshdlrdata->implcutsfreq >= 0 &&
    7308 ( (conshdlrdata->implcutsfreq == 0 && depth == 0) || (conshdlrdata->implcutsfreq > 0 && depth % conshdlrdata->implcutsfreq == 0)) )
    7309 {
    7310 int maximplcuts;
    7311 int ngen = 0;
    7312
    7313 /* determine maximal number of cuts*/
    7314 if ( depth == 0 )
    7315 maximplcuts = conshdlrdata->maximplcutsroot;
    7316 else
    7317 maximplcuts = conshdlrdata->maximplcuts;
    7318
    7319 /* call separator for implied bound cuts */
    7320 if ( maximplcuts >= 1 )
    7321 {
    7322 SCIP_Bool cutoff;
    7323 SCIP_CALL( sepaImplBoundCutsSOS1(scip, conshdlr, conshdlrdata, sol, maximplcuts, &ngen, &cutoff) );
    7324 if ( cutoff )
    7325 {
    7326 *result = SCIP_CUTOFF;
    7327 return SCIP_OKAY;
    7328 }
    7329 }
    7330
    7331 /* evaluate results */
    7332 if ( ngen > 0 )
    7333 *result = SCIP_SEPARATED;
    7334 SCIPdebugMsg(scip, "Separated %d implied bound inequalities.\n", ngen);
    7335 }
    7336
    7337 return SCIP_OKAY;
    7338}
    7339
    7340
    7341/* -------------------------- heuristic methods --------------------------------*/
    7342
    7343/** gets weights determining an order of the variables in a heuristic for the maximum weighted independent set problem */
    7344static
    7346 SCIP* scip, /**< SCIP pointer */
    7347 SCIP_SOL* sol, /**< primal solution or NULL for current LP solution */
    7348 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    7349 int nsos1vars, /**< number of SOS1 variables */
    7350 SCIP_Bool* indicatorzero, /**< vector that indicates which variables are currently fixed to zero */
    7351 SCIP_Real* weights /**< pointer to store weights determining the order of the variables (length = nsos1vars) */
    7352 )
    7353{
    7354 SCIP_VAR* var;
    7355 SCIP_Real val;
    7356 SCIP_Real sum;
    7357 int nviols;
    7358 int* succ;
    7359 int nsucc;
    7360 int i;
    7361 int j;
    7362
    7363 assert( scip != NULL );
    7364 assert( conflictgraph != NULL );
    7365 assert( indicatorzero != NULL );
    7366 assert( weights != NULL );
    7367
    7368 for (i = 0; i < nsos1vars; ++i)
    7369 {
    7370 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
    7371
    7372 if( nsucc == 0 || indicatorzero[i] )
    7373 weights[i] = 0.0;
    7374 else
    7375 {
    7376 var = SCIPnodeGetVarSOS1(conflictgraph, i);
    7377 val = REALABS( SCIPgetSolVal(scip, sol, var) );
    7378 if ( SCIPisFeasZero(scip, val) )
    7379 weights[i] = 0.0;
    7380 else
    7381 {
    7382 succ = SCIPdigraphGetSuccessors(conflictgraph, i);
    7383
    7384 nviols = 0;
    7385 sum = 0.0;
    7386 for (j = 0; j < nsucc; ++j)
    7387 {
    7388 SCIP_Real valsucc;
    7389
    7390 valsucc = REALABS( SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, succ[j])) );
    7391 if( ! SCIPisFeasZero(scip, valsucc) )
    7392 {
    7393 sum += MIN(10E05, valsucc);
    7394 ++nviols;
    7395 }
    7396 }
    7397
    7398 if ( nviols == 0 )
    7399 weights[i] = 0.0;
    7400 else
    7401 {
    7402 assert( SCIPisFeasPositive(scip, sum * (SCIP_Real)nviols));
    7403 val = MIN(1e6, val);
    7404 weights[i] = ( val + SCIPsumepsilon(scip) ) / ( sum * (SCIP_Real)nviols + SCIPsumepsilon(scip) );
    7405 }
    7406 }
    7407 }
    7408 }
    7409
    7410 return SCIP_OKAY;
    7411}
    7412
    7413
    7414/* marks neighbors of a given node as not a member of the maximal independent set */
    7415static
    7417 SCIP* scip, /**< SCIP pointer */
    7418 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
    7419 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    7420 int node, /**< node of the conflict graph */
    7421 SCIP_Bool* mark, /**< indicator vector of processed nodes */
    7422 SCIP_Bool* indset, /**< indicator vector of current independent */
    7423 int* cnt, /**< pointer to store number of marked nodes */
    7424 SCIP_Bool* cutoff /**< pointer to store whether operation is infeasible */
    7425 )
    7426{
    7427 int nsucc;
    7428 int* succ;
    7429 int j;
    7430
    7431 assert( scip != NULL );
    7432 assert( conflictgraph != NULL );
    7433 assert( mark != NULL );
    7434 assert( indset != NULL );
    7435 assert( cutoff != NULL );
    7436 assert( cnt != NULL );
    7437
    7438 *cutoff = FALSE;
    7439
    7440 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
    7441 succ = SCIPdigraphGetSuccessors(conflictgraph, node);
    7442
    7443 /* for all successors */
    7444 for (j = 0; j < nsucc && !(*cutoff); ++j)
    7445 {
    7446 int succj;
    7447
    7448 succj = succ[j];
    7449 assert( indset[succj] == 0 );
    7450 if( ! mark[succj] )
    7451 {
    7452 SCIP_VARSTATUS varstatus;
    7453 SCIP_VAR* var;
    7454
    7455 /* mark node as processed */
    7456 mark[succj] = TRUE;
    7457 ++(*cnt);
    7458
    7459 /* get variable and variable status corresponding to successor node */
    7460 var = SCIPnodeGetVarSOS1(conflictgraph, succj);
    7461 varstatus = SCIPvarGetStatus(var);
    7462
    7463 /* if variable is aggregated */
    7464 if ( varstatus == SCIP_VARSTATUS_AGGREGATED )
    7465 {
    7466 int aggrnode;
    7467
    7468 aggrnode = SCIPvarGetNodeSOS1(conshdlr, SCIPvarGetAggrVar(var));
    7469
    7470 /* if aggregated variable is an SOS1 variable */
    7471 if ( aggrnode >= 0 )
    7472 {
    7473 /* if aggregated variable is implied to be zero */
    7475 {
    7476 if ( ! mark[aggrnode] )
    7477 {
    7478 mark[aggrnode] = TRUE;
    7479 ++(*cnt);
    7480 }
    7481 else if ( indset[aggrnode] == 1 )
    7482 {
    7483 *cutoff = TRUE;
    7484 return SCIP_OKAY;
    7485 }
    7486 }
    7487 else
    7488 {
    7489 /* if aggregated variable is not already a member of the maximal independent set */
    7490 if ( indset[aggrnode] == 0 )
    7491 {
    7492 /* if variable is already marked */
    7493 if ( mark[aggrnode] )
    7494 {
    7495 *cutoff = TRUE;
    7496 return SCIP_OKAY;
    7497 }
    7498 else
    7499 {
    7500 indset[aggrnode] = 1;
    7501 mark[aggrnode] = TRUE;
    7502 ++(*cnt);
    7503 }
    7504
    7505 /* mark neighbors of aggregated variable */
    7506 SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, aggrnode, mark, indset, cnt, cutoff) );
    7507 }
    7508 }
    7509 }
    7510 }
    7511 else if ( varstatus == SCIP_VARSTATUS_NEGATED )
    7512 {
    7513 int negnode;
    7514
    7515 negnode = SCIPvarGetNodeSOS1(conshdlr, SCIPvarGetNegationVar(var));
    7516
    7517 /* if negated variable is an SOS1 variable */
    7518 if ( negnode >= 0 )
    7519 {
    7521 {
    7522 if ( indset[negnode] == 1 )
    7523 {
    7524 *cutoff = TRUE;
    7525 return SCIP_OKAY;
    7526 }
    7527 else if ( ! mark[negnode] )
    7528 {
    7529 mark[negnode] = TRUE;
    7530 ++(*cnt);
    7531 }
    7532 }
    7533 }
    7534 }
    7535 }
    7536 }
    7537
    7538 return SCIP_OKAY;
    7539}
    7540
    7541
    7542/** calls greedy algorithm for the maximum weighted independent set problem (MWIS)
    7543 *
    7544 * We compute a feasible solution to
    7545 * \f[
    7546 * \begin{array}{ll}
    7547 * \min\limits_{z} & {x^*}^T z \\
    7548 * & z_i + z_j \leq 1, \qquad (i,j)\in E \\
    7549 * & z_i \in \{0,1\}, \qquad\quad i\in V
    7550 * \end{array}
    7551 * \f]
    7552 * by the algorithm GGWMIN of Shuichi Sakai, Mitsunori Togasaki and Koichi Yamazaki in "A note on greedy algorithms for the
    7553 * maximum weighted independent set problem", Discrete Applied Mathematics. Here \f$x^*\f$ denotes the current LP
    7554 * relaxation solution. Note that the solution of the MWIS is the indicator vector of an independent set.
    7555 */
    7556static
    7558 SCIP* scip, /**< SCIP pointer */
    7559 SCIP_SOL* sol, /**< primal solution or NULL for current LP solution */
    7560 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
    7561 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    7562 int nsos1vars, /**< number of SOS1 variables */
    7563 SCIP_Bool* indicatorzero, /**< vector that indicates which variables are currently fixed to zero */
    7564 SCIP_Bool* indset /**< pointer to store indicator vector of an independent set */
    7565 )
    7566{
    7567 SCIP_Bool* mark = NULL;
    7568 SCIP_Real* weights = NULL;
    7569 int* indscipvars = NULL;
    7570 int ind;
    7571 int nsucc;
    7572 int i;
    7573 int k;
    7574
    7575 assert( scip != NULL );
    7576 assert( conflictgraph != NULL );
    7577 assert( indicatorzero != NULL );
    7578 assert( indset != NULL );
    7579
    7580 /* allocate buffer arrays */
    7581 SCIP_CALL( SCIPallocBufferArray(scip, &mark, nsos1vars) );
    7582 SCIP_CALL( SCIPallocBufferArray(scip, &weights, nsos1vars) );
    7583 SCIP_CALL( SCIPallocBufferArray(scip, &indscipvars, nsos1vars) );
    7584
    7585 /* sort SOS1 variables in nonincreasing order of weights */
    7586 for (i = 0; i < nsos1vars; ++i)
    7587 indscipvars[i] = i;
    7588
    7589 SCIP_CALL( getVectorOfWeights(scip, sol, conflictgraph, nsos1vars, indicatorzero, weights) );
    7590 SCIPsortDownRealInt(weights, indscipvars, nsos1vars);
    7591
    7592 /* mark fixed variables and variables without any neighbors in the conflict graph */
    7593 k = 0;
    7594 for (i = 0; i < nsos1vars; ++i)
    7595 {
    7596 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
    7597
    7598 if ( indset[i] == 0 )
    7599 {
    7600 if( indicatorzero[i] )
    7601 {
    7602 mark[i] = TRUE;
    7603 ++k;
    7604 }
    7605 else if ( nsucc == 0 )
    7606 {
    7607 indset[i] = 1;
    7608 mark[i] = TRUE;
    7609 ++k;
    7610 }
    7611 else
    7612 mark[i] = FALSE;
    7613 }
    7614 else
    7615 {
    7616 SCIP_Bool cutoff;
    7617
    7618 ++k;
    7619 mark[i] = TRUE;
    7620
    7621 SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, i, mark, indset, &k, &cutoff) );
    7622 assert( ! cutoff );
    7623 }
    7624 }
    7625
    7626 /* mark vertices in the order of their largest weight */
    7627 for (i = 0; k < nsos1vars; ++i) /*lint !e440*/
    7628 {
    7629 assert( i < nsos1vars );
    7630
    7631 ind = indscipvars[i];
    7632
    7633 if ( ! mark[ind] )
    7634 {
    7635 SCIP_Bool cutoff;
    7636
    7637 /* mark ind */
    7638 indset[ind] = 1;
    7639 mark[ind] = TRUE;
    7640 ++k;
    7641
    7642 SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, ind, mark, indset, &k, &cutoff) );
    7643 if ( cutoff )
    7644 indset[ind] = 0;
    7645 }
    7646 }
    7647 assert( k == nsos1vars );
    7648
    7649 /* free buffer arrays */
    7650 SCIPfreeBufferArrayNull(scip, &indscipvars);
    7651 SCIPfreeBufferArrayNull(scip, &weights);
    7653
    7654 return SCIP_OKAY;
    7655}
    7656
    7657
    7658/** based on solution values of the variables, fixes variables of the conflict graph to zero to turn all SOS1 constraints feasible
    7659 *
    7660 * if the SOS1 constraints do not overlap, the method makeSOS1constraintsFeasible() may be faster
    7661 */
    7662static
    7664 SCIP* scip, /**< SCIP pointer */
    7665 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
    7666 SCIP_SOL* sol, /**< solution */
    7667 SCIP_Bool* changed, /**< pointer to store whether the solution has been changed */
    7668 SCIP_Bool* allroundable /**< pointer to store whether all variables are roundable */
    7669 )
    7670{
    7671 SCIP_DIGRAPH* conflictgraph; /* conflict graph for SOS1 constraints */
    7672 SCIP_Bool* indicatorzero; /* indicates which solution values are zero */
    7673 SCIP_Bool* indset; /* indicator vector of feasible solution; i.e., an independent set */
    7674 int nsos1vars;
    7675 int j;
    7676
    7677 assert( scip != NULL );
    7678 assert( conshdlr != NULL );
    7679 assert( sol != NULL );
    7680 assert( changed != NULL );
    7681 assert( allroundable != NULL );
    7682
    7683 *allroundable = TRUE;
    7684 *changed = FALSE;
    7685
    7686 /* get number of SOS1 variables */
    7687 nsos1vars = SCIPgetNSOS1Vars(conshdlr);
    7688 assert( nsos1vars >= 0 );
    7689
    7690 /* get conflict graph */
    7691 conflictgraph = SCIPgetConflictgraphSOS1(conshdlr);
    7692 assert( conflictgraph != NULL );
    7693
    7694 /* allocate buffer arrays */
    7695 SCIP_CALL( SCIPallocBufferArray(scip, &indset, nsos1vars) );
    7696 SCIP_CALL( SCIPallocBufferArray(scip, &indicatorzero, nsos1vars) );
    7697
    7698 /* determine if variables with nonzero solution value are roundable */
    7699 for (j = 0; j < nsos1vars; ++j)
    7700 {
    7701 SCIP_VAR* var;
    7702 SCIP_Real lb;
    7703 SCIP_Real ub;
    7704
    7705 var = SCIPnodeGetVarSOS1(conflictgraph, j);
    7706 lb = SCIPvarGetLbLocal(var);
    7707 ub = SCIPvarGetUbLocal(var);
    7708 indset[j] = 0;
    7709
    7710 /* if solution value of variable is zero */
    7711 if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, var)) )
    7712 indicatorzero[j] = TRUE;
    7713 else
    7714 {
    7715 indicatorzero[j] = FALSE;
    7716
    7717 /* if variable is not roundable */
    7718 if ( ! SCIPvarMayRoundDown(var) && ! SCIPvarMayRoundUp(var) )
    7719 {
    7720 *allroundable = FALSE;
    7721 break;
    7722 }
    7723
    7724 /* if bounds of variable are fixed to zero */
    7725 if ( SCIPisFeasZero(scip, ub) && SCIPisFeasZero(scip, lb) )
    7726 indicatorzero[j] = TRUE;
    7727 else if ( SCIPisFeasPositive(scip, lb) || SCIPisFeasNegative(scip, ub) ) /* if variable is fixed to be nonzero */
    7728 indset[j] = 1;
    7729 }
    7730 }
    7731
    7732 /* return if at least one SOS1 variable is not roundable */
    7733 if ( ! (*allroundable) )
    7734 {
    7735 SCIPfreeBufferArray(scip, &indicatorzero);
    7736 SCIPfreeBufferArray(scip, &indset);
    7737 return SCIP_OKAY;
    7738 }
    7739
    7740 /* call greedy algorithm for the maximum weighted independent set problem */
    7741 SCIP_CALL( maxWeightIndSetHeuristic(scip, sol, conshdlr, conflictgraph, nsos1vars, indicatorzero, indset) );
    7742
    7743 /* make solution feasible */
    7744 for (j = 0; j < nsos1vars; ++j)
    7745 {
    7746 if ( indset[j] == 0 )
    7747 {
    7748 SCIP_CALL( SCIPsetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, j), 0.0) );
    7749 *changed = TRUE;
    7750 }
    7751 }
    7752
    7753 /* free buffer arrays */
    7754 SCIPfreeBufferArray(scip, &indicatorzero);
    7755 SCIPfreeBufferArray(scip, &indset);
    7756
    7757#ifdef SCIP_NDEBUG
    7758 {
    7759 SCIP_CONSDATA* consdata;
    7760 SCIP_CONS** conss;
    7761 int nconss;
    7762 int c;
    7763
    7764 conss = SCIPconshdlrGetConss(conshdlr);
    7765 nconss = SCIPconshdlrGetNConss(conshdlr);
    7766 for (c = 0; c < nconss; ++c)
    7767 {
    7768 int cnt = 0;
    7769 consdata = SCIPconsGetData(conss[c]);
    7770 assert( consdata != NULL );
    7771
    7772 for (j = 0; j < consdata->nvars; ++j)
    7773 {
    7774 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) )
    7775 {
    7776 ++cnt;
    7777 }
    7778 }
    7779 assert( cnt < 2 );
    7780 }
    7781 }
    7782#endif
    7783
    7784 return SCIP_OKAY;
    7785}
    7786
    7787
    7788/** based on solution values of the variables, fixes variables of the SOS1 constraints to zero to turn these constraints feasible
    7789 *
    7790 * if the SOS1 constraints overlap, the method makeSOS1constraintsFeasible() may result in better primal solutions
    7791 */
    7792static
    7794 SCIP* scip, /**< SCIP pointer */
    7795 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
    7796 SCIP_SOL* sol, /**< solution */
    7797 SCIP_Bool* changed, /**< pointer to store whether the solution has been changed */
    7798 SCIP_Bool* allroundable /**< pointer to store whether all variables are roundable */
    7799 )
    7800{
    7801 SCIP_CONSDATA* consdata;
    7802 SCIP_CONS** conss;
    7803 int nconss;
    7804 int c;
    7805
    7806 assert( scip != NULL );
    7807 assert( conshdlr != NULL );
    7808 assert( sol != NULL );
    7809 assert( changed != NULL );
    7810 assert( allroundable != NULL );
    7811
    7812 *allroundable = TRUE;
    7813 *changed = FALSE;
    7814
    7815 /* get SOS1 constraints and number of SOS1 constraints */
    7816 conss = SCIPconshdlrGetConss(conshdlr);
    7817 nconss = SCIPconshdlrGetNConss(conshdlr);
    7818 assert( nconss > 0 );
    7819
    7820 /* loop through all SOS1 constraints */
    7821 for (c = 0; c < nconss && *allroundable; ++c)
    7822 {
    7823 SCIP_CONS* cons;
    7824 SCIP_VAR** vars;
    7825 SCIP_Bool varisfixed = FALSE;
    7826 SCIP_Real maxval = 0.0;
    7827 int pos = -1;
    7828 int nvars;
    7829 int j;
    7830
    7831 cons = conss[c];
    7832 assert( cons != NULL );
    7833 consdata = SCIPconsGetData(cons);
    7834 assert( consdata != NULL );
    7835
    7836 nvars = consdata->nvars;
    7837 vars = consdata->vars;
    7838
    7839 /* search for maximum solution value */
    7840 for (j = 0; j < nvars; ++j)
    7841 {
    7842 SCIP_VAR* var;
    7843
    7844 var = vars[j];
    7845
    7846 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, var)) )
    7847 {
    7848 SCIP_Real lb;
    7849 SCIP_Real ub;
    7850
    7851 lb = SCIPvarGetLbLocal(var);
    7852 ub = SCIPvarGetUbLocal(var);
    7853
    7854 /* if variable is not roundable */
    7855 if ( ! SCIPvarMayRoundDown(var) && ! SCIPvarMayRoundUp(var) )
    7856 {
    7857 *allroundable = FALSE;
    7858 break;
    7859 }
    7860
    7861 /* it is possible that the bounds were proagated to zero although the current solution value is nonzero
    7862 * in this case fix the solution value to zero */
    7863 if ( SCIPisFeasZero(scip, ub) && SCIPisFeasZero(scip, lb) )
    7864 {
    7865 SCIP_CALL( SCIPsetSolVal(scip, sol, var, 0.0) );
    7866 *changed = TRUE;
    7867 }
    7868 else if ( SCIPisFeasPositive(scip, lb) || SCIPisFeasNegative(scip, ub) ) /* if variable is fixed to be nonzero */
    7869 {
    7870 assert( ! varisfixed );
    7871 varisfixed = TRUE;
    7872 maxval = SCIPgetSolVal(scip, sol, var);
    7873 pos = j;
    7874 }
    7875 else if ( ! varisfixed && SCIPisFeasGT(scip, REALABS(SCIPgetSolVal(scip, sol, var)), REALABS(maxval)) ) /* search for variable with maximum solution value */
    7876 {
    7877 maxval = SCIPgetSolVal(scip, sol, var);
    7878 pos = j;
    7879 }
    7880
    7881 /* fix variable to zero; the solution value of the variable with maximum solution value
    7882 * will be restored in a later step */
    7883 SCIP_CALL( SCIPsetSolVal(scip, sol, var, 0.0) );
    7884 *changed = TRUE;
    7885 }
    7886 }
    7887
    7888 if ( ! (*allroundable) )
    7889 break;
    7890 else if ( pos >= 0 ) /* restore solution of variable with maximum solution value */
    7891 {
    7892 SCIP_CALL( SCIPsetSolVal(scip, sol, vars[pos], maxval) );
    7893 }
    7894 }
    7895
    7896#ifdef SCIP_NDEBUG
    7897 if ( *allroundable )
    7898 {
    7899 for (c = 0; c < nconss; ++c)
    7900 {
    7901 int cnt = 0;
    7902 int j;
    7903
    7904 consdata = SCIPconsGetData(conss[c]);
    7905 assert( consdata != NULL );
    7906
    7907 for (j = 0; j < consdata->nvars; ++j)
    7908 {
    7909 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) )
    7910 {
    7911 ++cnt;
    7912 }
    7913 }
    7914 assert( cnt < 2 );
    7915 }
    7916 }
    7917#endif
    7918
    7919 return SCIP_OKAY;
    7920}
    7921
    7922
    7923/** determine a diving variables and boundchanges of diving variables by analyzing the conflict graph
    7924 *
    7925 * if the SOS1 constraints do not overlap, the method getDiveBdChgsSOS1constraints() may be faster
    7926 */
    7927static
    7929 SCIP* scip, /**< SCIP pointer */
    7930 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
    7931 SCIP_DIVESET* diveset, /**< diving settings */
    7932 SCIP_SOL* sol, /**< solution */
    7933 SCIP_Bool* success /**< pointer to store */
    7934 )
    7935{
    7936 SCIP_DIGRAPH* conflictgraph;
    7937 SCIP_VAR* bestvar = NULL;
    7938 SCIP_Bool bestvarfixneigh = FALSE;
    7939 SCIP_Real bestscore = SCIP_REAL_MIN;
    7940 int bestnode = -1;
    7941 int nsos1vars;
    7942 int v;
    7943
    7944 assert( scip != NULL );
    7945 assert( conshdlr != NULL );
    7946 assert( diveset != NULL );
    7947 assert( success != NULL );
    7948
    7949 *success = FALSE;
    7950
    7951 /* get number of SOS1 variables */
    7952 nsos1vars = SCIPgetNSOS1Vars(conshdlr);
    7953
    7954 /* get conflict graph of SOS1 constraints */
    7955 conflictgraph = SCIPgetConflictgraphSOS1(conshdlr);
    7956
    7957 /* loop over SOS1 variables */
    7958 for (v = 0; v < nsos1vars; ++v)
    7959 {
    7960 /* check whether the variable violates an SOS1 constraint together with at least one other variable */
    7961 if ( isViolatedSOS1(scip, conflictgraph, v, sol) )
    7962 {
    7963 SCIP_VAR* var;
    7964 SCIP_Real solval;
    7965 SCIP_Real score;
    7967 SCIP_Real fracval;
    7968 SCIP_Bool fixneigh;
    7969
    7970 var = SCIPnodeGetVarSOS1(conflictgraph, v);
    7971 solval = SCIPgetSolVal(scip, sol, var);
    7972
    7973 /* compute (variable) bound of candidate */
    7974 if ( SCIPisFeasNegative(scip, solval) )
    7975 bound = nodeGetSolvalVarboundLbSOS1(scip, conflictgraph, sol, v);
    7976 else
    7977 bound = nodeGetSolvalVarboundUbSOS1(scip, conflictgraph, sol, v);
    7978
    7979 /* ensure finiteness */
    7980 bound = MIN(DIVINGCUTOFFVALUE, REALABS(bound)); /*lint !e666*/
    7981 fracval = MIN(DIVINGCUTOFFVALUE, REALABS(solval)); /*lint !e666*/
    7982 assert( ! SCIPisInfinity(scip, bound) );
    7983 assert( ! SCIPisInfinity(scip, fracval) );
    7984 assert( SCIPisPositive(scip, bound) );
    7985
    7986 /* bound may have changed in propagation; ensure that fracval <= 1 */
    7987 if ( SCIPisFeasLT(scip, bound, fracval) )
    7988 bound = fracval;
    7989
    7990 /* get fractionality of candidate */
    7991 fracval /= (bound + SCIPsumepsilon(scip));
    7992
    7993 /* should SOS1 variables be scored by the diving heuristics specific score function;
    7994 * otherwise use the score function of the SOS1 constraint handler */
    7996 {
    7997 SCIP_Bool roundup;
    7998
    7999 SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_SOS1VARIABLE, var, solval, fracval,
    8000 &score, &roundup) );
    8001
    8002 fixneigh = roundup;
    8003 if ( SCIPisFeasNegative(scip, solval) )
    8004 fixneigh = !fixneigh;
    8005 }
    8006 else
    8007 {
    8008 /* we always fix the candidates neighbors in the conflict graph to zero */
    8009 fixneigh = TRUE;
    8010
    8011 /* score fractionality of candidate */
    8012 score = fracval;
    8013 }
    8014
    8015 /* best candidate maximizes the score */
    8016 if ( score > bestscore )
    8017 {
    8018 bestscore = score;
    8019
    8020 *success = TRUE;
    8021 bestvar = var;
    8022 bestnode = v;
    8023 bestvarfixneigh = fixneigh;
    8024 }
    8025 }
    8026 }
    8027 assert( !(*success) || bestvar != NULL );
    8028
    8029 if ( *success )
    8030 {
    8031 int* succ;
    8032 int nsucc;
    8033 int s;
    8034
    8035 assert( bestnode >= 0 && bestnode < nsos1vars );
    8036
    8037 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, bestnode);
    8038 succ = SCIPdigraphGetSuccessors(conflictgraph, bestnode);
    8039
    8040 /* if the diving score voted for fixing the best variable to 0.0, we add this as the preferred bound change;
    8041 * otherwise, fixing the neighbors in the conflict graph to 0.0 is the preferred bound change.
    8042 */
    8044 SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_FIXED, 0.0, !bestvarfixneigh) );
    8045 for (s = 0; s < nsucc; ++s)
    8046 {
    8047 SCIP_VAR* var;
    8048
    8049 var = SCIPnodeGetVarSOS1(conflictgraph, succ[s]);
    8050
    8051 /* if variable is not already fixed */
    8053 {
    8054 SCIP_CALL( SCIPaddDiveBoundChange(scip, var, SCIP_BRANCHDIR_FIXED, 0.0, bestvarfixneigh) );
    8055 }
    8056 }
    8057 }
    8058
    8059 return SCIP_OKAY;
    8060}
    8061
    8062
    8063/** determine a diving variables and boundchanges of diving variables by analyzing the SOS1 constraints
    8064 *
    8065 * if the SOS1 constraints overlap, the method getDiveBdChgsSOS1conflictgraph() may produce better results (e.g., due to more
    8066 * diving candidates)
    8067 */
    8068static
    8070 SCIP* scip, /**< SCIP pointer */
    8071 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
    8072 SCIP_DIVESET* diveset, /**< diving settings */
    8073 SCIP_SOL* sol, /**< solution */
    8074 SCIP_Bool* success /**< pointer to store */
    8075 )
    8076{
    8077 SCIP_VAR* bestvar = NULL;
    8078 SCIP_Bool bestvarfixcomp = FALSE;
    8079 SCIP_Real bestscore = SCIP_REAL_MIN;
    8080 SCIP_CONSDATA* consdata;
    8081 SCIP_CONS** conss;
    8082 int nconss;
    8083 int bestcons = -1;
    8084 int c;
    8085
    8086 assert( scip != NULL );
    8087 assert( conshdlr != NULL );
    8088 assert( diveset != NULL );
    8089 assert( success != NULL );
    8090
    8091 *success = FALSE;
    8092
    8093 /* get SOS1 constraints and number of SOS1 constraints */
    8094 conss = SCIPconshdlrGetConss(conshdlr);
    8095 nconss = SCIPconshdlrGetNConss(conshdlr);
    8096
    8097 /* loop through all SOS1 constraints */
    8098 for (c = 0; c < nconss; ++c)
    8099 {
    8100 SCIP_VAR** vars;
    8101 int nvars;
    8102 int cnt = 0;
    8103 int j;
    8104
    8105 consdata = SCIPconsGetData(conss[c]);
    8106 assert( consdata != NULL );
    8107
    8108 nvars = consdata->nvars;
    8109 vars = consdata->vars;
    8110
    8111 /* check whether SOS1 constraint is violated */
    8112 for (j = 0; j < nvars && cnt < 2; ++j)
    8113 {
    8114 SCIP_VAR* var;
    8115
    8116 var = vars[j];
    8117
    8118 /* check whether variable is nonzero w.r.t. sol and the bounds have not been fixed to zero by propagation */
    8119 if ( !SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, var))
    8121 ++cnt;
    8122 }
    8123
    8124 /* if SOS1 constraint is not violated then continue with the next SOS1 constraint */
    8125 if ( cnt < 2 )
    8126 continue;
    8127
    8128 /* get diving score of every variable in constraint */
    8129 for (j = 0; j < nvars; ++j)
    8130 {
    8131 SCIP_VAR* var;
    8132 SCIP_Real solval;
    8133 SCIP_Real score;
    8135 SCIP_Real fracval;
    8136 SCIP_Real lb;
    8137 SCIP_Real ub;
    8138 SCIP_Bool fixcomp; /* whether to fix the complementary variables of the candidate in the SOS1 constraint to zero */
    8139
    8140 var = vars[j];
    8141 solval = SCIPgetSolVal(scip, sol, var);
    8142 lb = SCIPvarGetLbLocal(var);
    8143 ub = SCIPvarGetUbLocal(var);
    8144
    8145 /* check whether variable is nonzero w.r.t. sol and the bounds have not been fixed to zero by propagation */
    8146 if ( ! SCIPisFeasZero(scip, solval) && ( ! SCIPisFeasZero(scip, lb) || ! SCIPisFeasZero(scip, ub) ) )
    8147 {
    8148 /* compute (variable) bound of candidate */
    8149 if ( SCIPisFeasNegative(scip, solval) )
    8150 bound = lb;
    8151 else
    8152 bound = ub;
    8153
    8154 /* bound may have changed in propagation; ensure that fracval <= 1 */
    8155 if ( SCIPisFeasLT(scip, REALABS(bound), REALABS(solval)) )
    8156 bound = solval;
    8157
    8158 /* ensure finiteness */
    8159 bound = MIN(DIVINGCUTOFFVALUE, REALABS(bound)); /*lint !e666*/
    8160 fracval = MIN(DIVINGCUTOFFVALUE, REALABS(solval)); /*lint !e666*/
    8161 assert( ! SCIPisInfinity(scip, bound) );
    8162 assert( ! SCIPisInfinity(scip, fracval) );
    8163 assert( SCIPisPositive(scip, bound) );
    8164
    8165 /* get fractionality of candidate */
    8166 fracval /= (bound + SCIPsumepsilon(scip));
    8167
    8168 /* should SOS1 variables be scored by the diving heuristics specific score function;
    8169 * otherwise use the score function of the SOS1 constraint handler
    8170 */
    8172 {
    8173 SCIP_Bool roundup;
    8174
    8175 SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_SOS1VARIABLE, var, solval, fracval,
    8176 &score, &roundup) );
    8177
    8178 fixcomp = roundup;
    8179 if ( SCIPisFeasNegative(scip, solval) )
    8180 fixcomp = !fixcomp;
    8181 }
    8182 else
    8183 {
    8184 /* we always fix the complementary variables of the candidate in the SOS1 constraint to zero */
    8185 fixcomp = TRUE;
    8186
    8187 /* score fractionality of candidate */
    8188 score = fracval;
    8189 }
    8190
    8191 /* best candidate maximizes the score */
    8192 if ( score > bestscore )
    8193 {
    8194 bestscore = score;
    8195
    8196 *success = TRUE;
    8197 bestvar = var;
    8198 bestcons = c;
    8199 bestvarfixcomp = fixcomp;
    8200 }
    8201 }
    8202 }
    8203 }
    8204 assert( !(*success) || bestvar != NULL );
    8205
    8206 if ( *success )
    8207 {
    8208 SCIP_VAR** vars;
    8209 int nvars;
    8210 int j;
    8211
    8212 consdata = SCIPconsGetData(conss[bestcons]);
    8213 assert( consdata != NULL );
    8214
    8215 nvars = consdata->nvars;
    8216 vars = consdata->vars;
    8217
    8218 assert( bestcons >= 0 && bestcons < nconss );
    8219
    8220 /* if the diving score voted for fixing the best variable to 0.0, we add this as the preferred bound change;
    8221 * otherwise, fixing the complementary variables of the candidate in the SOS1 constraint to 0.0 is the preferred bound change.
    8222 */
    8224
    8225 SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_FIXED, 0.0, !bestvarfixcomp) );
    8226 for (j = 0; j < nvars; ++j)
    8227 {
    8228 SCIP_VAR* var;
    8229
    8230 var = vars[j];
    8231
    8232 /* if variable is not already fixed and is not the candidate variable */
    8233 if ( var != bestvar && ( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var)) ) )
    8234 {
    8235 SCIP_CALL( SCIPaddDiveBoundChange(scip, var, SCIP_BRANCHDIR_FIXED, 0.0, bestvarfixcomp) );
    8236 }
    8237 }
    8238 }
    8239
    8240 return SCIP_OKAY;
    8241}
    8242
    8243
    8244/* --------------------initialization/deinitialization ------------------------*/
    8245
    8246/** check whether \f$x_1\f$ is a bound variable of \f$x_0\f$; i.e., \f$x_0 \leq c\cdot x_1\f$ or \f$x_0 \geq d\cdot x_1\f$
    8247 * for positive values \f$c, d\f$. If true, then add this information to the node data of the conflict graph.
    8248 */
    8249static
    8251 SCIP* scip, /**< SCIP pointer */
    8252 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */
    8253 SCIP_VAR* var0, /**< first variable */
    8254 SCIP_VAR* var1, /**< second variable */
    8255 SCIP_Real val0, /**< first coefficient */
    8256 SCIP_Real val1 /**< second coefficient */
    8257 )
    8258{
    8259 int node0;
    8260
    8261 assert( scip != NULL );
    8262 assert( conshdlrdata != NULL );
    8263 assert( var0 != NULL && var1 != NULL );
    8264
    8265 /* get nodes of variable in the conflict graph (node = -1 if no SOS1 variable) */
    8266 node0 = varGetNodeSOS1(conshdlrdata, var0);
    8267
    8268 /* if var0 is an SOS1 variable */
    8269 if ( node0 >= 0 )
    8270 {
    8271 SCIP_Real val;
    8272
    8273 assert( ! SCIPisFeasZero(scip, val0) );
    8274 val = -val1/val0;
    8275
    8276 /* check variable bound relation of variables */
    8277
    8278 /* handle lower bound case */
    8279 if ( SCIPisFeasNegative(scip, val0) && SCIPisFeasNegative(scip, val) )
    8280 {
    8282
    8283 /* get node data of the conflict graph */
    8284 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, node0);
    8285
    8286 /* @todo: maybe save multiple variable bounds for each SOS1 variable */
    8287 if ( nodedata->lbboundvar == NULL )
    8288 {
    8289 /* add variable bound information to node data */
    8290 nodedata->lbboundvar = var1;
    8291 nodedata->lbboundcoef = val;
    8292
    8293 SCIPdebugMsg(scip, "detected variable bound constraint %s >= %f %s.\n", SCIPvarGetName(var0), val, SCIPvarGetName(var1));
    8294 }
    8295 }
    8296 /* handle upper bound case */
    8297 else if ( SCIPisFeasPositive(scip, val0) && SCIPisFeasPositive(scip, val) )
    8298 {
    8300 assert( SCIPisFeasPositive(scip, val0) );
    8301
    8302 /* get node data of the conflict graph */
    8303 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, node0);
    8304
    8305 if ( nodedata->ubboundvar == NULL )
    8306 {
    8307 /* add variable bound information to node data */
    8308 nodedata->ubboundvar = var1;
    8309 nodedata->ubboundcoef = val;
    8310
    8311 SCIPdebugMsg(scip, "detected variable bound constraint %s <= %f %s.\n", SCIPvarGetName(var0), val, SCIPvarGetName(var1));
    8312 }
    8313 }
    8314 }
    8315
    8316 return SCIP_OKAY;
    8317}
    8318
    8319
    8320/** pass connected component \f$C\f$ of the conflict graph and check whether all the variables correspond to a unique variable upper bound variable \f$z\f$,
    8321 * i.e., \f$x_i \leq u_i z\f$ for every \f$i\in C\f$.
    8322 *
    8323 * @note if the bound variable is unique, then bound inequalities can be strengthened.
    8324 */
    8325static
    8327 SCIP* scip, /**< SCIP pointer */
    8328 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    8329 int node, /**< current node of connected component */
    8330 SCIP_VAR* boundvar, /**< bound variable of connected component */
    8331 SCIP_Bool checklb, /**< whether to check lower bound variable (else upper bound variable) */
    8332 SCIP_Bool* processed, /**< states for each variable whether it has been processed */
    8333 int* concomp, /**< current connected component */
    8334 int* nconcomp, /**< pointer to store number of elements of connected component */
    8335 SCIP_Bool* unique /**< pointer to store whether bound variable is unique */
    8336 )
    8337{
    8338 int* succ;
    8339 int nsucc;
    8340 int s;
    8341
    8342 assert( scip != NULL );
    8343 assert( conflictgraph != NULL );
    8344 assert( processed != NULL );
    8345 assert( concomp != NULL );
    8346 assert( nconcomp != NULL );
    8347 assert( unique != NULL );
    8348
    8349 processed[node] = TRUE;/*lint !e737*/
    8350 concomp[(*nconcomp)++] = node;
    8351
    8352 /* if bound variable of connected component without new node is unique */
    8353 if ( *unique )
    8354 {
    8356 SCIP_VAR* comparevar;
    8357 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
    8358 assert( nodedata != NULL );
    8359
    8360 if ( checklb )
    8361 comparevar = nodedata->lbboundvar;
    8362 else
    8363 comparevar = nodedata->ubboundvar;
    8364
    8365 /* check whether bound variable is unique for connected component without new node */
    8366 if ( boundvar == NULL )
    8367 {
    8368 if ( comparevar != NULL )
    8369 *unique = FALSE;
    8370 }
    8371 else
    8372 {
    8373 if ( comparevar == NULL )
    8374 *unique = FALSE;
    8375 else if ( SCIPvarCompare(boundvar, comparevar) != 0 )
    8376 *unique = FALSE;
    8377 }
    8378 }
    8379
    8380 /* pass through successor variables */
    8381 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
    8382 succ = SCIPdigraphGetSuccessors(conflictgraph, node);
    8383 for (s = 0; s < nsucc; ++s)
    8384 {
    8385 if ( ! processed[succ[s]] )
    8386 SCIP_CALL( passConComponentVarbound(scip, conflictgraph, succ[s], boundvar, checklb, processed, concomp, nconcomp, unique) );
    8387 }
    8388
    8389 return SCIP_OKAY;
    8390}
    8391
    8392
    8393/** for each connected component \f$C\f$ of the conflict graph check whether all the variables correspond to a unique variable upper bound variable \f$z\f$
    8394 * (e.g., for the upper bound case this means that \f$x_i \leq u_i z\f$ for every \f$i\in C\f$).
    8395 *
    8396 * @note if the bound variable is unique, then bound inequalities can be strengthened.
    8397 */
    8398static
    8400 SCIP* scip, /**< SCIP pointer */
    8401 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    8402 int nsos1vars, /**< number of SOS1 variables */
    8403 SCIP_Bool checklb /**< whether to check lower bound variable (else check upper bound variable) */
    8404 )
    8405{
    8406 SCIP_Bool* processed; /* states for each variable whether it has been processed */
    8407 int* concomp; /* current connected component */
    8408 int nconcomp;
    8409 int j;
    8410
    8411 assert( scip != NULL );
    8412 assert( conflictgraph != NULL );
    8413
    8414 /* allocate buffer arrays and initialize 'processed' array */
    8415 SCIP_CALL( SCIPallocBufferArray(scip, &processed, nsos1vars) );
    8416 SCIP_CALL( SCIPallocBufferArray(scip, &concomp, nsos1vars) );
    8417 for (j = 0; j < nsos1vars; ++j)
    8418 processed[j] = FALSE;
    8419
    8420 /* run through all SOS1 variables */
    8421 for (j = 0; j < nsos1vars; ++j)
    8422 {
    8423 /* if variable belongs to a connected component that has not been processed so far */
    8424 if ( ! processed[j] )
    8425 {
    8427 SCIP_VAR* boundvar;
    8428 SCIP_Bool unique;
    8429 int* succ;
    8430 int nsucc;
    8431 int s;
    8432
    8433 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, j);
    8434 assert( nodedata != NULL );
    8435
    8436 if ( checklb )
    8437 boundvar = nodedata->lbboundvar;
    8438 else
    8439 boundvar = nodedata->ubboundvar;
    8440 unique = TRUE;
    8441
    8442 processed[j] = TRUE;
    8443 concomp[0] = j;
    8444 nconcomp = 1;
    8445
    8446 /* pass through successor variables */
    8447 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
    8448 succ = SCIPdigraphGetSuccessors(conflictgraph, j);
    8449 for (s = 0; s < nsucc; ++s)
    8450 {
    8451 if ( ! processed[succ[s]] )
    8452 {
    8453 SCIP_CALL( passConComponentVarbound(scip, conflictgraph, succ[s], boundvar, checklb, processed, concomp, &nconcomp, &unique) );
    8454 }
    8455 }
    8456
    8457 /* if the connected component has a unique bound variable */
    8458 if ( unique && boundvar != NULL )
    8459 {
    8460 for (s = 0; s < nconcomp; ++s)
    8461 {
    8462 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, concomp[s]);
    8463 assert( processed[concomp[s]] == TRUE );
    8464 assert( nodedata != NULL );
    8465
    8466 if ( checklb )
    8467 nodedata->lbboundcomp = TRUE;
    8468 else
    8469 nodedata->ubboundcomp = TRUE;
    8470 }
    8471 SCIPdebugMsg(scip, "Found a connected component of size <%i> with unique bound variable.\n", nconcomp);
    8472 }
    8473 }
    8474 }
    8475
    8476 /* free buffer arrays */
    8477 SCIPfreeBufferArray(scip, &concomp);
    8478 SCIPfreeBufferArray(scip, &processed);
    8479
    8480 return SCIP_OKAY;
    8481}
    8482
    8483
    8484/** check all linear constraints for variable bound constraints of the form \f$c\cdot z \leq x \leq d\cdot z\f$, where @p x is some SOS1
    8485 * variable and @p z is some arbitrary variable (not necessarily binary)
    8486 */
    8487static
    8489 SCIP* scip, /**< SCIP pointer */
    8490 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */
    8491 SCIP_CONS** linconss, /**< linear constraints */
    8492 int nlinconss /**< number of linear constraints */
    8493 )
    8494{
    8495 int c;
    8496
    8497 /* loop through linear constraints */
    8498 for (c = 0; c < nlinconss; ++c)
    8499 {
    8500 SCIP_CONS* lincons;
    8501 int nvars;
    8502
    8503 lincons = linconss[c];
    8504
    8505 /* variable bound constraints only contain two variables */
    8506 nvars = SCIPgetNVarsLinear(scip, lincons);
    8507 if ( nvars == 2 )
    8508 {
    8509 SCIP_VAR** vars;
    8510 SCIP_Real* vals;
    8511 SCIP_VAR* var0;
    8512 SCIP_VAR* var1;
    8513 SCIP_Real lhs;
    8514 SCIP_Real rhs;
    8515
    8516 /* get constraint data */
    8517 vars = SCIPgetVarsLinear(scip, lincons);
    8518 vals = SCIPgetValsLinear(scip, lincons);
    8519 lhs = SCIPgetLhsLinear(scip, lincons);
    8520 rhs = SCIPgetRhsLinear(scip, lincons);
    8521
    8522 var0 = vars[0];
    8523 var1 = vars[1];
    8524 assert( var0 != NULL && var1 != NULL );
    8525
    8526 /* at least one variable should be an SOS1 variable */
    8527 if ( varIsSOS1(conshdlrdata, var0) || varIsSOS1(conshdlrdata, var1) )
    8528 {
    8529 SCIP_Real val0;
    8530 SCIP_Real val1;
    8531
    8532 /* check whether right hand side or left hand side of constraint is zero */
    8533 if ( SCIPisFeasZero(scip, lhs) )
    8534 {
    8535 val0 = -vals[0];
    8536 val1 = -vals[1];
    8537
    8538 /* check whether the two variables are in a variable bound relation */
    8539 SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var0, var1, val0, val1) );
    8540 SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var1, var0, val1, val0) );
    8541 }
    8542 else if( SCIPisFeasZero(scip, rhs) )
    8543 {
    8544 val0 = vals[0];
    8545 val1 = vals[1];
    8546
    8547 /* check whether the two variables are in a variable bound relation */
    8548 SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var0, var1, val0, val1) );
    8549 SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var1, var0, val1, val0) );
    8550 }
    8551 }
    8552 }
    8553 }
    8554
    8555 return SCIP_OKAY;
    8556}
    8557
    8558
    8559/** switch to SOS1 branching and separating bound iniqualities from SOS1 constraints if the SOS1 constraints do not overlap */
    8560static
    8562 SCIP* scip, /**< SCIP pointer */
    8563 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */
    8564 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    8565 SCIP_CONS** conss, /**< SOS1 constraints */
    8566 int nconss /**< number of SOS1 constraints */
    8567 )
    8568{
    8569 SCIP_Bool nonoverlap = TRUE;
    8570 int c;
    8571
    8572 /* loop through all SOS1 constraints */
    8573 if ( conshdlrdata->nsos1vars > 0 )
    8574 {
    8575 for (c = 0; c < nconss && nonoverlap; ++c)
    8576 {
    8577 SCIP_CONSDATA* consdata;
    8578 SCIP_VAR** vars;
    8579 int notfixed = 0;
    8580 int nvars;
    8581 int i;
    8582
    8583 assert( conss[c] != NULL );
    8584
    8585 /* get constraint data field of the constraint */
    8586 consdata = SCIPconsGetData(conss[c]);
    8587 assert( consdata != NULL );
    8588
    8589 /* get variables and number of variables of constraint */
    8590 nvars = consdata->nvars;
    8591 vars = consdata->vars;
    8592
    8593 /* get number of variables of SOS1 constraint that are not fixed to zero */
    8594 for (i = 0; i < nvars; ++i)
    8595 {
    8596 if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(vars[i])) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(vars[i])) )
    8597 ++notfixed;
    8598 }
    8599
    8600 /* check variables of SOS1 constraint */
    8601 for (i = 0; i < nvars; ++i)
    8602 {
    8603 int node;
    8604
    8605 assert( vars[i] != NULL );
    8606
    8607 node = varGetNodeSOS1(conshdlrdata, vars[i]);
    8608 assert( node >= 0 || ( SCIPisFeasZero(scip, SCIPvarGetLbLocal(vars[i])) && SCIPisFeasZero(scip, SCIPvarGetUbLocal(vars[i]))) );
    8609 assert( node < conshdlrdata->nsos1vars );
    8610 assert( node < 0 || SCIPdigraphGetNSuccessors(conflictgraph, node) >= notfixed-1 );
    8611 if ( node >= 0 && SCIPdigraphGetNSuccessors(conflictgraph, node) > notfixed-1 )
    8612 {
    8613 nonoverlap = FALSE;
    8614 break;
    8615 }
    8616 }
    8617 }
    8618 }
    8619
    8620 /* if the SOS1 constraints do not overlap */
    8621 if ( nonoverlap )
    8622 {
    8623 if ( conshdlrdata->autosos1branch )
    8624 {
    8625 conshdlrdata->switchsos1branch = TRUE;
    8626 SCIPdebugMsg(scip, "Switched to SOS1 branching, since the SOS1 constraints do not overlap\n");
    8627 }
    8628
    8629 if ( conshdlrdata->autocutsfromsos1 )
    8630 {
    8631 conshdlrdata->switchcutsfromsos1 = TRUE;
    8632 SCIPdebugMsg(scip, "Switched to separating bound cuts from SOS1 constraints (and not from the conflict graph), since the SOS1 constraints do not overlap\n");
    8633 }
    8634 }
    8635
    8636 return SCIP_OKAY;
    8637}
    8638
    8639
    8640/** sets node data of conflict graph nodes */
    8641static
    8643 SCIP* scip, /**< SCIP pointer */
    8644 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */
    8645 int nsos1vars /**< number of SOS1 variables */
    8646 )
    8647{
    8648 SCIP_CONSHDLR* linconshdlr;
    8649 SCIP_CONS** linconss;
    8650 int nlinconss;
    8651
    8652 /* if no SOS1 variables exist -> exit */
    8653 if ( nsos1vars == 0 )
    8654 return SCIP_OKAY;
    8655
    8656 /* get constraint handler data of linear constraints */
    8657 linconshdlr = SCIPfindConshdlr(scip, "linear");
    8658 if ( linconshdlr == NULL )
    8659 return SCIP_OKAY;
    8660
    8661 /* get linear constraints and number of linear constraints */
    8662 nlinconss = SCIPconshdlrGetNConss(linconshdlr);
    8663 linconss = SCIPconshdlrGetConss(linconshdlr);
    8664
    8665 /* check linear constraints for variable bound constraints */
    8666 SCIP_CALL( checkLinearConssVarboundSOS1(scip, conshdlrdata, linconss, nlinconss) );
    8667
    8668 /* for each connected component of the conflict graph check whether all the variables correspond to a unique variable
    8669 * upper bound variable */
    8670 SCIP_CALL( checkConComponentsVarbound(scip, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, TRUE) );
    8671 SCIP_CALL( checkConComponentsVarbound(scip, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, FALSE) );
    8672
    8673 return SCIP_OKAY;
    8674}
    8675
    8676
    8677/** initialize conflictgraph and create hashmap for SOS1 variables */
    8678static
    8680 SCIP* scip, /**< SCIP pointer */
    8681 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    8682 SCIP_CONS** conss, /**< SOS1 constraints */
    8683 int nconss /**< number of SOS1 constraints */
    8684 )
    8685{
    8686 SCIP_Bool* nodecreated; /* nodecreated[i] = TRUE if a node in the conflict graph is already created for index i
    8687 * (with i index of the original variables) */
    8688 int* nodeorig; /* nodeorig[i] = node of original variable x_i in the conflict graph */
    8689 int ntotalvars;
    8690 int cntsos;
    8691 int i;
    8692 int j;
    8693 int c;
    8694
    8695 assert( conshdlrdata != NULL );
    8696 assert( nconss == 0 || conss != NULL );
    8697
    8698 /* get the number of original problem variables */
    8699 ntotalvars = SCIPgetNTotalVars(scip);
    8700
    8701 /* initialize vector 'nodecreated' */
    8702 SCIP_CALL( SCIPallocBufferArray(scip, &nodeorig, ntotalvars) );
    8703 SCIP_CALL( SCIPallocBufferArray(scip, &nodecreated, ntotalvars) );
    8704 for (i = 0; i < ntotalvars; ++i)
    8705 nodecreated[i] = FALSE;
    8706
    8707 /* compute number of SOS1 variables */
    8708 cntsos = 0;
    8709 for (c = 0; c < nconss; ++c)
    8710 {
    8711 SCIP_CONSDATA* consdata;
    8712 SCIP_VAR** vars;
    8713 int nvars;
    8714
    8715 assert( conss[c] != NULL );
    8716
    8717 /* get constraint data field of the constraint */
    8718 consdata = SCIPconsGetData(conss[c]);
    8719 assert( consdata != NULL );
    8720
    8721 /* get variables and number of variables of constraint */
    8722 nvars = consdata->nvars;
    8723 vars = consdata->vars;
    8724
    8725 /* update number of SOS1 variables */
    8726 for (i = 0; i < nvars; ++i)
    8727 {
    8728 SCIP_VAR* var;
    8729
    8730 var = vars[i];
    8731
    8732 /* if the variable is not fixed to zero */
    8734 {
    8735 int ind;
    8736
    8737 ind = SCIPvarGetIndex(var);
    8738 assert( ind >= 0 && ind < ntotalvars );
    8739 if ( ! nodecreated[ind] )
    8740 {
    8741 nodecreated[ind] = TRUE; /* mark node as counted */
    8742 nodeorig[ind] = cntsos;
    8743 ++cntsos;
    8744 }
    8745 }
    8746 }
    8747 }
    8748 if ( cntsos <= 0 )
    8749 {
    8750 /* free buffer arrays */
    8751 SCIPfreeBufferArray(scip, &nodecreated);
    8752 SCIPfreeBufferArray(scip, &nodeorig);
    8753 conshdlrdata->nsos1vars = 0;
    8754 return SCIP_OKAY;
    8755 }
    8756
    8757 /* reinitialize vector 'nodecreated' */
    8758 for (i = 0; i < ntotalvars; ++i)
    8759 nodecreated[i] = FALSE;
    8760
    8761 /* create conflict graph */
    8762 SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->conflictgraph, cntsos) );
    8763
    8764 /* set up hash map */
    8765 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), cntsos) );
    8766
    8767 /* for every SOS1 constraint */
    8768 cntsos = 0;
    8769 for (c = 0; c < nconss; ++c)
    8770 {
    8771 SCIP_CONSDATA* consdata;
    8772 SCIP_VAR** vars;
    8773 int nvars;
    8774
    8775 assert( conss[c] != NULL );
    8776
    8777 /* get constraint data field of the constraint */
    8778 consdata = SCIPconsGetData(conss[c]);
    8779 assert( consdata != NULL );
    8780
    8781 /* get variables and number of variables of constraint */
    8782 nvars = consdata->nvars;
    8783 vars = consdata->vars;
    8784
    8785 /* add edges to the conflict graph and create node data for each of its nodes */
    8786 for (i = 0; i < nvars; ++i)
    8787 {
    8788 SCIP_VAR* var;
    8789
    8790 var = vars[i];
    8791
    8792 /* if the variable is not fixed to zero */
    8794 {
    8795 int indi;
    8796
    8797 indi = SCIPvarGetIndex(var);
    8798
    8799 if ( ! nodecreated[indi] )
    8800 {
    8802
    8803 /* insert node number to hash map */
    8804 assert( ! SCIPhashmapExists(conshdlrdata->varhash, var) );
    8805 SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->varhash, var, cntsos) );
    8806 assert( cntsos == SCIPhashmapGetImageInt(conshdlrdata->varhash, var) );
    8807 assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
    8808
    8809 /* create node data */
    8811 nodedata->var = var;
    8812 nodedata->lbboundvar = NULL;
    8813 nodedata->ubboundvar = NULL;
    8814 nodedata->lbboundcoef = 0.0;
    8815 nodedata->ubboundcoef = 0.0;
    8816 nodedata->lbboundcomp = FALSE;
    8817 nodedata->ubboundcomp = FALSE;
    8818
    8819 /* set node data */
    8820 SCIPdigraphSetNodeData(conshdlrdata->conflictgraph, (void*)nodedata, cntsos);
    8821
    8822 /* mark node and var data of node as created and update SOS1 counter */
    8823 nodecreated[indi] = TRUE;
    8824 ++cntsos;
    8825 }
    8826
    8827 /* add edges to the conflict graph */
    8828 for (j = i+1; j < nvars; ++j)
    8829 {
    8830 var = vars[j];
    8831
    8832 /* if the variable is not fixed to zero */
    8834 {
    8835 int indj;
    8836
    8837 indj = SCIPvarGetIndex(var);
    8838
    8839 /* in case indi = indj the variable will be deleted in the presolving step */
    8840 if ( indi != indj )
    8841 {
    8842 /* arcs have to be added 'safe' */
    8843 SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->conflictgraph, nodeorig[indi], nodeorig[indj], NULL) );
    8844 SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->conflictgraph, nodeorig[indj], nodeorig[indi], NULL) );
    8845 }
    8846 }
    8847 }
    8848 }
    8849 }
    8850 }
    8851
    8852 /* set number of problem variables that are contained in at least one SOS1 constraint */
    8853 conshdlrdata->nsos1vars = cntsos;
    8854
    8855 /* free buffer arrays */
    8856 SCIPfreeBufferArray(scip, &nodecreated);
    8857 SCIPfreeBufferArray(scip, &nodeorig);
    8858
    8859 /* sort successors in ascending order */
    8860 for (j = 0; j < conshdlrdata->nsos1vars; ++j)
    8861 {
    8862 int nsucc;
    8863
    8864 nsucc = SCIPdigraphGetNSuccessors(conshdlrdata->conflictgraph, j);
    8865 SCIPsortInt(SCIPdigraphGetSuccessors(conshdlrdata->conflictgraph, j), nsucc);
    8866 }
    8867
    8868 return SCIP_OKAY;
    8869}
    8870
    8871
    8872/** free conflict graph, nodedata and hashmap */
    8873static
    8875 SCIP* scip, /**< SCIP pointer */
    8876 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
    8877 )
    8878{
    8879 int j;
    8880
    8881 if ( conshdlrdata->conflictgraph == NULL )
    8882 {
    8883 assert( conshdlrdata->nsos1vars == 0 );
    8884 return SCIP_OKAY;
    8885 }
    8886
    8887 /* for every SOS1 variable */
    8888 assert( conshdlrdata->nsos1vars > 0 );
    8889 for (j = 0; j < conshdlrdata->nsos1vars; ++j)
    8890 {
    8892
    8893 /* get node data */
    8894 assert( conshdlrdata->conflictgraph != NULL );
    8895 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, j);
    8896 assert( nodedata != NULL );
    8897
    8898 /* free node data */
    8900 SCIPdigraphSetNodeData(conshdlrdata->conflictgraph, NULL, j);
    8901 }
    8902
    8903 /* free conflict graph and hash map */
    8904 assert( conshdlrdata->varhash != NULL );
    8905 SCIPhashmapFree(&conshdlrdata->varhash);
    8906 SCIPdigraphFree(&conshdlrdata->conflictgraph);
    8907 conshdlrdata->nsos1vars = 0;
    8908
    8909 assert( conshdlrdata->varhash == NULL );
    8910 assert( conshdlrdata->conflictgraph == NULL );
    8911
    8912 return SCIP_OKAY;
    8913}
    8914
    8915
    8916/* ---------------------------- constraint handler callback methods ----------------------*/
    8917
    8918/** copy method for constraint handler plugins (called when SCIP copies plugins) */
    8919static
    8920SCIP_DECL_CONSHDLRCOPY(conshdlrCopySOS1)
    8921{ /*lint --e{715}*/
    8922 assert( scip != NULL );
    8923 assert( conshdlr != NULL );
    8924 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    8925
    8926 /* call inclusion method of constraint handler */
    8928
    8929 *valid = TRUE;
    8930
    8931 return SCIP_OKAY;
    8932}
    8933
    8934
    8935/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
    8936static
    8938{
    8939 SCIP_CONSHDLRDATA* conshdlrdata;
    8940
    8941 assert( scip != NULL );
    8942 assert( conshdlr != NULL );
    8943 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    8944
    8945 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8946 assert(conshdlrdata != NULL);
    8947
    8948 /* free stack of variables fixed to nonzero (usually already freed in consExitsolSOS1 unless instance was solved during presolving) */
    8949 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars); /*lint !e737*/
    8950
    8951 SCIPfreeBlockMemory(scip, &conshdlrdata);
    8952
    8953 return SCIP_OKAY;
    8954}
    8955
    8956
    8957/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
    8958static
    8960{ /*lint --e{715}*/
    8961 SCIP_CONSHDLRDATA* conshdlrdata;
    8962
    8963 assert( scip != NULL );
    8964 assert( conshdlr != NULL );
    8965 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    8966
    8967 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8968 assert( conshdlrdata != NULL );
    8969
    8970 conshdlrdata->nsos1vars = 0;
    8971 conshdlrdata->varhash = NULL;
    8972
    8973 if ( nconss > 0 )
    8974 {
    8975 /* initialize conflict graph and hashmap for SOS1 variables */
    8976 SCIP_CALL( initConflictgraph(scip, conshdlrdata, conss, nconss) );
    8977
    8978 /* add data to conflict graph nodes */
    8979 SCIP_CALL( computeNodeDataSOS1(scip, conshdlrdata, conshdlrdata->nsos1vars) );
    8980
    8981 if ( ( conshdlrdata->autosos1branch || conshdlrdata->autocutsfromsos1 )
    8982 && ( ! conshdlrdata->switchsos1branch || ! conshdlrdata->switchcutsfromsos1 )
    8983 )
    8984 {
    8985 /* switch to nonoverlapping methods if the SOS1 constraints do not overlap */
    8986 SCIP_CALL( checkSwitchNonoverlappingSOS1Methods(scip, conshdlrdata, conshdlrdata->conflictgraph, conss, nconss) );
    8987 }
    8988
    8989 /* initialize tclique graph */
    8990 SCIP_CALL( initTCliquegraph(scip, conshdlr, conshdlrdata, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars) );
    8991
    8992 /* create local conflict graph if needed */
    8993 if ( conshdlrdata->addcomps )
    8994 {
    8995 SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->localconflicts, conshdlrdata->nsos1vars) );
    8996 }
    8997
    8998 /* initialize stack of variables fixed to nonzero (memory may be already allocated in consTransSOS1()) */
    8999 if ( conshdlrdata->fixnonzerovars == NULL )
    9000 {
    9001 conshdlrdata->maxnfixnonzerovars = conshdlrdata->nsos1vars;
    9002 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars) );
    9003 }
    9004 }
    9005
    9006 return SCIP_OKAY;
    9007}
    9008
    9009
    9010/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
    9011static
    9013{ /*lint --e{715}*/
    9014 SCIP_CONSHDLRDATA* conshdlrdata;
    9015 int c;
    9016
    9017 assert( scip != NULL );
    9018 assert( conshdlr != NULL );
    9019 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9020 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9021 assert( conshdlrdata != NULL );
    9022
    9023 /* check each constraint */
    9024 for (c = 0; c < nconss; ++c)
    9025 {
    9026 SCIP_CONSDATA* consdata;
    9027
    9028 assert( conss != NULL );
    9029 assert( conss[c] != NULL );
    9030 consdata = SCIPconsGetData(conss[c]);
    9031 assert( consdata != NULL );
    9032
    9033 SCIPdebugMsg(scip, "Exiting SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
    9034
    9035 /* free rows */
    9036 if ( consdata->rowub != NULL )
    9037 {
    9038 SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowub) );
    9039 }
    9040
    9041 if ( consdata->rowlb != NULL )
    9042 {
    9043 SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowlb) );
    9044 }
    9045 }
    9046
    9047 /* free implication graph */
    9048 if ( conshdlrdata->implgraph != NULL )
    9049 {
    9050 SCIP_CALL( freeImplGraphSOS1(scip, conshdlrdata) );
    9051 }
    9052 assert( conshdlrdata->implgraph == NULL );
    9053
    9054 /* free tclique graph and tclique data */
    9055 if ( conshdlrdata->tcliquegraph != NULL )
    9056 {
    9057 assert( conshdlrdata->tcliquedata != NULL );
    9058 SCIPfreeBlockMemory(scip, &conshdlrdata->tcliquedata);
    9059 tcliqueFree(&conshdlrdata->tcliquegraph);
    9060 }
    9061 assert(conshdlrdata->tcliquegraph == NULL);
    9062 assert(conshdlrdata->tcliquedata == NULL);
    9063
    9064 /* free stack of variables fixed to nonzero */
    9065 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars); /*lint !e737*/
    9066 conshdlrdata->nfixnonzerovars = 0;
    9067 conshdlrdata->maxnfixnonzerovars = 0;
    9068
    9069 /* free graph for storing local conflicts */
    9070 if ( conshdlrdata->localconflicts != NULL )
    9071 SCIPdigraphFree(&conshdlrdata->localconflicts);
    9072 assert( conshdlrdata->localconflicts == NULL );
    9073
    9074 /* free conflict graph */
    9075 SCIP_CALL( freeConflictgraph(scip, conshdlrdata) );
    9076 assert( conshdlrdata->conflictgraph == NULL );
    9077
    9078 return SCIP_OKAY;
    9079}
    9080
    9081
    9082/** frees specific constraint data */
    9083static
    9085{
    9086 assert( scip != NULL );
    9087 assert( conshdlr != NULL );
    9088 assert( cons != NULL );
    9089 assert( consdata != NULL );
    9090 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9091
    9092 SCIPdebugMsg(scip, "Deleting SOS1 constraint <%s>.\n", SCIPconsGetName(cons) );
    9093
    9094 /* drop events on transformed variables */
    9095 if ( SCIPconsIsTransformed(cons) )
    9096 {
    9097 SCIP_CONSHDLRDATA* conshdlrdata;
    9098 int j;
    9099
    9100 /* get constraint handler data */
    9101 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9102 assert( conshdlrdata != NULL );
    9103 assert( conshdlrdata->eventhdlr != NULL );
    9104
    9105 for (j = 0; j < (*consdata)->nvars; ++j)
    9106 {
    9107 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->vars[j], EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr,
    9108 (SCIP_EVENTDATA*)cons, -1) ); /*lint !e737 !e740*/
    9109 }
    9110 }
    9111
    9112 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->maxvars);
    9113 if ( (*consdata)->weights != NULL )
    9114 {
    9115 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->maxvars);
    9116 }
    9117
    9118 /* free rows */
    9119 if ( (*consdata)->rowub != NULL )
    9120 {
    9121 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowub) );
    9122 }
    9123 if ( (*consdata)->rowlb != NULL )
    9124 {
    9125 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowlb) );
    9126 }
    9127 assert( (*consdata)->rowub == NULL );
    9128 assert( (*consdata)->rowlb == NULL );
    9129
    9130 SCIPfreeBlockMemory(scip, consdata);
    9131
    9132 return SCIP_OKAY;
    9133}
    9134
    9135
    9136/** transforms constraint data into data belonging to the transformed problem */
    9137static
    9139{
    9140 SCIP_CONSDATA* consdata;
    9141 SCIP_CONSHDLRDATA* conshdlrdata;
    9142 SCIP_CONSDATA* sourcedata;
    9143 char s[SCIP_MAXSTRLEN];
    9144 int j;
    9145
    9146 assert( scip != NULL );
    9147 assert( conshdlr != NULL );
    9148 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9149 assert( sourcecons != NULL );
    9150 assert( targetcons != NULL );
    9151
    9152 /* get constraint handler data */
    9153 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9154 assert( conshdlrdata != NULL );
    9155 assert( conshdlrdata->eventhdlr != NULL );
    9156
    9157 SCIPdebugMsg(scip, "Transforming SOS1 constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
    9158
    9159 /* get data of original constraint */
    9160 sourcedata = SCIPconsGetData(sourcecons);
    9161 assert( sourcedata != NULL );
    9162 assert( sourcedata->nvars > 0 );
    9163 assert( sourcedata->nvars <= sourcedata->maxvars );
    9164
    9165 /* initialize stack of variables fixed to nonzero */
    9166 if ( conshdlrdata->fixnonzerovars == NULL )
    9167 {
    9168 conshdlrdata->maxnfixnonzerovars = SCIPgetNTotalVars(scip);
    9169 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars) );
    9170 }
    9171
    9172 /* create constraint data */
    9173 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
    9174
    9175 consdata->nvars = sourcedata->nvars;
    9176 consdata->maxvars = sourcedata->nvars;
    9177 consdata->rowub = NULL;
    9178 consdata->rowlb = NULL;
    9179 consdata->nfixednonzeros = 0;
    9180 consdata->local = sourcedata->local;
    9181
    9182 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, consdata->nvars) );
    9183
    9184 /* if weights were used */
    9185 if ( sourcedata->weights != NULL )
    9186 {
    9187 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, sourcedata->weights, consdata->nvars) );
    9188 }
    9189 else
    9190 consdata->weights = NULL;
    9191
    9192 for (j = 0; j < sourcedata->nvars; ++j)
    9193 {
    9194 assert( sourcedata->vars[j] != 0 );
    9195 SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->vars[j], &(consdata->vars[j])) );
    9196
    9197 /* if variable is fixed to be nonzero */
    9198 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->vars[j])) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(consdata->vars[j])) )
    9199 ++(consdata->nfixednonzeros);
    9200 }
    9201
    9202 /* create transformed constraint with the same flags */
    9203 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
    9204 SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
    9205 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
    9206 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
    9207 SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
    9208 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
    9209 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
    9210
    9211 /* catch bound change events on variable */
    9212 for (j = 0; j < consdata->nvars; ++j)
    9213 {
    9214 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[j], EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr,
    9215 (SCIP_EVENTDATA*)*targetcons, NULL) ); /*lint !e740*/
    9216 }
    9217
    9218#ifdef SCIP_DEBUG
    9219 if ( consdata->nfixednonzeros > 0 )
    9220 {
    9221 SCIPdebugMsg(scip, "constraint <%s> has %d variables fixed to be nonzero.\n", SCIPconsGetName(*targetcons),
    9222 consdata->nfixednonzeros );
    9223 }
    9224#endif
    9225
    9226 return SCIP_OKAY;
    9227}
    9228
    9229
    9230/** presolving method of constraint handler */
    9231static
    9233{ /*lint --e{715}*/
    9234 SCIP_CONSHDLRDATA* conshdlrdata;
    9235 SCIPdebug( int oldnfixedvars = *nfixedvars; )
    9236 SCIPdebug( int oldnchgbds = *nchgbds; )
    9237 SCIPdebug( int oldndelconss = *ndelconss; )
    9238 SCIPdebug( int oldnupgdconss = *nupgdconss; )
    9239 int nremovedvars;
    9240
    9241 assert( scip != NULL );
    9242 assert( conshdlr != NULL );
    9243 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9244 assert( result != NULL );
    9245
    9246 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9247 assert( conshdlrdata != NULL );
    9248
    9249 SCIPdebugMsg(scip, "Presolving SOS1 constraints.\n");
    9250
    9251 *result = SCIP_DIDNOTRUN;
    9252
    9253 nremovedvars = 0;
    9254
    9255 /* only run if success if possible */
    9256 if( nconss > 0 && ( nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 ) )
    9257 {
    9258 SCIP_Bool** adjacencymatrix = NULL;
    9259 SCIP_DIGRAPH* conflictgraph;
    9260 SCIP_EVENTHDLR* eventhdlr;
    9261 int nsos1vars;
    9262 int i;
    9263 int j;
    9264
    9265 *result = SCIP_DIDNOTFIND;
    9266
    9267 /* get constraint handler data */
    9268 assert( SCIPconshdlrGetData(conshdlr) != NULL );
    9269 eventhdlr = SCIPconshdlrGetData(conshdlr)->eventhdlr;
    9270 assert( eventhdlr != NULL );
    9271
    9272 /* initialize conflict graph */
    9273 SCIP_CALL( initConflictgraph(scip, conshdlrdata, conss, nconss) );
    9274
    9275 /* get conflict graph and number of SOS1 variables */
    9276 conflictgraph = conshdlrdata->conflictgraph;
    9277 nsos1vars = conshdlrdata->nsos1vars;
    9278 if ( nsos1vars < 2 )
    9279 {
    9280 SCIP_CALL( freeConflictgraph(scip, conshdlrdata) );
    9281 return SCIP_OKAY;
    9282 }
    9283
    9284 /* we do not create the adjacency matrix of the conflict graph if the number of SOS1 variables is larger than a predefined value */
    9285 if ( conshdlrdata->maxsosadjacency == -1 || nsos1vars <= conshdlrdata->maxsosadjacency )
    9286 {
    9287 /* allocate buffer arrays for adjacency matrix */
    9288 SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix, nsos1vars) );
    9289 for (i = 0; i < nsos1vars; ++i)
    9290 {
    9291 SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix[i], i+1) );/*lint !e866*/
    9292 }
    9293
    9294 /* create adjacency matrix */
    9295 for (i = 0; i < nsos1vars; ++i)
    9296 {
    9297 for (j = 0; j < i+1; ++j)
    9298 adjacencymatrix[i][j] = 0;
    9299 }
    9300 for (i = 0; i < nsos1vars; ++i)
    9301 {
    9302 int* succ;
    9303 int nsucc;
    9304
    9305 succ = SCIPdigraphGetSuccessors(conflictgraph, i);
    9306 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
    9307
    9308 for (j = 0; j < nsucc; ++j)
    9309 {
    9310 if ( i > succ[j] )
    9311 adjacencymatrix[i][succ[j]] = 1;
    9312 }
    9313 }
    9314 }
    9315 else
    9316 {
    9317 SCIPdebugMsg(scip, "Adjacency matrix was not created since number of SOS1 variables (%d) is larger than %d.\n", nsos1vars, conshdlrdata->maxsosadjacency);
    9318 }
    9319
    9320 /* perform one presolving round for SOS1 constraints */
    9321 SCIP_CALL( presolRoundConssSOS1(scip, eventhdlr, conshdlrdata, conflictgraph, adjacencymatrix, conss, nconss, nsos1vars, naddconss, ndelconss, nupgdconss, nfixedvars, &nremovedvars, result) );
    9322
    9323 if ( adjacencymatrix != NULL )
    9324 {
    9325 /* perform one presolving round for SOS1 variables */
    9326 if ( conshdlrdata->maxtightenbds != 0 && *result != SCIP_CUTOFF )
    9327 {
    9328 SCIP_CALL( presolRoundVarsSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, nsos1vars, nfixedvars, nchgbds, naddconss, result) );
    9329 }
    9330
    9331 /* free adjacency matrix */
    9332 for (j = nsos1vars-1; j >= 0; --j)
    9333 SCIPfreeBufferArrayNull(scip, &adjacencymatrix[j]);
    9334 SCIPfreeBufferArrayNull(scip, &adjacencymatrix);
    9335 }
    9336
    9337 /* free memory allocated in function initConflictgraph() */
    9338 SCIP_CALL( freeConflictgraph(scip, conshdlrdata) );
    9339 }
    9340 (*nchgcoefs) += nremovedvars;
    9341
    9342 SCIPdebug( SCIPdebugMsg(scip, "presolving fixed %d variables, changed %d bounds, removed %d variables, deleted %d constraints, and upgraded %d constraints.\n",
    9343 *nfixedvars - oldnfixedvars, *nchgbds - oldnchgbds, nremovedvars, *ndelconss - oldndelconss, *nupgdconss - oldnupgdconss); )
    9344
    9345 return SCIP_OKAY;
    9346}
    9347
    9348
    9349/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
    9350static
    9352{
    9353 SCIP_CONSHDLRDATA* conshdlrdata;
    9354
    9355 assert( scip != NULL );
    9356 assert( conshdlr != NULL );
    9357 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9358
    9359 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9360 assert( conshdlrdata != NULL );
    9361
    9362 *infeasible = FALSE;
    9363
    9364 /* checking for initial rows for SOS1 constraints */
    9365 if( conshdlrdata->boundcutsfromsos1 || conshdlrdata->switchcutsfromsos1 )
    9366 {
    9367 SCIP_CALL( initsepaBoundInequalityFromSOS1Cons(scip, conshdlr, conshdlrdata, conss, nconss, NULL, FALSE, -1, NULL, infeasible) );
    9368 }
    9369
    9370 return SCIP_OKAY;
    9371}
    9372
    9373
    9374/** separation method of constraint handler for LP solutions */
    9375static
    9377{ /*lint --e{715}*/
    9378 assert( scip != NULL );
    9379 assert( conshdlr != NULL );
    9380 assert( conss != NULL );
    9381 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9382 assert( result != NULL );
    9383
    9384 SCIP_CALL( separateSOS1(scip, conshdlr, NULL, nconss, conss, result) );
    9385
    9386 return SCIP_OKAY;
    9387}
    9388
    9389
    9390/** separation method of constraint handler for arbitrary primal solutions */
    9391static
    9393{ /*lint --e{715}*/
    9394 assert( scip != NULL );
    9395 assert( conshdlr != NULL );
    9396 assert( conss != NULL );
    9397 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9398 assert( result != NULL );
    9399
    9400 SCIP_CALL( separateSOS1(scip, conshdlr, sol, nconss, conss, result) );
    9401
    9402 return SCIP_OKAY;
    9403}
    9404
    9405
    9406/** constraint enforcing method of constraint handler for LP solutions */
    9407static
    9409{ /*lint --e{715}*/
    9410 assert( scip != NULL );
    9411 assert( conshdlr != NULL );
    9412 assert( conss != NULL );
    9413 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9414 assert( result != NULL );
    9415
    9416 SCIP_CALL( enforceSOS1(scip, conshdlr, nconss, conss, NULL, result) );
    9417
    9418 return SCIP_OKAY;
    9419}
    9420
    9421
    9422/** constraint enforcing method of constraint handler for relaxation solutions */
    9423static
    9424SCIP_DECL_CONSENFORELAX(consEnforelaxSOS1)
    9425{ /*lint --e{715}*/
    9426 assert( scip != NULL );
    9427 assert( conshdlr != NULL );
    9428 assert( conss != NULL );
    9429 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9430 assert( result != NULL );
    9431
    9432 SCIP_CALL( enforceSOS1(scip, conshdlr, nconss, conss, sol, result) );
    9433
    9434 return SCIP_OKAY;
    9435}
    9436
    9437
    9438/** constraint enforcing method of constraint handler for pseudo solutions */
    9439static
    9441{ /*lint --e{715}*/
    9442 assert( scip != NULL );
    9443 assert( conshdlr != NULL );
    9444 assert( conss != NULL );
    9445 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9446 assert( result != NULL );
    9447
    9448 SCIP_CALL( enforceSOS1(scip, conshdlr, nconss, conss, NULL, result) );
    9449
    9450 return SCIP_OKAY;
    9451}
    9452
    9453
    9454/** feasibility check method of constraint handler for integral solutions
    9455 *
    9456 * We simply check whether at most one variable is nonzero in the given solution.
    9457 */
    9458static
    9460{ /*lint --e{715}*/
    9461 int c;
    9462
    9463 assert( scip != NULL );
    9464 assert( conshdlr != NULL );
    9465 assert( conss != NULL );
    9466 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9467 assert( result != NULL );
    9468
    9469 *result = SCIP_FEASIBLE;
    9470
    9471 /* check each constraint */
    9472 for (c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c)
    9473 {
    9474 SCIP_CONSDATA* consdata;
    9475 int j;
    9476 int cnt;
    9477
    9478 cnt = 0;
    9479 assert( conss[c] != NULL );
    9480 consdata = SCIPconsGetData(conss[c]);
    9481 assert( consdata != NULL );
    9482 SCIPdebugMsg(scip, "Checking SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]));
    9483
    9484 /* check all variables */
    9485 for (j = 0; j < consdata->nvars; ++j)
    9486 {
    9487 /* if variable is nonzero */
    9488 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) )
    9489 {
    9490 ++cnt;
    9491
    9492 /* if more than one variable is nonzero */
    9493 if ( cnt > 1 )
    9494 {
    9495 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
    9496 *result = SCIP_INFEASIBLE;
    9497
    9498 /* update constraint violation in solution */
    9499 if ( sol != NULL )
    9500 SCIPupdateSolConsViolation(scip, sol, 1.0, 1.0);
    9501
    9502 if ( printreason )
    9503 {
    9504 int l;
    9505
    9506 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
    9507 SCIPinfoMessage(scip, NULL, ";\nviolation: ");
    9508
    9509 for (l = 0; l < consdata->nvars; ++l)
    9510 {
    9511 /* if variable is nonzero */
    9512 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[l])) )
    9513 {
    9514 SCIPinfoMessage(scip, NULL, "<%s> = %.15g ",
    9515 SCIPvarGetName(consdata->vars[l]), SCIPgetSolVal(scip, sol, consdata->vars[l]));
    9516 }
    9517 }
    9518 SCIPinfoMessage(scip, NULL, "\n");
    9519 }
    9520 }
    9521 }
    9522 }
    9523 }
    9524
    9525 return SCIP_OKAY;
    9526}
    9527
    9528
    9529/** domain propagation method of constraint handler */
    9530static
    9532{ /*lint --e{715}*/
    9533 SCIP_CONSHDLRDATA* conshdlrdata;
    9534 SCIP_DIGRAPH* conflictgraph;
    9535 SCIP_DIGRAPH* implgraph;
    9536 int ngen = 0;
    9537
    9538 assert( scip != NULL );
    9539 assert( conshdlr != NULL );
    9540 assert( conss != NULL );
    9541 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9542 assert( result != NULL );
    9543 assert( SCIPisTransformed(scip) );
    9544
    9545 /* return if number of SOS1 constraints is zero */
    9546 if ( nconss < 1 )
    9547 {
    9548 *result = SCIP_DIDNOTRUN;
    9549 return SCIP_OKAY;
    9550 }
    9551 *result = SCIP_DIDNOTFIND;
    9552
    9553 /* get constraint handler data */
    9554 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9555 assert( conshdlrdata != NULL );
    9556
    9557 /* get conflict graph */
    9558 conflictgraph = conshdlrdata->conflictgraph;
    9559
    9560 /* get/initialize implication graph */
    9561 implgraph = conshdlrdata->implgraph;
    9562 if ( implgraph == NULL && conshdlrdata->implprop && conflictgraph != NULL )
    9563 {
    9564 if ( SCIPgetDepth(scip) == 0 )
    9565 {
    9566 SCIP_Bool success;
    9567 SCIP_Bool cutoff;
    9568 int nchbds;
    9569
    9570 SCIP_CALL( initImplGraphSOS1(scip, conshdlrdata, conflictgraph, conshdlrdata->nsos1vars, conshdlrdata->maxtightenbds, &nchbds, &cutoff, &success) );
    9571 if ( ! success )
    9572 conshdlrdata->implprop = FALSE;
    9573
    9574 if ( cutoff )
    9575 {
    9576 *result = SCIP_CUTOFF;
    9577 return SCIP_OKAY;
    9578 }
    9579 else if ( nchbds > 0 )
    9580 *result = SCIP_REDUCEDDOM;
    9581 implgraph = conshdlrdata->implgraph;
    9582 }
    9583 else
    9584 conshdlrdata->implprop = FALSE;
    9585 }
    9586
    9587 /* if conflict graph propagation shall be used */
    9588 if ( conshdlrdata->conflictprop && conflictgraph != NULL )
    9589 {
    9590 SCIP_VAR** fixnonzerovars;
    9591 int nfixnonzerovars;
    9592 int j;
    9593
    9594 assert( nconss > 0 );
    9595
    9596 /* stack of variables fixed to nonzero */
    9597 nfixnonzerovars = conshdlrdata->nfixnonzerovars;
    9598 fixnonzerovars = conshdlrdata->fixnonzerovars;
    9599 assert( fixnonzerovars != NULL );
    9600
    9601 /* check each variable from stack */
    9602 for (j = 0; j < nfixnonzerovars; ++j)
    9603 {
    9604 SCIP_VAR* var;
    9605
    9606 var = fixnonzerovars[j];
    9607 if ( var != NULL )
    9608 {
    9609 int node;
    9610 node = varGetNodeSOS1(conshdlrdata, var);
    9611
    9612 /* if variable is involved in an SOS1 constraint */
    9613 if ( node >= 0 )
    9614 {
    9615 assert( varGetNodeSOS1(conshdlrdata, var) < conshdlrdata->nsos1vars );
    9616 SCIPdebugMsg(scip, "Propagating SOS1 variable <%s>.\n", SCIPvarGetName(var) );
    9617
    9618 /* if zero is outside the domain of variable */
    9620 {
    9621 SCIP_Bool cutoff;
    9622
    9623 SCIP_CALL( propVariableNonzero(scip, conflictgraph, implgraph, conss[0], node, conshdlrdata->implprop, &cutoff, &ngen) );
    9624 if ( cutoff )
    9625 {
    9626 *result = SCIP_CUTOFF;
    9627 return SCIP_OKAY;
    9628 }
    9629 }
    9630 }
    9631 }
    9632 }
    9633 }
    9634 conshdlrdata->nfixnonzerovars = 0;
    9635
    9636 /* if SOS1 constraint propagation shall be used */
    9637 if ( conshdlrdata->sosconsprop || conflictgraph == NULL )
    9638 {
    9639 int c;
    9640
    9641 /* check each constraint */
    9642 for (c = 0; c < nconss; ++c)
    9643 {
    9644 SCIP_CONS* cons;
    9645 SCIP_CONSDATA* consdata;
    9646 SCIP_Bool cutoff;
    9647
    9648 assert( conss[c] != NULL );
    9649 cons = conss[c];
    9650 consdata = SCIPconsGetData(cons);
    9651 assert( consdata != NULL );
    9652 SCIPdebugMsg(scip, "Propagating SOS1 constraint <%s>.\n", SCIPconsGetName(cons) );
    9653
    9654 SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) );
    9655 if ( cutoff )
    9656 {
    9657 *result = SCIP_CUTOFF;
    9658 return SCIP_OKAY;
    9659 }
    9660 }
    9661 }
    9662
    9663 SCIPdebugMsg(scip, "Propagated %d domains.\n", ngen);
    9664 if ( ngen > 0 )
    9665 *result = SCIP_REDUCEDDOM;
    9666
    9667 return SCIP_OKAY;
    9668}
    9669
    9670
    9671/** propagation conflict resolving method of constraint handler
    9672 *
    9673 * We check which bound changes were the reason for infeasibility. We
    9674 * use that @a inferinfo stores the index of the variable that has
    9675 * bounds that fix it to be nonzero (these bounds are the reason). */
    9676static
    9678{ /*lint --e{715}*/
    9679 SCIP_VAR* var;
    9680
    9681 assert( scip != NULL );
    9682 assert( cons != NULL );
    9683 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9684 assert( infervar != NULL );
    9685 assert( bdchgidx != NULL );
    9686 assert( result != NULL );
    9687
    9688 *result = SCIP_DIDNOTFIND;
    9689 SCIPdebugMsg(scip, "Propagation resolution method of SOS1 constraint <%s>.\n", SCIPconsGetName(cons));
    9690
    9691 /* check whether conflict was detected in variable propagation or constraint propagation */
    9692 if ( inferinfo < 0 )
    9693 {
    9694 SCIP_CONSHDLRDATA* conshdlrdata;
    9695
    9696 assert( conshdlr != NULL );
    9697
    9698 /* get constraint handler data */
    9699 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9700 assert( conshdlrdata != NULL );
    9701 assert( conshdlrdata->conflictgraph != NULL );
    9702 assert( inferinfo >= -conshdlrdata->maxnfixnonzerovars );
    9703 assert( inferinfo >= -conshdlrdata->nsos1vars );
    9704 assert( inferinfo <= -1 );
    9705
    9706 var = SCIPnodeGetVarSOS1(conshdlrdata->conflictgraph, -inferinfo - 1); /*lint !e2704*/
    9707 }
    9708 else
    9709 {
    9710 SCIP_CONSDATA* consdata;
    9711
    9712 /* get constraint data */
    9713 consdata = SCIPconsGetData(cons);
    9714 assert( consdata != NULL );
    9715 assert( inferinfo < consdata->nvars );
    9716
    9717 var = consdata->vars[inferinfo];
    9718 }
    9719 assert( var != NULL );
    9720 assert( var != infervar );
    9721
    9722 /* check if lower bound of var was the reason */
    9723 if ( SCIPisFeasPositive(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) )
    9724 {
    9725 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
    9726 *result = SCIP_SUCCESS;
    9727 }
    9728
    9729 /* check if upper bound of var was the reason */
    9730 if ( SCIPisFeasNegative(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) )
    9731 {
    9732 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
    9733 *result = SCIP_SUCCESS;
    9734 }
    9735
    9736 return SCIP_OKAY;
    9737}
    9738
    9739
    9740/** variable rounding lock method of constraint handler
    9741 *
    9742 * Let lb and ub be the lower and upper bounds of a
    9743 * variable. Preprocessing usually makes sure that lb <= 0 <= ub.
    9744 *
    9745 * - If lb < 0 then rounding down may violate the constraint.
    9746 * - If ub > 0 then rounding up may violated the constraint.
    9747 * - If lb > 0 or ub < 0 then the constraint is infeasible and we do
    9748 * not have to deal with it here.
    9749 * - If lb == 0 then rounding down does not violate the constraint.
    9750 * - If ub == 0 then rounding up does not violate the constraint.
    9751 */
    9752static
    9754{
    9755 SCIP_CONSDATA* consdata;
    9756 SCIP_VAR** vars;
    9757 int nvars;
    9758 int j;
    9759
    9760 assert( scip != NULL );
    9761 assert( conshdlr != NULL );
    9762 assert( cons != NULL );
    9763 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9764 assert(locktype == SCIP_LOCKTYPE_MODEL);
    9765
    9766 consdata = SCIPconsGetData(cons);
    9767 assert( consdata != NULL );
    9768
    9769 SCIPdebugMsg(scip, "Locking constraint <%s>.\n", SCIPconsGetName(cons));
    9770
    9771 vars = consdata->vars;
    9772 nvars = consdata->nvars;
    9773 assert( vars != NULL );
    9774
    9775 for (j = 0; j < nvars; ++j)
    9776 {
    9777 SCIP_VAR* var;
    9778 var = vars[j];
    9779
    9780 /* if lower bound is negative, rounding down may violate constraint */
    9782 {
    9783 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlockspos, nlocksneg) );
    9784 }
    9785
    9786 /* additionally: if upper bound is positive, rounding up may violate constraint */
    9788 {
    9789 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlocksneg, nlockspos) );
    9790 }
    9791 }
    9792
    9793 return SCIP_OKAY;
    9794}
    9795
    9796
    9797/** constraint display method of constraint handler */
    9798static
    9800{ /*lint --e{715}*/
    9801 SCIP_CONSDATA* consdata;
    9802 int j;
    9803
    9804 assert( scip != NULL );
    9805 assert( conshdlr != NULL );
    9806 assert( cons != NULL );
    9807 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9808
    9809 consdata = SCIPconsGetData(cons);
    9810 assert( consdata != NULL );
    9811
    9812 for (j = 0; j < consdata->nvars; ++j)
    9813 {
    9814 if ( j > 0 )
    9815 SCIPinfoMessage(scip, file, ", ");
    9816 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[j], FALSE) );
    9817 if ( consdata->weights == NULL )
    9818 SCIPinfoMessage(scip, file, " (%d)", j+1);
    9819 else
    9820 SCIPinfoMessage(scip, file, " (%3.2f)", consdata->weights[j]);
    9821 }
    9822
    9823 return SCIP_OKAY;
    9824}
    9825
    9826
    9827/** constraint copying method of constraint handler */
    9828static
    9830{ /*lint --e{715}*/
    9831 SCIP_CONSDATA* sourceconsdata;
    9832 SCIP_VAR** sourcevars;
    9833 SCIP_VAR** targetvars;
    9834 SCIP_Real* targetweights = NULL;
    9835 const char* consname;
    9836 int nvars;
    9837 int v;
    9838
    9839 assert( scip != NULL );
    9840 assert( sourcescip != NULL );
    9841 assert( sourcecons != NULL );
    9842 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 );
    9843 assert( valid != NULL );
    9844
    9845 *valid = TRUE;
    9846
    9847 if ( name != NULL )
    9848 consname = name;
    9849 else
    9850 consname = SCIPconsGetName(sourcecons);
    9851
    9852 SCIPdebugMsg(scip, "Copying SOS1 constraint <%s> ...\n", consname);
    9853
    9854 sourceconsdata = SCIPconsGetData(sourcecons);
    9855 assert( sourceconsdata != NULL );
    9856
    9857 /* get variables and weights of the source constraint */
    9858 nvars = sourceconsdata->nvars;
    9859 assert( nvars >= 0 );
    9860
    9861 /* duplicate weights array */
    9862 if ( sourceconsdata->weights != NULL )
    9863 {
    9864 SCIP_CALL( SCIPduplicateBufferArray(sourcescip, &targetweights, sourceconsdata->weights, nvars) );
    9865 }
    9866
    9867 /* get copied variables in target SCIP */
    9868 sourcevars = sourceconsdata->vars;
    9869 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetvars, nvars) );
    9870 for (v = 0; v < nvars && *valid; ++v)
    9871 {
    9872 assert( sourcevars != NULL );
    9873 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &(targetvars[v]), varmap, consmap, global, valid) );
    9874 }
    9875
    9876 /* only create the target constraint, if all variables were be copied */
    9877 if ( *valid )
    9878 {
    9879 SCIP_CALL( SCIPcreateConsSOS1(scip, cons, consname, nvars, targetvars, targetweights,
    9880 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
    9881 }
    9882
    9883 /* free buffer array */
    9884 SCIPfreeBufferArray(sourcescip, &targetvars);
    9885 SCIPfreeBufferArrayNull(sourcescip, &targetweights);
    9886
    9887 return SCIP_OKAY;
    9888}
    9889
    9890
    9891/** constraint parsing method of constraint handler */
    9892static
    9894{ /*lint --e{715}*/
    9895 SCIP_VAR* var;
    9896 SCIP_Real weight;
    9897 const char* s;
    9898 char* t;
    9899
    9900 assert(scip != NULL);
    9901 assert(conshdlr != NULL);
    9902 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9903 assert(cons != NULL);
    9904 assert(success != NULL);
    9905
    9906 *success = TRUE;
    9907 s = str;
    9908
    9909 /* create empty SOS1 constraint */
    9910 SCIP_CALL( SCIPcreateConsSOS1(scip, cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
    9911
    9912 /* loop through string */
    9913 while( *s != '\0' )
    9914 {
    9915 /* parse variable name */
    9916 SCIP_CALL( SCIPparseVarName(scip, s, &var, &t) );
    9917
    9918 if( var == NULL )
    9919 break;
    9920
    9921 /* skip until beginning of weight */
    9922 t = strchr(t, '(');
    9923
    9924 if( t == NULL )
    9925 {
    9926 SCIPerrorMessage("Syntax error: expected opening '(' at input: %s\n", s);
    9927 *success = FALSE;
    9928 break;
    9929 }
    9930
    9931 s = t;
    9932
    9933 /* skip '(' */
    9934 ++s;
    9935
    9936 /* find weight */
    9937 weight = strtod(s, &t);
    9938
    9939 if( t == NULL )
    9940 {
    9941 SCIPerrorMessage("Syntax error during parsing of the weight: %s\n", s);
    9942 *success = FALSE;
    9943 break;
    9944 }
    9945
    9946 s = t;
    9947
    9948 /* skip until ending of weight */
    9949 t = strchr(t, ')');
    9950
    9951 if( t == NULL )
    9952 {
    9953 SCIPerrorMessage("Syntax error: expected closing ')' at input %s\n", s);
    9954 *success = FALSE;
    9955 break;
    9956 }
    9957
    9958 s = t;
    9959
    9960 /* skip ')' */
    9961 ++s;
    9962
    9963 /* skip white space */
    9964 SCIP_CALL( SCIPskipSpace((char**)&s) );
    9965
    9966 /* skip ',' */
    9967 if( *s == ',' )
    9968 ++s;
    9969
    9970 /* add variable */
    9971 SCIP_CALL( SCIPaddVarSOS1(scip, *cons, var, weight) );
    9972 }
    9973
    9974 if( !*success )
    9975 SCIP_CALL( SCIPreleaseCons(scip, cons) );
    9976
    9977 return SCIP_OKAY;
    9978}
    9979
    9980
    9981/** constraint method of constraint handler which returns the variables (if possible) */
    9982static
    9984{ /*lint --e{715}*/
    9985 SCIP_CONSDATA* consdata;
    9986
    9987 consdata = SCIPconsGetData(cons);
    9988 assert(consdata != NULL);
    9989
    9990 if( varssize < consdata->nvars )
    9991 (*success) = FALSE;
    9992 else
    9993 {
    9994 assert(vars != NULL);
    9995
    9996 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
    9997 (*success) = TRUE;
    9998 }
    9999
    10000 return SCIP_OKAY;
    10001}
    10002
    10003
    10004/** constraint method of constraint handler which returns the number of variables (if possible) */
    10005static
    10006SCIP_DECL_CONSGETNVARS(consGetNVarsSOS1)
    10007{ /*lint --e{715}*/
    10008 SCIP_CONSDATA* consdata;
    10009
    10010 consdata = SCIPconsGetData(cons);
    10011 assert(consdata != NULL);
    10012
    10013 (*nvars) = consdata->nvars;
    10014 (*success) = TRUE;
    10015
    10016 return SCIP_OKAY;
    10017}
    10018
    10019
    10020/* ---------------- Callback methods of event handler ---------------- */
    10021
    10022/** exec the event handler
    10023 *
    10024 * We update the number of variables fixed to be nonzero
    10025 */
    10026static
    10028{
    10029 SCIP_CONSHDLRDATA* conshdlrdata;
    10030 SCIP_EVENTTYPE eventtype;
    10031 SCIP_CONSHDLR* conshdlr;
    10032 SCIP_CONSDATA* consdata;
    10033 SCIP_CONS* cons;
    10034 SCIP_VAR* var;
    10035 SCIP_Real oldbound;
    10036 SCIP_Real newbound;
    10037
    10038 assert( eventhdlr != NULL );
    10039 assert( eventdata != NULL );
    10040 assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0 );
    10041 assert( event != NULL );
    10042
    10043 cons = (SCIP_CONS*)eventdata;
    10044 assert( cons != NULL );
    10045 consdata = SCIPconsGetData(cons);
    10046 assert( 0 <= consdata->nfixednonzeros && consdata->nfixednonzeros <= consdata->nvars );
    10047
    10048 oldbound = SCIPeventGetOldbound(event);
    10049 newbound = SCIPeventGetNewbound(event);
    10050
    10051 eventtype = SCIPeventGetType(event);
    10052 switch ( eventtype )
    10053 {
    10055 /* if variable is now fixed to be nonzero */
    10056 if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
    10057 {
    10058 conshdlr = SCIPconsGetHdlr(cons);
    10059 assert( conshdlr != NULL );
    10060 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    10061 assert( conshdlrdata != NULL );
    10062
    10063 /* store variable fixed to be nonzero on stack */
    10064 assert( 0 <= conshdlrdata->nfixnonzerovars && conshdlrdata->nfixnonzerovars <= SCIPgetNTotalVars(scip) );
    10065 if ( conshdlrdata->nfixnonzerovars < conshdlrdata->maxnfixnonzerovars )
    10066 {
    10067 assert( conshdlrdata->fixnonzerovars != NULL );
    10068 assert( SCIPeventGetVar(event) != NULL );
    10069 conshdlrdata->fixnonzerovars[conshdlrdata->nfixnonzerovars++] = SCIPeventGetVar(event);
    10070 }
    10071
    10072 ++(consdata->nfixednonzeros);
    10073 }
    10074 break;
    10075
    10077 /* if variable is now fixed to be nonzero */
    10078 if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
    10079 {
    10080 conshdlr = SCIPconsGetHdlr(cons);
    10081 assert( conshdlr != NULL );
    10082 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    10083 assert( conshdlrdata != NULL );
    10084
    10085 /* store variable fixed to be nonzero on stack */
    10086 assert( 0 <= conshdlrdata->nfixnonzerovars && conshdlrdata->nfixnonzerovars <= SCIPgetNTotalVars(scip) );
    10087 if ( conshdlrdata->nfixnonzerovars < conshdlrdata->maxnfixnonzerovars )
    10088 {
    10089 assert( conshdlrdata->fixnonzerovars != NULL );
    10090 assert( SCIPeventGetVar(event) != NULL );
    10091 conshdlrdata->fixnonzerovars[conshdlrdata->nfixnonzerovars++] = SCIPeventGetVar(event);
    10092 }
    10093
    10094 ++(consdata->nfixednonzeros);
    10095 }
    10096 break;
    10097
    10099 /* if variable is not fixed to be nonzero anymore */
    10100 if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
    10101 --(consdata->nfixednonzeros);
    10102 break;
    10103
    10105 /* if variable is not fixed to be nonzero anymore */
    10106 if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
    10107 --(consdata->nfixednonzeros);
    10108 break;
    10109
    10111 var = SCIPeventGetVar(event);
    10112 assert(var != NULL);
    10113
    10114 /* global lower bound is not negative anymore -> remove down lock */
    10115 if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
    10116 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
    10117 /* global lower bound turned negative -> add down lock */
    10118 else if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
    10119 SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, FALSE) );
    10120 break;
    10121
    10123 var = SCIPeventGetVar(event);
    10124 assert(var != NULL);
    10125
    10126 /* global upper bound is not positive anymore -> remove up lock */
    10127 if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
    10128 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
    10129 /* global upper bound turned positive -> add up lock */
    10130 else if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
    10131 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
    10132 break;
    10133
    10134 default:
    10135 SCIPerrorMessage("invalid event type.\n");
    10136 return SCIP_INVALIDDATA;
    10137 }
    10138 assert( 0 <= consdata->nfixednonzeros && consdata->nfixednonzeros <= consdata->nvars );
    10139
    10140 SCIPdebugMsg(scip, "changed bound of variable <%s> from %f to %f (nfixednonzeros: %d).\n", SCIPvarGetName(SCIPeventGetVar(event)),
    10141 oldbound, newbound, consdata->nfixednonzeros);
    10142
    10143 return SCIP_OKAY;
    10144}
    10145
    10146
    10147/** constraint handler method to determine a diving variable by assigning a variable and two values for diving */
    10148static
    10149SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsSOS1)
    10150{
    10151 SCIP_CONSHDLRDATA* conshdlrdata;
    10152
    10153 assert( scip != NULL );
    10154 assert( conshdlr != NULL );
    10155 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    10156 assert( diveset != NULL );
    10157 assert( success != NULL );
    10158 assert( infeasible != NULL );
    10159
    10160 *infeasible = FALSE;
    10161 *success = FALSE;
    10162
    10163 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
    10164 {
    10165 SCIPerrorMessage("not an SOS1 constraint handler.\n");
    10166 return SCIP_INVALIDDATA;
    10167 }
    10168 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    10169 assert( conshdlrdata != NULL );
    10170
    10171 /* if the SOS1 constraints do not overlap, we apply a faster method getDiveBdChgsSOS1constraints() that does not make use of the conflict graph;
    10172 * for overlapping SOS1 constraints we apply the method getDiveBdChgsSOS1conflictgraph(), which then may produce better results (e.g. due to more
    10173 * diving candidates) */
    10174 if ( conshdlrdata->switchsos1branch )
    10175 {
    10176 SCIP_CALL( getDiveBdChgsSOS1constraints(scip, conshdlr, diveset, sol, success) );
    10177 }
    10178 else
    10179 {
    10180 SCIP_CALL( getDiveBdChgsSOS1conflictgraph(scip, conshdlr, diveset, sol, success) );
    10181 }
    10182
    10183 return SCIP_OKAY;
    10184}
    10185
    10186
    10187/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
    10188static
    10189SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphSOS1)
    10190{ /*lint --e{715}*/
    10191 SCIP_CONSDATA* consdata;
    10192 SCIP_VAR** consvars;
    10193 SCIP_VAR** locvars;
    10194 SCIP_Real* locvals;
    10195 SCIP_Real constant;
    10196 int consnodeidx;
    10197 int nodeidx;
    10198 int nconsvars;
    10199 int nlocvars;
    10200 int nvars;
    10201 int i;
    10202
    10203 consdata = SCIPconsGetData(cons);
    10204 assert(consdata != NULL);
    10205
    10206 /* get active variables of the constraint */
    10207 nvars = SCIPgetNVars(scip);
    10208 nconsvars = consdata->nvars;
    10209 consvars = SCIPgetVarsSOS1(scip, cons);
    10210 assert(consvars != NULL);
    10211
    10212 SCIP_CALL( SCIPallocBufferArray(scip, &locvars, nvars) );
    10213 SCIP_CALL( SCIPallocBufferArray(scip, &locvals, nvars) );
    10214
    10215 /* add node initializing constraint (with artificial rhs) */
    10216 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, 0.0, 0.0, &consnodeidx) );
    10217
    10218 /* for all (aggregations of) variables, add a node to graph and connect it with the root */
    10219 for( i = 0; i < nconsvars; ++i )
    10220 {
    10221 locvars[0] = consvars[i];
    10222 locvals[0] = 1.0;
    10223 constant = 0.0;
    10224 nlocvars = 1;
    10225
    10226 /* ignore weights of SOS1 constraint (variables are sorted according to these weights) */
    10228 &nlocvars, &constant, SCIPisTransformed(scip)) );
    10229
    10230 if( nlocvars == 1 && SCIPisZero(scip, constant) && SCIPisEQ(scip, locvals[0], 1.0) )
    10231 {
    10232 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, locvars[0]);
    10233 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, nodeidx, FALSE, 0.0) );
    10234 }
    10235 else
    10236 {
    10237 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &nodeidx) ); /*lint !e641*/
    10238 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, nodeidx, FALSE, 0.0) );
    10239 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, locvars, locvals, nlocvars, constant) );
    10240 }
    10241 }
    10242
    10243 SCIPfreeBufferArray(scip, &locvals);
    10244 SCIPfreeBufferArray(scip, &locvars);
    10245
    10246 assert(success != NULL);
    10247 *success = TRUE;
    10248
    10249 return SCIP_OKAY;
    10250}
    10251
    10252
    10253/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
    10254static
    10255SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphSOS1)
    10256{ /*lint --e{715}*/
    10257 SCIP_CONSDATA* consdata;
    10258 SCIP_VAR** consvars;
    10259 SCIP_VAR** locvars;
    10260 SCIP_Real* locvals;
    10261 SCIP_Real constant;
    10262 int consnodeidx;
    10263 int nodeidx;
    10264 int nconsvars;
    10265 int nlocvars;
    10266 int nvars;
    10267 int i;
    10268
    10269 consdata = SCIPconsGetData(cons);
    10270 assert(consdata != NULL);
    10271
    10272 /* get active variables of the constraint */
    10273 nvars = SCIPgetNVars(scip);
    10274 nconsvars = consdata->nvars;
    10275 consvars = SCIPgetVarsSOS1(scip, cons);
    10276 assert(consvars != NULL);
    10277
    10278 SCIP_CALL( SCIPallocBufferArray(scip, &locvars, nvars) );
    10279 SCIP_CALL( SCIPallocBufferArray(scip, &locvals, nvars) );
    10280
    10281 /* add node initializing constraint (with artificial rhs) */
    10282 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, 0.0, 0.0, &consnodeidx) );
    10283
    10284 /* for all (aggregation of) variables, add a node to graph and connect it with the root */
    10285 for( i = 0; i < nconsvars; ++i )
    10286 {
    10287 locvars[0] = consvars[i];
    10288 locvals[0] = 1.0;
    10289 constant = 0.0;
    10290 nlocvars = 1;
    10291
    10292 /* ignore weights of SOS1 constraint (variables are sorted according to these weights) */
    10293
    10294 /* use SYM_SYMTYPE_PERM here to NOT center variable domains at 0, as the latter might not preserve
    10295 * SOS1 constraints */
    10297 &nlocvars, &constant, SCIPisTransformed(scip)) );
    10298
    10299 if( nlocvars == 1 && SCIPisZero(scip, constant) && SCIPisEQ(scip, locvals[0], 1.0) )
    10300 {
    10301 SCIP_Bool allownegation = FALSE;
    10302
    10303 /* a negation is allowed if it is centered around 0 */
    10304 if ( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(locvars[0])) == SCIPisInfinity(scip, SCIPvarGetUbGlobal(locvars[0]))
    10305 && (SCIPisInfinity(scip, SCIPvarGetUbGlobal(locvars[0]))
    10306 || SCIPisZero(scip, (SCIPvarGetLbGlobal(locvars[0]) + SCIPvarGetUbGlobal(locvars[0]))/2)) )
    10307 allownegation = TRUE;
    10308
    10309 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, locvars[0]);
    10310 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, nodeidx, TRUE, 1.0) );
    10311
    10312 nodeidx = SCIPgetSymgraphNegatedVarnodeidx(scip, graph, locvars[0]);
    10313 if( allownegation )
    10314 {
    10315 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, nodeidx, TRUE, 1.0) );
    10316 }
    10317 else
    10318 {
    10319 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, nodeidx, TRUE, -1.0) );
    10320 }
    10321 }
    10322 else
    10323 {
    10324 int sumnodeidx;
    10325 int j;
    10326
    10327 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &sumnodeidx) ); /*lint !e641*/
    10328 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, sumnodeidx, FALSE, 0.0) );
    10329
    10330 /* add nodes and edges for variables in aggregation, do not add edges to negated variables
    10331 * since this might not necessarily be a symmetry of the SOS1 constraint; therefore,
    10332 * do not use SCIPaddSymgraphVarAggregation() */
    10333 for( j = 0; j < nlocvars; ++j )
    10334 {
    10335 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, locvars[j]);
    10336 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, locvals[j]) );
    10337 }
    10338
    10339 /* possibly add node for constant */
    10340 if( ! SCIPisZero(scip, constant) )
    10341 {
    10342 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, constant, &nodeidx) );
    10343 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, FALSE, 0.0) );
    10344 }
    10345 }
    10346 }
    10347
    10348 SCIPfreeBufferArray(scip, &locvals);
    10349 SCIPfreeBufferArray(scip, &locvars);
    10350
    10351 assert(success != NULL);
    10352 *success = TRUE;
    10353
    10354 return SCIP_OKAY;
    10355}
    10356
    10357
    10358/* ---------------- Constraint specific interface methods ---------------- */
    10359
    10360/** creates the handler for SOS1 constraints and includes it in SCIP */
    10362 SCIP* scip /**< SCIP data structure */
    10363 )
    10364{
    10365 SCIP_CONSHDLRDATA* conshdlrdata;
    10366 SCIP_CONSHDLR* conshdlr;
    10367
    10368 /* create constraint handler data */
    10369 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
    10370 conshdlrdata->branchsos = TRUE;
    10371 conshdlrdata->switchsos1branch = FALSE;
    10372 conshdlrdata->switchcutsfromsos1 = FALSE;
    10373 conshdlrdata->eventhdlr = NULL;
    10374 conshdlrdata->fixnonzerovars = NULL;
    10375 conshdlrdata->maxnfixnonzerovars = 0;
    10376 conshdlrdata->nfixnonzerovars = 0;
    10377 conshdlrdata->conflictgraph = NULL;
    10378 conshdlrdata->localconflicts = NULL;
    10379 conshdlrdata->isconflocal = FALSE;
    10380 conshdlrdata->implgraph = NULL;
    10381 conshdlrdata->nimplnodes = 0;
    10382 conshdlrdata->nboundcuts = 0;
    10383 conshdlrdata->tcliquegraph = NULL;
    10384 conshdlrdata->tcliquedata = NULL;
    10385 conshdlrdata->cntextsos1 = -1;
    10386 conshdlrdata->varhash = NULL;
    10387 conshdlrdata->nsos1vars = 0;
    10388
    10389 /* create event handler for bound change events */
    10390 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecSOS1, NULL) );
    10391 if ( conshdlrdata->eventhdlr == NULL )
    10392 {
    10393 SCIPerrorMessage("event handler for SOS1 constraints not found.\n");
    10394 return SCIP_PLUGINNOTFOUND;
    10395 }
    10396
    10397 /* include constraint handler */
    10400 consEnfolpSOS1, consEnfopsSOS1, consCheckSOS1, consLockSOS1, conshdlrdata) );
    10401 assert(conshdlr != NULL);
    10402
    10403 /* set non-fundamental callbacks via specific setter functions */
    10404 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySOS1, consCopySOS1) );
    10405 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSOS1) );
    10406 SCIP_CALL( SCIPsetConshdlrGetDiveBdChgs(scip, conshdlr, consGetDiveBdChgsSOS1) );
    10407 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolSOS1) );
    10408 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSOS1) );
    10409 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSOS1) );
    10410 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSOS1) );
    10411 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSOS1) );
    10412 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSOS1) );
    10413 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSOS1) );
    10415 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSOS1) );
    10417 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSOS1) );
    10418 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSOS1, consSepasolSOS1, CONSHDLR_SEPAFREQ, CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
    10419 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSOS1) );
    10420 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSOS1) );
    10421 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphSOS1) );
    10422 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphSOS1) );
    10423
    10424 /* add SOS1 constraint handler parameters */
    10425
    10426 /* adjacency matrix parameters */
    10427 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxsosadjacency",
    10428 "do not create an adjacency matrix if number of SOS1 variables is larger than predefined value (-1: no limit)",
    10429 &conshdlrdata->maxsosadjacency, TRUE, DEFAULT_MAXSOSADJACENCY, -1, INT_MAX, NULL, NULL) );
    10430
    10431 /* presolving parameters */
    10432 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxextensions",
    10433 "maximal number of extensions that will be computed for each SOS1 constraint (-1: no limit)",
    10434 &conshdlrdata->maxextensions, TRUE, DEFAULT_MAXEXTENSIONS, -1, INT_MAX, NULL, NULL) );
    10435
    10436 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxtightenbds",
    10437 "maximal number of bound tightening rounds per presolving round (-1: no limit)",
    10438 &conshdlrdata->maxtightenbds, TRUE, DEFAULT_MAXTIGHTENBDS, -1, INT_MAX, NULL, NULL) );
    10439
    10440 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/perfimplanalysis",
    10441 "if TRUE then perform implication graph analysis (might add additional SOS1 constraints)",
    10442 &conshdlrdata->perfimplanalysis, TRUE, DEFAULT_PERFIMPLANALYSIS, NULL, NULL) );
    10443
    10444 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/depthimplanalysis",
    10445 "number of recursive calls of implication graph analysis (-1: no limit)",
    10446 &conshdlrdata->depthimplanalysis, TRUE, DEFAULT_DEPTHIMPLANALYSIS, -1, INT_MAX, NULL, NULL) );
    10447
    10448 /* propagation parameters */
    10449 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/conflictprop",
    10450 "whether to use conflict graph propagation",
    10451 &conshdlrdata->conflictprop, TRUE, DEFAULT_CONFLICTPROP, NULL, NULL) );
    10452
    10453 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/implprop",
    10454 "whether to use implication graph propagation",
    10455 &conshdlrdata->implprop, TRUE, DEFAULT_IMPLPROP, NULL, NULL) );
    10456
    10457 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/sosconsprop",
    10458 "whether to use SOS1 constraint propagation",
    10459 &conshdlrdata->sosconsprop, TRUE, DEFAULT_SOSCONSPROP, NULL, NULL) );
    10460
    10461 /* branching parameters */
    10462 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchingrule",
    10463 "which branching rule should be applied ? ('n': neighborhood, 'b': bipartite, 's': SOS1/clique) (note: in some cases an automatic switching to SOS1 branching is possible)",
    10464 &conshdlrdata->branchingrule, TRUE, DEFAULT_BRANCHINGRULE, DEFAULT_BRANCHSTRATEGIES, NULL, NULL) );
    10465
    10466 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/autosos1branch",
    10467 "if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap",
    10468 &conshdlrdata->autosos1branch, TRUE, DEFAULT_AUTOSOS1BRANCH, NULL, NULL) );
    10469
    10470 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/fixnonzero",
    10471 "if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the feasibility tolerance",
    10472 &conshdlrdata->fixnonzero, TRUE, DEFAULT_FIXNONZERO, NULL, NULL) );
    10473
    10474 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/addcomps",
    10475 "if TRUE then add complementarity constraints to the branching nodes (can be used in combination with neighborhood or bipartite branching)",
    10476 &conshdlrdata->addcomps, TRUE, DEFAULT_ADDCOMPS, NULL, NULL) );
    10477
    10478 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxaddcomps",
    10479 "maximal number of complementarity constraints added per branching node (-1: no limit)",
    10480 &conshdlrdata->maxaddcomps, TRUE, DEFAULT_MAXADDCOMPS, -1, INT_MAX, NULL, NULL) );
    10481
    10482 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/addcompsfeas",
    10483 "minimal feasibility value for complementarity constraints in order to be added to the branching node",
    10484 &conshdlrdata->addcompsfeas, TRUE, DEFAULT_ADDCOMPSFEAS, -SCIP_REAL_MAX, SCIP_REAL_MAX, NULL, NULL) );
    10485
    10486 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/addbdsfeas",
    10487 "minimal feasibility value for bound inequalities in order to be added to the branching node",
    10488 &conshdlrdata->addbdsfeas, TRUE, DEFAULT_ADDBDSFEAS, -SCIP_REAL_MAX, SCIP_REAL_MAX, NULL, NULL) );
    10489
    10490 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/addextendedbds",
    10491 "should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities",
    10492 &conshdlrdata->addextendedbds, TRUE, DEFAULT_ADDEXTENDEDBDS, NULL, NULL) );
    10493
    10494 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchsos",
    10495 "Use SOS1 branching in enforcing (otherwise leave decision to branching rules)? This value can only be set to false if all SOS1 variables are binary",
    10496 &conshdlrdata->branchsos, FALSE, TRUE, NULL, NULL) );
    10497
    10498 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchnonzeros",
    10499 "Branch on SOS constraint with most number of nonzeros?",
    10500 &conshdlrdata->branchnonzeros, FALSE, FALSE, NULL, NULL) );
    10501
    10502 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchweight",
    10503 "Branch on SOS cons. with highest nonzero-variable weight for branching (needs branchnonzeros = false)?",
    10504 &conshdlrdata->branchweight, FALSE, FALSE, NULL, NULL) );
    10505
    10506 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/addcompsdepth",
    10507 "only add complementarity constraints to branching nodes for predefined depth (-1: no limit)",
    10508 &conshdlrdata->addcompsdepth, TRUE, DEFAULT_ADDCOMPSDEPTH, -1, INT_MAX, NULL, NULL) );
    10509
    10510 /* selection rule parameters */
    10511 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/nstrongrounds",
    10512 "maximal number of strong branching rounds to perform for each node (-1: auto); only available for neighborhood and bipartite branching",
    10513 &conshdlrdata->nstrongrounds, TRUE, DEFAULT_NSTRONGROUNDS, -1, INT_MAX, NULL, NULL) );
    10514
    10515 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/nstrongiter",
    10516 "maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit)",
    10517 &conshdlrdata->nstrongiter, TRUE, DEFAULT_NSTRONGITER, -2, INT_MAX, NULL, NULL) );
    10518
    10519 /* separation parameters */
    10520 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfromsos1",
    10521 "if TRUE separate bound inequalities from initial SOS1 constraints",
    10522 &conshdlrdata->boundcutsfromsos1, TRUE, DEFAULT_BOUNDCUTSFROMSOS1, NULL, NULL) );
    10523
    10524 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfromgraph",
    10525 "if TRUE separate bound inequalities from the conflict graph",
    10526 &conshdlrdata->boundcutsfromgraph, TRUE, DEFAULT_BOUNDCUTSFROMGRAPH, NULL, NULL) );
    10527
    10528 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/autocutsfromsos1",
    10529 "if TRUE then automatically switch to separating initial SOS1 constraints if the SOS1 constraints do not overlap",
    10530 &conshdlrdata->autocutsfromsos1, TRUE, DEFAULT_AUTOCUTSFROMSOS1, NULL, NULL) );
    10531
    10532 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfreq",
    10533 "frequency for separating bound cuts; zero means to separate only in the root node",
    10534 &conshdlrdata->boundcutsfreq, TRUE, DEFAULT_BOUNDCUTSFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
    10535
    10536 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsdepth",
    10537 "node depth of separating bound cuts (-1: no limit)",
    10538 &conshdlrdata->boundcutsdepth, TRUE, DEFAULT_BOUNDCUTSDEPTH, -1, INT_MAX, NULL, NULL) );
    10539
    10540 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxboundcuts",
    10541 "maximal number of bound cuts separated per branching node",
    10542 &conshdlrdata->maxboundcuts, TRUE, DEFAULT_MAXBOUNDCUTS, 0, INT_MAX, NULL, NULL) );
    10543
    10544 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxboundcutsroot",
    10545 "maximal number of bound cuts separated per iteration in the root node",
    10546 &conshdlrdata->maxboundcutsroot, TRUE, DEFAULT_MAXBOUNDCUTSROOT, 0, INT_MAX, NULL, NULL) );
    10547
    10548 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strthenboundcuts",
    10549 "if TRUE then bound cuts are strengthened in case bound variables are available",
    10550 &conshdlrdata->strthenboundcuts, TRUE, DEFAULT_STRTHENBOUNDCUTS, NULL, NULL) );
    10551
    10552 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/implcutsfreq",
    10553 "frequency for separating implied bound cuts; zero means to separate only in the root node",
    10554 &conshdlrdata->implcutsfreq, TRUE, DEFAULT_IMPLCUTSFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
    10555
    10556 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/implcutsdepth",
    10557 "node depth of separating implied bound cuts (-1: no limit)",
    10558 &conshdlrdata->implcutsdepth, TRUE, DEFAULT_IMPLCUTSDEPTH, -1, INT_MAX, NULL, NULL) );
    10559
    10560 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maximplcuts",
    10561 "maximal number of implied bound cuts separated per branching node",
    10562 &conshdlrdata->maximplcuts, TRUE, DEFAULT_MAXIMPLCUTS, 0, INT_MAX, NULL, NULL) );
    10563
    10564 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maximplcutsroot",
    10565 "maximal number of implied bound cuts separated per iteration in the root node",
    10566 &conshdlrdata->maximplcutsroot, TRUE, DEFAULT_MAXIMPLCUTSROOT, 0, INT_MAX, NULL, NULL) );
    10567
    10568 return SCIP_OKAY;
    10569}
    10570
    10571
    10572/** creates and captures a SOS1 constraint
    10573 *
    10574 * We set the constraint to not be modifable. If the weights are non NULL, the variables are ordered according to these
    10575 * weights (in ascending order).
    10576 *
    10577 * @note The constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons().
    10578 */
    10580 SCIP* scip, /**< SCIP data structure */
    10581 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    10582 const char* name, /**< name of constraint */
    10583 int nvars, /**< number of variables in the constraint */
    10584 SCIP_VAR** vars, /**< array with variables of constraint entries */
    10585 SCIP_Real* weights, /**< weights determining the variable order, or NULL if natural order should be used */
    10586 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    10587 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    10588 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    10589 * Usually set to TRUE. */
    10590 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    10591 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    10592 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    10593 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    10594 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    10595 * Usually set to TRUE. */
    10596 SCIP_Bool local, /**< is constraint only valid locally?
    10597 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    10598 SCIP_Bool dynamic, /**< is constraint subject to aging?
    10599 * Usually set to FALSE. Set to TRUE for own cuts which
    10600 * are separated as constraints. */
    10601 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    10602 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    10603 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    10604 * if it may be moved to a more global node?
    10605 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    10606 )
    10607{
    10608 SCIP_CONSHDLR* conshdlr;
    10609 SCIP_CONSDATA* consdata;
    10610 SCIP_Bool modifiable;
    10611 SCIP_Bool transformed;
    10612 int v;
    10613
    10614 modifiable = FALSE;
    10615
    10616 /* find the SOS1 constraint handler */
    10617 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    10618 if ( conshdlr == NULL )
    10619 {
    10620 SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
    10621 return SCIP_PLUGINNOTFOUND;
    10622 }
    10623
    10624 /* are we in the transformed problem? */
    10625 transformed = SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED;
    10626
    10627#ifndef NDEBUG
    10628 /* Check that the weights are sensible (not nan or inf); although not strictly needed, such values are likely a mistake. */
    10629 if ( nvars > 0 && weights != NULL )
    10630 {
    10631 for (v = 0; v < nvars; ++v)
    10632 assert( SCIPisFinite(weights[v]) );
    10633 }
    10634#endif
    10635
    10636 /* create constraint data */
    10637 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
    10638 consdata->vars = NULL;
    10639 consdata->nvars = nvars;
    10640 consdata->maxvars = nvars;
    10641 consdata->rowub = NULL;
    10642 consdata->rowlb = NULL;
    10643 consdata->nfixednonzeros = transformed ? 0 : -1;
    10644 consdata->weights = NULL;
    10645 consdata->local = local;
    10646
    10647 if ( nvars > 0 )
    10648 {
    10649 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->vars, vars, nvars) );
    10650
    10651 /* check weights */
    10652 if ( weights != NULL )
    10653 {
    10654 /* store weights */
    10655 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, weights, nvars) );
    10656
    10657 /* sort variables - ascending order */
    10658 SCIPsortRealPtr(consdata->weights, (void**)consdata->vars, nvars);
    10659 }
    10660 }
    10661 else
    10662 {
    10663 assert( weights == NULL );
    10664 }
    10665
    10666 /* branching on multiaggregated variables does not seem to work well, so avoid it */
    10667 for (v = 0; v < nvars; ++v)
    10668 {
    10669 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->vars[v]) );
    10670 }
    10671
    10672 /* create constraint */
    10673 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    10674 local, modifiable, dynamic, removable, stickingatnode) );
    10675 assert( transformed == SCIPconsIsTransformed(*cons) );
    10676
    10677 /* replace original variables by transformed variables in transformed constraint, add locks, and catch events */
    10678 for (v = nvars - 1; v >= 0; --v)
    10679 {
    10680 SCIP_CONSHDLRDATA* conshdlrdata;
    10681
    10682 /* always use transformed variables in transformed constraints */
    10683 if ( transformed )
    10684 {
    10685 SCIP_CALL( SCIPgetTransformedVar(scip, consdata->vars[v], &(consdata->vars[v])) );
    10686 }
    10687 assert( consdata->vars[v] != NULL );
    10688 assert( transformed == SCIPvarIsTransformed(consdata->vars[v]) );
    10689
    10690 /* get constraint handler data */
    10691 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    10692 assert( conshdlrdata != NULL );
    10693
    10694 /* handle the new variable */
    10695 SCIP_CALL( handleNewVariableSOS1(scip, *cons, consdata, conshdlrdata, consdata->vars[v], transformed) );
    10696 }
    10697
    10698 return SCIP_OKAY;
    10699}
    10700
    10701
    10702/** creates and captures a SOS1 constraint with all constraint flags set to their default values.
    10703 *
    10704 * @warning Do NOT set the constraint to be modifiable manually, because this might lead
    10705 * to wrong results as the variable array will not be re-sorted
    10706 *
    10707 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    10708 */
    10710 SCIP* scip, /**< SCIP data structure */
    10711 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    10712 const char* name, /**< name of constraint */
    10713 int nvars, /**< number of variables in the constraint */
    10714 SCIP_VAR** vars, /**< array with variables of constraint entries */
    10715 SCIP_Real* weights /**< weights determining the variable order, or NULL if natural order should be used */
    10716 )
    10717{
    10718 SCIP_CALL( SCIPcreateConsSOS1( scip, cons, name, nvars, vars, weights, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
    10719
    10720 return SCIP_OKAY;
    10721}
    10722
    10723
    10724/** adds variable to SOS1 constraint, the position is determined by the given weight */
    10726 SCIP* scip, /**< SCIP data structure */
    10727 SCIP_CONS* cons, /**< constraint */
    10728 SCIP_VAR* var, /**< variable to add to the constraint */
    10729 SCIP_Real weight /**< weight determining position of variable */
    10730 )
    10731{
    10732 SCIP_CONSHDLRDATA* conshdlrdata;
    10733 SCIP_CONSHDLR* conshdlr;
    10734
    10735 assert( scip != NULL );
    10736 assert( var != NULL );
    10737 assert( cons != NULL );
    10738 /* Check weight is sensible (not nan or inf); although not strictly needed, such values are likely a mistake. */
    10739 assert( SCIPisFinite(weight) );
    10740
    10741 SCIPdebugMsg(scip, "adding variable <%s> to constraint <%s> with weight %g\n", SCIPvarGetName(var), SCIPconsGetName(cons), weight);
    10742
    10743 conshdlr = SCIPconsGetHdlr(cons);
    10744 assert( conshdlr != NULL );
    10745 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
    10746 {
    10747 SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
    10748 return SCIP_INVALIDDATA;
    10749 }
    10750
    10751 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    10752 assert( conshdlrdata != NULL );
    10753
    10754 SCIP_CALL( addVarSOS1(scip, cons, conshdlrdata, var, weight) );
    10755
    10756 return SCIP_OKAY;
    10757}
    10758
    10759
    10760/** appends variable to SOS1 constraint */
    10762 SCIP* scip, /**< SCIP data structure */
    10763 SCIP_CONS* cons, /**< constraint */
    10764 SCIP_VAR* var /**< variable to add to the constraint */
    10765 )
    10766{
    10767 SCIP_CONSHDLRDATA* conshdlrdata;
    10768 SCIP_CONSHDLR* conshdlr;
    10769
    10770 assert( scip != NULL );
    10771 assert( var != NULL );
    10772 assert( cons != NULL );
    10773
    10774 SCIPdebugMsg(scip, "appending variable <%s> to constraint <%s>\n", SCIPvarGetName(var), SCIPconsGetName(cons));
    10775
    10776 conshdlr = SCIPconsGetHdlr(cons);
    10777 assert( conshdlr != NULL );
    10778 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
    10779 {
    10780 SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
    10781 return SCIP_INVALIDDATA;
    10782 }
    10783
    10784 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    10785 assert( conshdlrdata != NULL );
    10786
    10787 SCIP_CALL( appendVarSOS1(scip, cons, conshdlrdata, var) );
    10788
    10789 return SCIP_OKAY;
    10790}
    10791
    10792
    10793/** gets number of variables in SOS1 constraint */
    10795 SCIP* scip, /**< SCIP data structure */
    10796 SCIP_CONS* cons /**< constraint */
    10797 )
    10798{
    10799 SCIP_CONSDATA* consdata;
    10800
    10801 assert( scip != NULL );
    10802 assert( cons != NULL );
    10803
    10804 if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    10805 {
    10806 SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
    10807 SCIPABORT();
    10808 return -1; /*lint !e527*/
    10809 }
    10810
    10811 consdata = SCIPconsGetData(cons);
    10812 assert( consdata != NULL );
    10813
    10814 return consdata->nvars;
    10815}
    10816
    10817
    10818/** gets array of variables in SOS1 constraint */
    10820 SCIP* scip, /**< SCIP data structure */
    10821 SCIP_CONS* cons /**< constraint data */
    10822 )
    10823{
    10824 SCIP_CONSDATA* consdata;
    10825
    10826 assert( scip != NULL );
    10827 assert( cons != NULL );
    10828
    10829 if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    10830 {
    10831 SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
    10832 SCIPABORT();
    10833 return NULL; /*lint !e527*/
    10834 }
    10835
    10836 consdata = SCIPconsGetData(cons);
    10837 assert( consdata != NULL );
    10838
    10839 return consdata->vars;
    10840}
    10841
    10842
    10843/** gets array of weights in SOS1 constraint (or NULL if not existent) */
    10845 SCIP* scip, /**< SCIP data structure */
    10846 SCIP_CONS* cons /**< constraint data */
    10847 )
    10848{
    10849 SCIP_CONSDATA* consdata;
    10850
    10851 assert( scip != NULL );
    10852 assert( cons != NULL );
    10853
    10854 if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    10855 {
    10856 SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
    10857 SCIPABORT();
    10858 return NULL; /*lint !e527*/
    10859 }
    10860
    10861 consdata = SCIPconsGetData(cons);
    10862 assert( consdata != NULL );
    10863
    10864 return consdata->weights;
    10865}
    10866
    10867
    10868/** gets conflict graph of SOS1 constraints (or NULL if not existent)
    10869 *
    10870 * @note The conflict graph is globally valid; local changes are not taken into account.
    10871 */
    10873 SCIP_CONSHDLR* conshdlr /**< SOS1 constraint handler */
    10874 )
    10875{
    10876 SCIP_CONSHDLRDATA* conshdlrdata;
    10877
    10878 assert( conshdlr != NULL );
    10879
    10880 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
    10881 {
    10882 SCIPerrorMessage("not an SOS1 constraint handler.\n");
    10883 SCIPABORT();
    10884 return NULL; /*lint !e527*/
    10885 }
    10886 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    10887 assert( conshdlrdata != NULL );
    10888
    10889 return conshdlrdata->conflictgraph;
    10890}
    10891
    10892
    10893/** gets number of problem variables that are part of the SOS1 conflict graph */
    10895 SCIP_CONSHDLR* conshdlr /**< SOS1 constraint handler */
    10896 )
    10897{
    10898 SCIP_CONSHDLRDATA* conshdlrdata;
    10899
    10900 assert( conshdlr != NULL );
    10901
    10902 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
    10903 {
    10904 SCIPerrorMessage("not an SOS1 constraint handler.\n");
    10905 SCIPABORT();
    10906 return -1; /*lint !e527*/
    10907 }
    10908 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    10909 assert( conshdlrdata != NULL );
    10910
    10911 return conshdlrdata->nsos1vars;
    10912}
    10913
    10914
    10915/** returns whether variable is part of the SOS1 conflict graph */
    10917 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
    10918 SCIP_VAR* var /**< variable */
    10919 )
    10920{
    10921 SCIP_CONSHDLRDATA* conshdlrdata;
    10922
    10923 assert( var != NULL );
    10924 assert( conshdlr != NULL );
    10925
    10926 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
    10927 {
    10928 SCIPerrorMessage("not an SOS1 constraint handler.\n");
    10929 SCIPABORT();
    10930 return FALSE; /*lint !e527*/
    10931 }
    10932 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    10933 assert( conshdlrdata != NULL );
    10934
    10935 return varIsSOS1(conshdlrdata, var);
    10936}
    10937
    10938
    10939/** returns node of variable in the conflict graph or -1 if variable is not part of the SOS1 conflict graph */
    10941 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
    10942 SCIP_VAR* var /**< variable */
    10943 )
    10944{
    10945 SCIP_CONSHDLRDATA* conshdlrdata;
    10946
    10947 assert( conshdlr != NULL );
    10948 assert( var != NULL );
    10949
    10950 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
    10951 {
    10952 SCIPerrorMessage("Not an SOS1 constraint handler.\n");
    10953 SCIPABORT();
    10954 return -1; /*lint !e527*/
    10955 }
    10956 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    10957 assert( conshdlrdata != NULL );
    10958
    10959 if ( conshdlrdata->varhash == NULL )
    10960 {
    10961 SCIPerrorMessage("Hashmap not yet initialized.\n");
    10962 SCIPABORT();
    10963 return -1; /*lint !e527*/
    10964 }
    10965
    10966 return varGetNodeSOS1(conshdlrdata, var);
    10967}
    10968
    10969
    10970/** returns variable that belongs to a given node from the conflict graph */
    10972 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
    10973 int node /**< node from the conflict graph */
    10974 )
    10975{
    10977
    10978 assert( conflictgraph != NULL );
    10979 assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
    10980
    10981 /* get node data */
    10982 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
    10983
    10984 if ( nodedata == NULL )
    10985 {
    10986 SCIPerrorMessage("variable is not assigned to an index.\n");
    10987 SCIPABORT();
    10988 return NULL; /*lint !e527*/
    10989 }
    10990
    10991 return nodedata->var;
    10992}
    10993
    10994
    10995/** based on solution values of the variables, fixes variables to zero to turn all SOS1 constraints feasible */
    10997 SCIP* scip, /**< SCIP pointer */
    10998 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
    10999 SCIP_SOL* sol, /**< solution */
    11000 SCIP_Bool* changed, /**< pointer to store whether the solution has been changed */
    11001 SCIP_Bool* success /**< pointer to store whether SOS1 constraints have been turned feasible and
    11002 * solution was good enough */
    11003 )
    11004{
    11005 SCIP_CONSHDLRDATA* conshdlrdata;
    11006 SCIP_Real roundobjval;
    11007 SCIP_Bool allroundable;
    11008
    11009 assert( scip != NULL );
    11010 assert( conshdlr != NULL );
    11011 assert( sol != NULL );
    11012 assert( changed != NULL );
    11013 assert( success != NULL );
    11014
    11015 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
    11016 {
    11017 SCIPerrorMessage("Not an SOS1 constraint handler.\n");
    11019 }
    11020 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11021 assert( conshdlrdata != NULL );
    11022
    11023 *changed = FALSE;
    11024 *success = FALSE;
    11025 allroundable = FALSE;
    11026
    11027 /* check number of SOS1 constraints */
    11028 if ( SCIPconshdlrGetNConss(conshdlr) < 1 )
    11029 {
    11030 *success = TRUE;
    11031 return SCIP_OKAY;
    11032 }
    11033
    11034 /* if the SOS1 constraints do not overlap, we apply a faster method makeSOS1constraintsFeasible() that does not make use of the conflict graph;
    11035 * for overlapping SOS1 constraints we apply the method makeSOS1conflictgraphFeasible(), which then may produce better feasible solutions */
    11036 if ( conshdlrdata->switchsos1branch )
    11037 {
    11038 SCIP_CALL( makeSOS1constraintsFeasible(scip, conshdlr, sol, changed, &allroundable) );
    11039 }
    11040 else
    11041 {
    11042 SCIP_CALL( makeSOS1conflictgraphFeasible(scip, conshdlr, sol, changed, &allroundable) );
    11043 }
    11044
    11045 if ( ! allroundable ) /*lint !e774*/
    11046 return SCIP_OKAY;
    11047
    11048 /* check whether objective value of rounded solution is good enough */
    11049 roundobjval = SCIPgetSolOrigObj(scip, sol);
    11051 roundobjval *= -1;
    11052
    11053 if ( SCIPisLT(scip, roundobjval, SCIPgetUpperbound(scip) ) )
    11054 *success = TRUE;
    11055
    11056 return SCIP_OKAY;
    11057}
    static long bound
    SCIP_VAR * w
    Definition: circlepacking.c:67
    struct SCIP_NodeData SCIP_NODEDATA
    static SCIP_RETCODE branchCons(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result)
    Constraint handler for linear constraints in their most general form, .
    Constraint handler for the set partitioning / packing / covering constraints .
    #define DEFAULT_MAXSOSADJACENCY
    Definition: cons_sos1.c:137
    static SCIP_RETCODE lockVariableSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
    Definition: cons_sos1.c:748
    #define DEFAULT_AUTOCUTSFROMSOS1
    Definition: cons_sos1.c:174
    #define DEFAULT_MAXADDCOMPS
    Definition: cons_sos1.c:160
    static SCIP_DECL_CONSHDLRCOPY(conshdlrCopySOS1)
    Definition: cons_sos1.c:8920
    static SCIP_Bool isImpliedZero(SCIP_DIGRAPH *conflictgraph, SCIP_Bool *implnodes, int node)
    Definition: cons_sos1.c:2254
    #define CONSHDLR_NEEDSCONS
    Definition: cons_sos1.c:132
    #define CONSHDLR_SEPAFREQ
    Definition: cons_sos1.c:125
    static SCIP_RETCODE getDiveBdChgsSOS1constraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DIVESET *diveset, SCIP_SOL *sol, SCIP_Bool *success)
    Definition: cons_sos1.c:8069
    #define DEFAULT_BRANCHINGRULE
    Definition: cons_sos1.c:153
    static SCIP_RETCODE updateWeightsTCliquegraph(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, TCLIQUE_DATA *tcliquedata, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int nsos1vars)
    Definition: cons_sos1.c:6189
    static SCIP_RETCODE initTCliquegraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, int nsos1vars)
    Definition: cons_sos1.c:6120
    #define DEFAULT_NSTRONGROUNDS
    Definition: cons_sos1.c:167
    static SCIP_RETCODE consdataEnsurevarsSizeSOS1(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool reserveWeights)
    Definition: cons_sos1.c:788
    #define CONSHDLR_CHECKPRIORITY
    Definition: cons_sos1.c:124
    #define DEFAULT_MAXBOUNDCUTS
    Definition: cons_sos1.c:177
    #define DEFAULT_MAXBOUNDCUTSROOT
    Definition: cons_sos1.c:178
    static SCIP_RETCODE getBranchingDecisionStrongbranchSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int nsos1vars, SCIP_Real lpobjval, SCIP_Bool bipbranch, int nstrongrounds, SCIP_Bool *verticesarefixed, int *fixingsnode1, int *fixingsnode2, int *vertexbestprior, SCIP_Real *bestobjval1, SCIP_Real *bestobjval2, SCIP_RESULT *result)
    Definition: cons_sos1.c:4474
    #define CONSHDLR_DESC
    Definition: cons_sos1.c:121
    static SCIP_RETCODE appendVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var)
    Definition: cons_sos1.c:1021
    static SCIP_RETCODE computeNodeDataSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nsos1vars)
    Definition: cons_sos1.c:8642
    #define DIVINGCUTOFFVALUE
    Definition: cons_sos1.c:192
    static SCIP_RETCODE maxWeightIndSetHeuristic(SCIP *scip, SCIP_SOL *sol, SCIP_CONSHDLR *conshdlr, SCIP_DIGRAPH *conflictgraph, int nsos1vars, SCIP_Bool *indicatorzero, SCIP_Bool *indset)
    Definition: cons_sos1.c:7557
    #define CONSHDLR_PROP_TIMING
    Definition: cons_sos1.c:133
    static SCIP_Bool varIsSOS1(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var)
    Definition: cons_sos1.c:538
    #define DEFAULT_AUTOSOS1BRANCH
    Definition: cons_sos1.c:155
    #define DEFAULT_ADDEXTENDEDBDS
    Definition: cons_sos1.c:164
    static SCIP_DECL_CONSENFOPS(consEnfopsSOS1)
    Definition: cons_sos1.c:9440
    static SCIP_DECL_CONSCHECK(consCheckSOS1)
    Definition: cons_sos1.c:9459
    #define DEFAULT_MAXTIGHTENBDS
    Definition: cons_sos1.c:142
    static SCIP_DECL_CONSSEPASOL(consSepasolSOS1)
    Definition: cons_sos1.c:9392
    static SCIP_RETCODE tightenVarsBoundsSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_DIGRAPH *implgraph, SCIP_HASHMAP *implhash, SCIP_Bool **adjacencymatrix, SCIP_VAR **totalvars, int ntotalvars, int nsos1vars, int *nchgbds, SCIP_Bool *implupdate, SCIP_Bool *cutoff)
    Definition: cons_sos1.c:2682
    static SCIP_Real nodeGetSolvalVarboundUbSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int node)
    Definition: cons_sos1.c:511
    static SCIP_DECL_CONSLOCK(consLockSOS1)
    Definition: cons_sos1.c:9753
    static SCIP_RETCODE handleNewVariableSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var, SCIP_Bool transformed)
    Definition: cons_sos1.c:816
    #define DEFAULT_BOUNDCUTSDEPTH
    Definition: cons_sos1.c:176
    #define DEFAULT_DEPTHIMPLANALYSIS
    Definition: cons_sos1.c:144
    #define CONSHDLR_MAXPREROUNDS
    Definition: cons_sos1.c:129
    static SCIP_RETCODE getVectorOfWeights(SCIP *scip, SCIP_SOL *sol, SCIP_DIGRAPH *conflictgraph, int nsos1vars, SCIP_Bool *indicatorzero, SCIP_Real *weights)
    Definition: cons_sos1.c:7345
    static SCIP_RETCODE getCoverVertices(SCIP_DIGRAPH *conflictgraph, SCIP_Bool *verticesarefixed, int vertex, int *neightocover, int nneightocover, int *coververtices, int *ncoververtices)
    Definition: cons_sos1.c:4008
    static SCIP_RETCODE getBoundConsFromVertices(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int v1, int v2, SCIP_VAR *boundvar, SCIP_Bool extend, SCIP_CONS *cons, SCIP_Real *feas)
    Definition: cons_sos1.c:4691
    static SCIP_RETCODE updateImplicationGraphSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_Bool **adjacencymatrix, SCIP_DIGRAPH *implgraph, SCIP_HASHMAP *implhash, SCIP_Bool *implnodes, SCIP_VAR **totalvars, int **cliquecovers, int *cliquecoversizes, int *varincover, SCIP_VAR **vars, SCIP_Real *coefs, int nvars, SCIP_Real *bounds, SCIP_VAR *var, SCIP_Real bound, SCIP_Real boundnonzero, int ninftynonzero, SCIP_Bool lower, int *nchgbds, SCIP_Bool *update, SCIP_Bool *infeasible)
    Definition: cons_sos1.c:2409
    static SCIP_DECL_CONSENFOLP(consEnfolpSOS1)
    Definition: cons_sos1.c:9408
    #define DEFAULT_IMPLPROP
    Definition: cons_sos1.c:148
    static SCIP_RETCODE checkSwitchNonoverlappingSOS1Methods(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_CONS **conss, int nconss)
    Definition: cons_sos1.c:8561
    static SCIP_RETCODE enforceConflictgraph(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_RESULT *result)
    Definition: cons_sos1.c:5339
    static SCIP_RETCODE makeSOS1conflictgraphFeasible(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_Bool *changed, SCIP_Bool *allroundable)
    Definition: cons_sos1.c:7663
    static SCIP_RETCODE getDiveBdChgsSOS1conflictgraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DIVESET *diveset, SCIP_SOL *sol, SCIP_Bool *success)
    Definition: cons_sos1.c:7928
    #define CONSHDLR_SEPAPRIORITY
    Definition: cons_sos1.c:122
    static SCIP_RETCODE sepaImplBoundCutsSOS1(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_SOL *sol, int maxcuts, int *ngen, SCIP_Bool *cutoff)
    Definition: cons_sos1.c:6999
    static int varGetNodeSOS1(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var)
    Definition: cons_sos1.c:555
    #define DEFAULT_STRTHENBOUNDCUTS
    Definition: cons_sos1.c:179
    static SCIP_RETCODE passConComponentVarbound(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int node, SCIP_VAR *boundvar, SCIP_Bool checklb, SCIP_Bool *processed, int *concomp, int *nconcomp, SCIP_Bool *unique)
    Definition: cons_sos1.c:8326
    #define DEFAULT_BRANCHSTRATEGIES
    Definition: cons_sos1.c:152
    static SCIP_RETCODE detectVarboundSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var0, SCIP_VAR *var1, SCIP_Real val0, SCIP_Real val1)
    Definition: cons_sos1.c:8250
    static SCIP_Bool isViolatedSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int node, SCIP_SOL *sol)
    Definition: cons_sos1.c:389
    #define DEFAULT_SOSCONSPROP
    Definition: cons_sos1.c:149
    static SCIP_RETCODE propVariableNonzero(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_DIGRAPH *implgraph, SCIP_CONS *cons, int node, SCIP_Bool implprop, SCIP_Bool *cutoff, int *ngen)
    Definition: cons_sos1.c:3635
    static SCIP_RETCODE presolRoundConsSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *substituted, SCIP_Bool *cutoff, SCIP_Bool *success, int *ndelconss, int *nupgdconss, int *nfixedvars, int *nremovedvars)
    Definition: cons_sos1.c:1599
    static SCIP_RETCODE checkLinearConssVarboundSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **linconss, int nlinconss)
    Definition: cons_sos1.c:8488
    static SCIP_DECL_CONSPROP(consPropSOS1)
    Definition: cons_sos1.c:9531
    #define DEFAULT_MAXEXTENSIONS
    Definition: cons_sos1.c:141
    #define DEFAULT_FIXNONZERO
    Definition: cons_sos1.c:156
    static SCIP_RETCODE fixVariableZeroNode(SCIP *scip, SCIP_VAR *var, SCIP_NODE *node, SCIP_Bool *infeasible)
    Definition: cons_sos1.c:576
    static SCIP_RETCODE makeSOS1constraintsFeasible(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_Bool *changed, SCIP_Bool *allroundable)
    Definition: cons_sos1.c:7793
    static SCIP_RETCODE freeConflictgraph(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
    Definition: cons_sos1.c:8874
    static SCIP_DECL_CONSEXITSOL(consExitsolSOS1)
    Definition: cons_sos1.c:9012
    static SCIP_DECL_CONSTRANS(consTransSOS1)
    Definition: cons_sos1.c:9138
    static SCIP_DECL_CONSENFORELAX(consEnforelaxSOS1)
    Definition: cons_sos1.c:9424
    #define DEFAULT_ADDCOMPSFEAS
    Definition: cons_sos1.c:162
    #define DEFAULT_ADDCOMPS
    Definition: cons_sos1.c:158
    static SCIP_RETCODE updateArcData(SCIP *scip, SCIP_DIGRAPH *implgraph, SCIP_HASHMAP *implhash, SCIP_VAR **totalvars, SCIP_VAR *varv, SCIP_VAR *varw, SCIP_Real lb, SCIP_Real ub, SCIP_Real newbound, SCIP_Bool lower, int *nchgbds, SCIP_Bool *update, SCIP_Bool *infeasible)
    Definition: cons_sos1.c:2283
    static SCIP_DECL_CONSFREE(consFreeSOS1)
    Definition: cons_sos1.c:8937
    static SCIP_DECL_CONSCOPY(consCopySOS1)
    Definition: cons_sos1.c:9829
    #define DEFAULT_MAXIMPLCUTS
    Definition: cons_sos1.c:182
    static SCIP_RETCODE inferVariableZero(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened, SCIP_Bool *success)
    Definition: cons_sos1.c:705
    static SCIP_DECL_EVENTEXEC(eventExecSOS1)
    Definition: cons_sos1.c:10027
    #define DEFAULT_BOUNDCUTSFROMSOS1
    Definition: cons_sos1.c:172
    static SCIP_RETCODE getBranchingVerticesSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, SCIP_Bool *verticesarefixed, SCIP_Bool bipbranch, int branchvertex, int *fixingsnode1, int *nfixingsnode1, int *fixingsnode2, int *nfixingsnode2)
    Definition: cons_sos1.c:4115
    static SCIP_DECL_CONSINITSOL(consInitsolSOS1)
    Definition: cons_sos1.c:8959
    static SCIP_DECL_CONSPRESOL(consPresolSOS1)
    Definition: cons_sos1.c:9232
    #define DEFAULT_ADDCOMPSDEPTH
    Definition: cons_sos1.c:161
    static SCIP_RETCODE getBranchingPrioritiesSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int nsos1vars, SCIP_Bool *verticesarefixed, SCIP_Bool bipbranch, int *fixingsnode1, int *fixingsnode2, SCIP_Real *branchpriors, int *vertexbestprior, SCIP_Bool *relsolfeas)
    Definition: cons_sos1.c:4228
    static SCIP_RETCODE genConflictgraphLinearCons(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraphlin, SCIP_DIGRAPH *conflictgraphorig, SCIP_VAR **linvars, int nlinvars, int *posinlinvars)
    Definition: cons_sos1.c:1379
    static SCIP_DECL_CONSGETVARS(consGetVarsSOS1)
    Definition: cons_sos1.c:9983
    static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphSOS1)
    Definition: cons_sos1.c:10189
    static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphSOS1)
    Definition: cons_sos1.c:10255
    static SCIP_RETCODE fixVariableZero(SCIP *scip, SCIP_VAR *var, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: cons_sos1.c:631
    static SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsSOS1)
    Definition: cons_sos1.c:10149
    static SCIP_Real nodeGetSolvalBinaryBigMSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int node)
    Definition: cons_sos1.c:434
    static SCIP_RETCODE initConflictgraph(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss)
    Definition: cons_sos1.c:8679
    static SCIP_RETCODE initsepaBoundInequalityFromSOS1Cons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool solvedinitlp, int maxboundcuts, int *ngen, SCIP_Bool *cutoff)
    Definition: cons_sos1.c:6885
    static SCIP_RETCODE generateBoundInequalityFromSOS1Nodes(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DIGRAPH *conflictgraph, int *nodes, int nnodes, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool global, SCIP_Bool strengthen, SCIP_Bool removable, const char *nameext, SCIP_ROW **rowlb, SCIP_ROW **rowub)
    Definition: cons_sos1.c:6323
    #define DEFAULT_NSTRONGITER
    Definition: cons_sos1.c:169
    static SCIP_RETCODE enforceSOS1(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_RESULT *result)
    Definition: cons_sos1.c:6057
    #define DEFAULT_BOUNDCUTSFREQ
    Definition: cons_sos1.c:175
    static SCIP_RETCODE computeVarsCoverSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraphroot, SCIP_DIGRAPH *conflictgraphlin, SCIP_VAR **linvars, SCIP_Bool *coveredvars, int *clique, int *cliquesize, int v, SCIP_Bool considersolvals)
    Definition: cons_sos1.c:2571
    static SCIP_RETCODE enforceConssSOS1(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_RESULT *result)
    Definition: cons_sos1.c:5811
    static SCIP_DECL_CONSPRINT(consPrintSOS1)
    Definition: cons_sos1.c:9799
    static SCIP_RETCODE checkConComponentsVarbound(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int nsos1vars, SCIP_Bool checklb)
    Definition: cons_sos1.c:8399
    static SCIP_RETCODE unlockVariableSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
    Definition: cons_sos1.c:768
    static SCIP_Bool isConnectedSOS1(SCIP_Bool **adjacencymatrix, SCIP_DIGRAPH *conflictgraph, int vertex1, int vertex2)
    Definition: cons_sos1.c:329
    #define DEFAULT_BOUNDCUTSFROMGRAPH
    Definition: cons_sos1.c:173
    static SCIP_RETCODE addBranchingComplementaritiesSOS1(SCIP *scip, SCIP_NODE *node, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_DIGRAPH *localconflicts, SCIP_SOL *sol, int nsos1vars, SCIP_Bool *verticesarefixed, int *fixingsnode1, int nfixingsnode1, int *fixingsnode2, int nfixingsnode2, int *naddedconss, SCIP_Bool onlyviolsos1)
    Definition: cons_sos1.c:4919
    #define CONSHDLR_PROPFREQ
    Definition: cons_sos1.c:126
    static SCIP_RETCODE performStrongbranchSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int *fixingsexec, int nfixingsexec, int *fixingsop, int nfixingsop, int inititer, SCIP_Bool fixnonzero, int *domainfixings, int *ndomainfixings, SCIP_Bool *infeasible, SCIP_Real *objval, SCIP_Bool *lperror)
    Definition: cons_sos1.c:4332
    #define DEFAULT_ADDBDSFEAS
    Definition: cons_sos1.c:163
    static SCIP_DECL_CONSRESPROP(consRespropSOS1)
    Definition: cons_sos1.c:9677
    static SCIP_DECL_CONSSEPALP(consSepalpSOS1)
    Definition: cons_sos1.c:9376
    static SCIP_RETCODE generateBoundInequalityFromSOS1Cons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool local, SCIP_Bool global, SCIP_Bool strengthen, SCIP_Bool removable, SCIP_ROW **rowlb, SCIP_ROW **rowub)
    Definition: cons_sos1.c:6822
    static SCIP_RETCODE getSOS1Implications(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR **vars, SCIP_DIGRAPH *implgraph, SCIP_HASHMAP *implhash, SCIP_Bool *implnodes, int node)
    Definition: cons_sos1.c:1533
    static SCIP_RETCODE addVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var, SCIP_Real weight)
    Definition: cons_sos1.c:951
    static SCIP_RETCODE freeImplGraphSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
    Definition: cons_sos1.c:3949
    #define CONSHDLR_PRESOLTIMING
    Definition: cons_sos1.c:134
    #define DEFAULT_IMPLCUTSDEPTH
    Definition: cons_sos1.c:181
    #define DEFAULT_CONFLICTPROP
    Definition: cons_sos1.c:147
    #define DEFAULT_MAXIMPLCUTSROOT
    Definition: cons_sos1.c:183
    #define DEFAULT_IMPLCUTSFREQ
    Definition: cons_sos1.c:180
    struct SCIP_SuccData SCIP_SUCCDATA
    Definition: cons_sos1.c:231
    static SCIP_RETCODE presolRoundConssSOS1(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_Bool **adjacencymatrix, SCIP_CONS **conss, int nconss, int nsos1vars, int *naddconss, int *ndelconss, int *nupgdconss, int *nfixedvars, int *nremovedvars, SCIP_RESULT *result)
    Definition: cons_sos1.c:1824
    static SCIP_RETCODE resetConflictgraphSOS1(SCIP_DIGRAPH *conflictgraph, SCIP_DIGRAPH *localconflicts, int nsos1vars)
    Definition: cons_sos1.c:5283
    #define CONSHDLR_EAGERFREQ
    Definition: cons_sos1.c:127
    #define EVENTHDLR_DESC
    Definition: cons_sos1.c:187
    static SCIP_RETCODE initImplGraphSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, int nsos1vars, int maxrounds, int *nchgbds, SCIP_Bool *cutoff, SCIP_Bool *success)
    Definition: cons_sos1.c:3778
    #define EVENTHDLR_EVENT_TYPE
    Definition: cons_sos1.c:189
    static SCIP_DECL_CONSPARSE(consParseSOS1)
    Definition: cons_sos1.c:9893
    #define CONSHDLR_ENFOPRIORITY
    Definition: cons_sos1.c:123
    static SCIP_DECL_CONSDELETE(consDeleteSOS1)
    Definition: cons_sos1.c:9084
    #define DEFAULT_PERFIMPLANALYSIS
    Definition: cons_sos1.c:143
    static SCIP_RETCODE markNeighborsMWISHeuristic(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DIGRAPH *conflictgraph, int node, SCIP_Bool *mark, SCIP_Bool *indset, int *cnt, SCIP_Bool *cutoff)
    Definition: cons_sos1.c:7416
    #define CONSHDLR_DELAYSEPA
    Definition: cons_sos1.c:130
    static SCIP_RETCODE presolRoundVarsSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_Bool **adjacencymatrix, int nsos1vars, int *nfixedvars, int *nchgbds, int *naddconss, SCIP_RESULT *result)
    Definition: cons_sos1.c:3363
    static SCIP_RETCODE sepaBoundInequalitiesFromGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_SOL *sol, int maxboundcuts, int *ngen, SCIP_Bool *cutoff)
    Definition: cons_sos1.c:6748
    static SCIP_RETCODE addBoundCutSepa(SCIP *scip, TCLIQUE_DATA *tcliquedata, SCIP_ROW *rowlb, SCIP_ROW *rowub, SCIP_Bool *success, SCIP_Bool *cutoff)
    Definition: cons_sos1.c:6249
    static TCLIQUE_NEWSOL(tcliqueNewsolClique)
    Definition: cons_sos1.c:6613
    static SCIP_RETCODE propConsSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_Bool *cutoff, int *ngen)
    Definition: cons_sos1.c:3537
    static SCIP_RETCODE extensionOperatorSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_Bool **adjacencymatrix, SCIP_DIGRAPH *vertexcliquegraph, int nsos1vars, int nconss, SCIP_CONS *cons, SCIP_VAR **vars, SCIP_Real *weights, SCIP_Bool firstcall, SCIP_Bool usebacktrack, int **cliques, int *ncliques, int *cliquesizes, int *newclique, int *workingset, int nworkingset, int nexts, int pos, int *maxextensions, int *naddconss, SCIP_Bool *success)
    Definition: cons_sos1.c:1118
    #define CONSHDLR_NAME
    Definition: cons_sos1.c:120
    #define EVENTHDLR_NAME
    Definition: cons_sos1.c:186
    static SCIP_DECL_CONSGETNVARS(consGetNVarsSOS1)
    Definition: cons_sos1.c:10006
    static SCIP_RETCODE deleteVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
    Definition: cons_sos1.c:1079
    static SCIP_DECL_CONSINITLP(consInitlpSOS1)
    Definition: cons_sos1.c:9351
    static SCIP_RETCODE performImplicationGraphAnalysis(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_VAR **totalvars, SCIP_DIGRAPH *implgraph, SCIP_HASHMAP *implhash, SCIP_Bool **adjacencymatrix, int givennode, int nonznode, SCIP_Real *impllbs, SCIP_Real *implubs, SCIP_Bool *implnodes, int *naddconss, int *probingdepth, SCIP_Bool *infeasible)
    Definition: cons_sos1.c:2096
    #define CONSHDLR_DELAYPROP
    Definition: cons_sos1.c:131
    static SCIP_Real nodeGetSolvalVarboundLbSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int node)
    Definition: cons_sos1.c:484
    static SCIP_RETCODE cliqueGetCommonSuccessorsSOS1(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, int *clique, SCIP_VAR **vars, int nvars, int *comsucc, int *ncomsucc)
    Definition: cons_sos1.c:1432
    static SCIP_RETCODE separateSOS1(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, int nconss, SCIP_CONS **conss, SCIP_RESULT *result)
    Definition: cons_sos1.c:7224
    constraint handler for SOS type 1 constraints
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:297
    #define SCIP_REAL_MAX
    Definition: def.h:158
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIPABORT()
    Definition: def.h:327
    #define SCIP_REAL_MIN
    Definition: def.h:159
    #define REALABS(x)
    Definition: def.h:182
    #define SCIP_CALL(x)
    Definition: def.h:355
    #define nnodes
    Definition: gastrans.c:74
    static const NodeData nodedata[]
    Definition: gastrans.c:83
    void SCIPcomputeArraysSetminusInt(int *array1, int narray1, int *array2, int narray2, int *setminusarray, int *nsetminusarray)
    Definition: misc.c:10639
    void SCIPcomputeArraysIntersectionInt(int *array1, int narray1, int *array2, int narray2, int *intersectarray, int *nintersectarray)
    Definition: misc.c:10530
    SCIP_Real SCIPgetRhsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_DIGRAPH * SCIPgetConflictgraphSOS1(SCIP_CONSHDLR *conshdlr)
    Definition: cons_sos1.c:10872
    SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_Bool SCIPvarIsSOS1(SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
    Definition: cons_sos1.c:10916
    SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
    SCIP_RETCODE SCIPmakeSOS1sFeasible(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_Bool *changed, SCIP_Bool *success)
    Definition: cons_sos1.c:10996
    SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
    int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPaddVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real weight)
    Definition: cons_sos1.c:10725
    SCIP_Real * SCIPgetValsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsSOS1(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    Definition: cons_sos1.c:10579
    SCIP_RETCODE SCIPcreateConsBasicSOS1(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights)
    Definition: cons_sos1.c:10709
    SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    Definition: cons_setppc.c:9460
    SCIP_Real * SCIPgetWeightsSOS1(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_sos1.c:10844
    SCIP_RETCODE SCIPappendVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
    Definition: cons_sos1.c:10761
    int SCIPgetNSOS1Vars(SCIP_CONSHDLR *conshdlr)
    Definition: cons_sos1.c:10894
    int SCIPvarGetNodeSOS1(SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
    Definition: cons_sos1.c:10940
    SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    SCIP_VAR ** SCIPgetVarsSOS1(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_sos1.c:10819
    int SCIPgetNVarsSOS1(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_sos1.c:10794
    SCIP_VAR * SCIPnodeGetVarSOS1(SCIP_DIGRAPH *conflictgraph, int node)
    Definition: cons_sos1.c:10971
    SCIP_RETCODE SCIPincludeConshdlrSOS1(SCIP *scip)
    Definition: cons_sos1.c:10361
    SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
    Definition: scip_copy.c:713
    void ** SCIPdigraphGetSuccessorsData(SCIP_DIGRAPH *digraph, int node)
    Definition: misc.c:7914
    int SCIPdigraphGetNSuccessors(SCIP_DIGRAPH *digraph, int node)
    Definition: misc.c:7881
    int SCIPdigraphGetNNodes(SCIP_DIGRAPH *digraph)
    Definition: misc.c:7823
    SCIP_RETCODE SCIPdigraphAddArc(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
    Definition: misc.c:7739
    SCIP_RETCODE SCIPdigraphAddArcSafe(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
    Definition: misc.c:7770
    void SCIPdigraphFree(SCIP_DIGRAPH **digraph)
    Definition: misc.c:7645
    int SCIPdigraphGetNArcs(SCIP_DIGRAPH *digraph)
    Definition: misc.c:7863
    void * SCIPdigraphGetNodeData(SCIP_DIGRAPH *digraph, int node)
    Definition: misc.c:7833
    void SCIPdigraphSetNodeData(SCIP_DIGRAPH *digraph, void *dataptr, int node)
    Definition: misc.c:7849
    SCIP_RETCODE SCIPdigraphSetNSuccessors(SCIP_DIGRAPH *digraph, int node, int nsuccessors)
    Definition: misc.c:7807
    int * SCIPdigraphGetSuccessors(SCIP_DIGRAPH *digraph, int node)
    Definition: misc.c:7896
    SCIP_RETCODE SCIPcreateDigraph(SCIP *scip, SCIP_DIGRAPH **digraph, int nnodes)
    SCIP_Bool SCIPisTransformed(SCIP *scip)
    Definition: scip_general.c:647
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:759
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    SCIP_RETCODE SCIPaddConsUpgrade(SCIP *scip, SCIP_CONS *oldcons, SCIP_CONS **newcons)
    Definition: scip_prob.c:3368
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3420
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
    Definition: scip_prob.c:1400
    int SCIPgetNTotalVars(SCIP *scip)
    Definition: scip_prob.c:3064
    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
    SCIP_RETCODE SCIPupdateNodeLowerbound(SCIP *scip, SCIP_NODE *node, SCIP_Real newbound)
    Definition: scip_prob.c:4354
    SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:4067
    SCIP_RETCODE SCIPaddConsNode(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode)
    Definition: scip_prob.c:3901
    SCIP_Real SCIPgetLocalTransEstimate(SCIP *scip)
    Definition: scip_prob.c:4139
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:167
    SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:83
    SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:139
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    void SCIPswapInts(int *value1, int *value2)
    Definition: misc.c:10485
    void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
    Definition: misc.c:10498
    SCIP_Real SCIPcalcNodeselPriority(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR branchdir, SCIP_Real targetvalue)
    Definition: scip_branch.c:928
    SCIP_Real SCIPcalcChildEstimate(SCIP *scip, SCIP_VAR *var, SCIP_Real targetvalue)
    Definition: scip_branch.c:955
    SCIP_Real SCIPcalcChildEstimateIncrease(SCIP *scip, SCIP_VAR *var, SCIP_Real varsol, SCIP_Real targetvalue)
    Definition: scip_branch.c:979
    SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
    Definition: scip_branch.c:1025
    SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
    SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
    SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
    Definition: scip_cons.c:808
    SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
    Definition: scip_cons.c:540
    SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
    Definition: scip_cons.c:831
    SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
    Definition: scip_cons.c:235
    SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
    Definition: scip_cons.c:281
    SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
    Definition: scip_cons.c:181
    SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)))
    Definition: scip_cons.c:900
    SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
    Definition: scip_cons.c:578
    SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
    Definition: scip_cons.c:372
    SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
    Definition: scip_cons.c:323
    int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4778
    SCIP_RETCODE SCIPsetConshdlrGetDiveBdChgs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETDIVEBDCHGS((*consgetdivebdchgs)))
    Definition: scip_cons.c:877
    const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4316
    SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
    Definition: scip_cons.c:347
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)))
    Definition: scip_cons.c:924
    SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
    Definition: scip_cons.c:468
    SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
    Definition: scip_cons.c:624
    SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
    Definition: scip_cons.c:444
    SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4336
    SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
    Definition: scip_cons.c:601
    SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
    Definition: scip_cons.c:647
    SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
    Definition: scip_cons.c:854
    SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4735
    SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
    Definition: scip_cons.c:785
    SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
    Definition: cons.c:8419
    SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
    Definition: cons.c:8648
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8409
    SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
    Definition: cons.c:8558
    SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
    Definition: scip_cons.c:2536
    SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
    Definition: cons.c:8588
    SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
    Definition: cons.c:8698
    SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
    Definition: cons.c:8578
    SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    Definition: scip_cons.c:997
    SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
    Definition: cons.c:8608
    SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
    Definition: cons.c:8628
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8389
    SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1812
    SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
    Definition: cons.c:8638
    SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
    Definition: cons.c:8668
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
    Definition: cons.c:8568
    SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
    Definition: cons.c:8658
    SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:117
    SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
    Definition: scip_cut.c:135
    SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
    Definition: scip_cut.c:225
    SCIP_Bool SCIPdivesetSupportsType(SCIP_DIVESET *diveset, SCIP_DIVETYPE divetype)
    Definition: heur.c:753
    SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: scip_event.c:111
    const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
    Definition: event.c:396
    SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
    Definition: event.c:1194
    SCIP_RETCODE 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_Real SCIPeventGetOldbound(SCIP_EVENT *event)
    Definition: event.c:1391
    SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
    Definition: event.c:1217
    SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
    Definition: event.c:1415
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    SCIP_Real SCIPgetLPObjval(SCIP *scip)
    Definition: scip_lp.c:253
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPreallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:128
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPduplicateBufferArray(scip, ptr, source, num)
    Definition: scip_mem.h:132
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
    Definition: scip_mem.h:99
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
    Definition: scip_mem.h:111
    #define SCIPfreeBufferArrayNull(scip, ptr)
    Definition: scip_mem.h:137
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    #define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
    Definition: scip_mem.h:105
    SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
    Definition: tree.c:8483
    SCIP_RETCODE SCIPgetDivesetScore(SCIP *scip, SCIP_DIVESET *diveset, SCIP_DIVETYPE divetype, SCIP_VAR *divecand, SCIP_Real divecandsol, SCIP_Real divecandfrac, SCIP_Real *candscore, SCIP_Bool *roundup)
    SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_probing.c:346
    SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_probing.c:302
    SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
    Definition: scip_probing.c:581
    SCIP_RETCODE SCIPstartProbing(SCIP *scip)
    Definition: scip_probing.c:120
    SCIP_RETCODE SCIPaddDiveBoundChange(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir, SCIP_Real value, SCIP_Bool preferred)
    SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
    Definition: scip_probing.c:825
    SCIP_RETCODE SCIPfixVarProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval)
    Definition: scip_probing.c:419
    SCIP_RETCODE SCIPendProbing(SCIP *scip)
    Definition: scip_probing.c:261
    SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1581
    SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1604
    SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1367
    SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_lp.c:1646
    SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
    Definition: scip_lp.c:2176
    SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
    Definition: lp.c:17917
    SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_lp.c:1672
    void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
    Definition: scip_sol.c:453
    SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1892
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1571
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Real SCIPgetUpperbound(SCIP *scip)
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_Longint SCIPgetNNodeInitLPs(SCIP *scip)
    SCIP_Longint SCIPgetNDualResolveLPIterations(SCIP *scip)
    SCIP_Longint SCIPgetNNodeInitLPIterations(SCIP *scip)
    SCIP_Longint SCIPgetNDualResolveLPs(SCIP *scip)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasGT(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_Real SCIPsumepsilon(SCIP *scip)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
    Definition: scip_tree.c:91
    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
    SCIP_Real SCIPvarGetNegationConstant(SCIP_VAR *var)
    Definition: var.c:23889
    SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
    Definition: scip_var.c:5210
    SCIP_Bool SCIPvarMayRoundUp(SCIP_VAR *var)
    Definition: var.c:4484
    SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
    Definition: var.c:23843
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23642
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23478
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23386
    SCIP_Real SCIPvarGetAggrConstant(SCIP_VAR *var)
    Definition: var.c:23771
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
    Definition: var.c:23430
    SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:7069
    SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR *var)
    Definition: var.c:4473
    SCIP_RETCODE SCIPchgVarUbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:6088
    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_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
    Definition: scip_var.c:728
    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:24142
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23652
    SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
    Definition: scip_var.c:5118
    SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
    Definition: scip_var.c:5296
    SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
    Definition: scip_var.c:2872
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize)
    Definition: scip_var.c:2378
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23490
    SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:2332
    SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
    Definition: var.c:23806
    int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
    Definition: var.c:23794
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24234
    SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
    Definition: var.c:23878
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24120
    SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:11057
    SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
    Definition: scip_var.c:10318
    SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6964
    SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
    Definition: scip_var.c:2736
    int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
    Definition: var.c:17274
    SCIP_RETCODE SCIPchgVarLbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:6044
    SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
    Definition: scip_var.c:361
    SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
    Definition: scip_var.c:2078
    SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
    Definition: var.c:23818
    SCIP_VAR * SCIPvarGetAggrVar(SCIP_VAR *var)
    Definition: var.c:23736
    void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
    void SCIPsortRealPtr(SCIP_Real *realarray, void **ptrarray, int len)
    void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
    void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
    void SCIPsortInt(int *intarray, int len)
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    SCIP_RETCODE SCIPskipSpace(char **s)
    Definition: misc.c:10816
    SCIP_RETCODE SCIPaddSymgraphEdge(SCIP *scip, SYM_GRAPH *graph, int first, int second, SCIP_Bool hasval, SCIP_Real val)
    SCIP_RETCODE SCIPaddSymgraphOpnode(SCIP *scip, SYM_GRAPH *graph, int op, int *nodeidx)
    SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
    SCIP_RETCODE SCIPaddSymgraphValnode(SCIP *scip, SYM_GRAPH *graph, SCIP_Real val, int *nodeidx)
    int SCIPgetSymgraphVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
    SCIP_RETCODE SCIPaddSymgraphConsnode(SCIP *scip, SYM_GRAPH *graph, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, int *nodeidx)
    SCIP_RETCODE SCIPaddSymgraphVarAggregation(SCIP *scip, SYM_GRAPH *graph, int rootidx, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Real constant)
    int SCIPgetSymgraphNegatedVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
    memory allocation routines
    #define BMScopyMemoryArray(ptr, source, num)
    Definition: memory.h:134
    public methods for managing constraints
    public methods for managing events
    public methods for primal heuristics
    public methods for LP management
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    public data structures and miscellaneous methods
    #define SCIPisFinite(x)
    Definition: pub_misc.h:82
    methods for sorting joint arrays of various types
    public methods for branch and bound tree
    public methods for problem variables
    public methods for branching rule plugins and branching
    public methods for conflict handler plugins and conflict analysis
    public methods for constraint handler plugins and constraints
    public methods for problem copies
    public methods for cuts and aggregation rows
    public methods for data structures
    public methods for event handler plugins and event handlers
    general public methods
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for the probing mode
    public methods for solutions
    public methods for querying solving statistics
    public methods for the branch-and-bound tree
    public methods for SCIP variables
    static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
    Main separation function.
    Definition: sepa_flower.c:1221
    int maxboundcuts
    Definition: cons_sos1.c:245
    SCIP_Bool cutoff
    Definition: cons_sos1.c:242
    SCIP_Bool strthenboundcuts
    Definition: cons_sos1.c:246
    SCIP_Real scaleval
    Definition: cons_sos1.c:241
    SCIP * scip
    Definition: cons_sos1.c:237
    SCIP_SOL * sol
    Definition: cons_sos1.c:240
    SCIP_CONSHDLR * conshdlr
    Definition: cons_sos1.c:238
    int nboundcuts
    Definition: cons_sos1.c:244
    SCIP_DIGRAPH * conflictgraph
    Definition: cons_sos1.c:239
    structs for symmetry computations
    methods for dealing with symmetry detection graphs
    tclique user interface
    void tcliqueChangeWeight(TCLIQUE_GRAPH *tcliquegraph, int node, TCLIQUE_WEIGHT weight)
    void tcliqueFree(TCLIQUE_GRAPH **tcliquegraph)
    enum TCLIQUE_Status TCLIQUE_STATUS
    Definition: tclique.h:68
    int TCLIQUE_WEIGHT
    Definition: tclique.h:48
    void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
    TCLIQUE_Bool tcliqueFlush(TCLIQUE_GRAPH *tcliquegraph)
    struct TCLIQUE_Graph TCLIQUE_GRAPH
    Definition: tclique.h:49
    TCLIQUE_Bool tcliqueCreate(TCLIQUE_GRAPH **tcliquegraph)
    TCLIQUE_Bool tcliqueAddNode(TCLIQUE_GRAPH *tcliquegraph, int node, TCLIQUE_WEIGHT weight)
    TCLIQUE_Bool tcliqueAddEdge(TCLIQUE_GRAPH *tcliquegraph, int node1, int node2)
    struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
    Definition: type_cons.h:64
    struct SCIP_ConsData SCIP_CONSDATA
    Definition: type_cons.h:65
    #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
    #define SCIP_EVENTTYPE_LBRELAXED
    Definition: type_event.h:78
    #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
    #define SCIP_EVENTTYPE_UBRELAXED
    Definition: type_event.h:80
    #define SCIP_DIVETYPE_SOS1VARIABLE
    Definition: type_heur.h:61
    @ SCIP_BRANCHDIR_DOWNWARDS
    Definition: type_history.h:43
    @ SCIP_BRANCHDIR_FIXED
    Definition: type_history.h:45
    enum SCIP_LPSolStat SCIP_LPSOLSTAT
    Definition: type_lp.h:52
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_LPSOLSTAT_TIMELIMIT
    Definition: type_lp.h:49
    @ SCIP_LPSOLSTAT_INFEASIBLE
    Definition: type_lp.h:45
    @ SCIP_LPSOLSTAT_OBJLIMIT
    Definition: type_lp.h:47
    @ SCIP_LPSOLSTAT_ITERLIMIT
    Definition: type_lp.h:48
    @ SCIP_OBJSENSE_MAXIMIZE
    Definition: type_prob.h:47
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_FEASIBLE
    Definition: type_result.h:45
    @ SCIP_REDUCEDDOM
    Definition: type_result.h:51
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_BRANCHED
    Definition: type_result.h:54
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    @ SCIP_SUCCESS
    Definition: type_result.h:58
    @ SCIP_INFEASIBLE
    Definition: type_result.h:46
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_INVALIDDATA
    Definition: type_retcode.h:52
    @ SCIP_PLUGINNOTFOUND
    Definition: type_retcode.h:54
    @ SCIP_PARAMETERWRONGVAL
    Definition: type_retcode.h:57
    @ SCIP_NOMEMORY
    Definition: type_retcode.h:44
    @ 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_TRANSFORMED
    Definition: type_set.h:47
    @ SYM_CONSOPTYPE_SUM
    Definition: type_symmetry.h:83
    @ SYM_SYMTYPE_PERM
    Definition: type_symmetry.h:61
    @ SCIP_VARSTATUS_MULTAGGR
    Definition: type_var.h:56
    @ SCIP_VARSTATUS_NEGATED
    Definition: type_var.h:57
    @ SCIP_VARSTATUS_AGGREGATED
    Definition: type_var.h:55
    @ SCIP_LOCKTYPE_MODEL
    Definition: type_var.h:141
    enum SCIP_Varstatus SCIP_VARSTATUS
    Definition: type_var.h:59