SCIP

    Solving Constraint Integer Programs

    cons_indicator.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file cons_indicator.c
    26 * @ingroup DEFPLUGINS_CONS
    27 * @brief constraint handler for indicator constraints
    28 * @author Marc Pfetsch
    29 *
    30 * An indicator constraint is given by a binary variable \f$y\f$ and an inequality \f$ax \leq
    31 * b\f$. It states that if \f$y = 1\f$ then \f$ax \leq b\f$ holds.
    32 *
    33 * This constraint is handled by adding a slack variable \f$s:\; ax - s \leq b\f$ with \f$s \geq
    34 * 0\f$. The constraint is enforced by fixing \f$s\f$ to 0 if \f$y = 1\f$.
    35 *
    36 * @note The constraint only implements an implication not an equivalence, i.e., it does not ensure
    37 * that \f$y = 1\f$ if \f$ax \leq b\f$ or equivalently if \f$s = 0\f$ holds.
    38 *
    39 * This constraint is equivalent to a linear constraint \f$ax - s \leq b\f$ and an SOS1 constraint on
    40 * \f$y\f$ and \f$s\f$ (at most one should be nonzero). In the indicator context we can, however,
    41 * separate more inequalities.
    42 *
    43 * The name indicator apparently comes from CPLEX.
    44 *
    45 *
    46 * @section SEPARATION Separation Methods
    47 *
    48 * We now explain the handling of indicator constraints in more detail. The indicator constraint
    49 * handler adds an inequality for each indicator constraint. We assume that this system (with added
    50 * slack variables) is \f$ Ax - s \leq b \f$, where \f$ x \f$ are the original variables and \f$ s
    51 * \f$ are the slack variables added by the indicator constraint. Variables \f$ y \f$ are the binary
    52 * variables corresponding to the indicator constraints.
    53 *
    54 * @note In the implementation, we assume that bounds on the original variables \f$x\f$ cannot be
    55 * influenced by the indicator constraint. If it should be possible to relax these constraints as
    56 * well, then these constraints have to be added as indicator constraints.
    57 *
    58 * We separate inequalities by using the so-called alternative polyhedron.
    59 *
    60 *
    61 * @section ALTERNATIVEPOLYHEDRON Separation via the Alternative Polyhedron
    62 *
    63 * We now describe the separation method of the first method in more detail.
    64 *
    65 * Consider the LP-relaxation of the current subproblem:
    66 * \f[
    67 * \begin{array}{ll}
    68 * min & c^T x + d^T z\\
    69 * & A x - s \leq b, \\
    70 * & D x + C z \leq f, \\
    71 * & l \leq x \leq u, \\
    72 * & u \leq z \leq v, \\
    73 * & 0 \leq s.
    74 * \end{array}
    75 * \f]
    76 * As above \f$Ax - s \leq b\f$ contains all inequalities corresponding to indicator constraints,
    77 * while the system \f$Dx + Cy \leq f\f$ contains all other inequalities (which are ignored in the
    78 * following). Similarly, variables \f$z\f$ not appearing in indicator constraints are
    79 * ignored. Bounds for the variables \f$x_j\f$ can be given, in particular, variables can be
    80 * fixed. Note that \f$s \leq 0\f$ renders the system infeasible.
    81 *
    82 * To generate cuts, we construct the so-called @a alternative @a polyhedron:
    83 * \f[
    84 * \begin{array}{ll}
    85 * P = \{ (w,r,t) : & A^T w - r + t = 0,\\
    86 * & b^T w - l^T r + u^T t = -1,\\
    87 * & w, r, t \geq 0 \}.
    88 * \end{array}
    89 * \f]
    90 * Here, \f$r\f$ and \f$t\f$ correspond to the lower and upper bounds on \f$x\f$, respectively.
    91 *
    92 * It turns out that the vertices of \f$P\f$ correspond to minimal infeasible subsystems of \f$A x
    93 * \leq b\f$, \f$l \leq x \leq u\f$. If \f$I\f$ is the index set of such a system, it follows that not all \f$s_i\f$ for
    94 * \f$i \in I\f$ can be 0, i.e., \f$y_i\f$ can be 1. In other words, the following cut is valid:
    95 * \f[
    96 * \sum_{i \in I} y_i \leq |I| - 1.
    97 * \f]
    98 *
    99 *
    100 * @subsection DETAIL Separation heuristic
    101 *
    102 * We separate the above inequalities by a heuristic described in
    103 *
    104 * Branch-And-Cut for the Maximum Feasible Subsystem Problem,@n
    105 * Marc Pfetsch, SIAM Journal on Optimization 19, No.1, 21-38 (2008)
    106 *
    107 * The first step in the separation heuristic is to apply the transformation \f$\bar{y} = 1 - y\f$, which
    108 * transforms the above inequality into the constraint
    109 * \f[
    110 * \sum_{i \in I} \bar{y}_i \geq 1,
    111 * \f]
    112 * that is, it is a set covering constraint on the negated variables.
    113 *
    114 * The basic idea is to use the current solution to the LP relaxation and use it as the objective,
    115 * when optimizing of the alternative polyhedron. Since any vertex corresponds to such an
    116 * inequality, we can check whether it is violated. To enlarge the chance that we find a @em
    117 * violated inequality, we perform a fixing procedure, in which the variable corresponding to an
    118 * arbitrary element of the last IIS \f$I\f$ is fixed to zero, i.e., cannot be used in the next
    119 * IISs. This is repeated until the corresponding alternative polyhedron is infeasible, i.e., we
    120 * have obtained an IIS-cover. For more details see the paper above.
    121 *
    122 *
    123 * @subsection PREPROC Preprocessing
    124 *
    125 * Since each indicator constraint adds a linear constraint to the formulation, preprocessing of the
    126 * linear constraints change the above approach as follows.
    127 *
    128 * The system as present in the formulation is the following (ignoring variables that are not
    129 * contained in indicator constraints and the objective function):
    130 * \f[
    131 * \begin{array}{ll}
    132 * & A x - s \leq b, \\
    133 * & l \leq x \leq u, \\
    134 * & s \leq 0.
    135 * \end{array}
    136 * \f]
    137 * Note again that the requirement \f$s \leq 0\f$ leads to an infeasible system. Consider now the
    138 * preprocessing of the linear constraint (aggregation, bound strengthening, etc.) and assume that
    139 * this changes the above system to the following:
    140 * \f[
    141 * \begin{array}{ll}
    142 * & \tilde{A} x - \tilde{B} s \leq \tilde{b}, \\
    143 * & \tilde{l} \leq x \leq \tilde{u}, \\
    144 * & s \leq 0. \\
    145 * \end{array}
    146 * \f]
    147 * Note that we forbid multi-aggregation of the \f$s\f$ variables in order to be able to change their
    148 * bounds in propagation/branching. The corresponding alternative system is the following:
    149 * \f[
    150 * \begin{array}{ll}
    151 * & \tilde{A}^T w - r + t = 0,\\
    152 * & - \tilde{B}^T w + v = 0,\\
    153 * & b^T w - l^T r + u^T t = -1,\\
    154 * & w, v, r, t \geq 0
    155 * \end{array}
    156 * \qquad \Leftrightarrow \qquad
    157 * \begin{array}{ll}
    158 * & \tilde{A}^T w - r + t = 0,\\
    159 * & \tilde{B}^T w \geq 0,\\
    160 * & b^T w - l^T r + u^T t = -1,\\
    161 * & w, r, t \geq 0,
    162 * \end{array}
    163 * \f]
    164 * where the second form arises by substituting \f$v \geq 0\f$. A closer look at this system reveals
    165 * that it is not larger than the original one:
    166 *
    167 * - (Multi-)Aggregation of variables \f$x\f$ will remove these variables from the formulation, such that
    168 * the corresponding column of \f$\tilde{A}\f$ (row of \f$\tilde{A}^T\f$) will be zero.
    169 *
    170 * - The rows of \f$\tilde{B}^T\f$ are not unit vectors, i.e., do not correspond to redundant
    171 * nonnegativity constraints, only if the corresponding slack variables appear in an aggregation.
    172 *
    173 * Taken together, these two observations yield the conclusion that the new system is roughly as
    174 * large as the original one.
    175 *
    176 * @note Because of possible (multi-)aggregation it might happen that the linear constraint
    177 * corresponding to an indicator constraint becomes redundant and is deleted. From this we cannot
    178 * conclude that the indicator constraint is redundant as well (i.e. always fulfilled), because the
    179 * corresponding slack variable is still present and its setting to 0 might influence other
    180 * (linear) constraints. Thus, we have to rely on the dual presolving of the linear constraints to
    181 * detect this case: If the linear constraint is really redundant, i.e., is always fulfilled, it is
    182 * deleted and the slack variable can be fixed to 0. In this case, the indicator constraint can be
    183 * deleted as well.
    184 *
    185 * @todo Accept arbitrary ranged linear constraints as input (in particular: equations). Internally
    186 * create two indicator constraints or correct alternative polyhedron accordingly (need to split the
    187 * variables there, but not in original problem).
    188 *
    189 * @todo Treat variable upper bounds in a special way: Do not create the artificial slack variable,
    190 * but directly enforce the propagations etc.
    191 *
    192 * @todo Turn off separation if the alternative polyhedron is infeasible and updateBounds is false.
    193 *
    194 * @todo Improve parsing of indicator constraint in CIP-format. Currently, we have to rely on a particular name, i.e.,
    195 * the slack variable has to start with "indslack" and end with the name of the corresponding linear constraint.
    196 *
    197 * @todo Check whether one can further use the fact that the slack variable is aggregated.
    198 */
    199
    200/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    201
    202#include "blockmemshell/memory.h"
    203#include "lpi/lpi.h"
    204#include "lpi/type_lpi.h"
    205#include "scip/expr_var.h"
    206#include "scip/expr_product.h"
    207#include "scip/cons_nonlinear.h"
    208#include "scip/cons_indicator.h"
    209#include "scip/cons_linear.h"
    210#include "scip/cons_logicor.h"
    211#include "scip/cons_varbound.h"
    212#include "scip/heur_indicator.h"
    213#include "scip/heur_trysol.h"
    214#include "scip/pub_conflict.h"
    215#include "scip/pub_cons.h"
    216#include "scip/pub_event.h"
    217#include "scip/pub_lp.h"
    218#include "scip/pub_message.h"
    219#include "scip/pub_misc.h"
    220#include "scip/pub_paramset.h"
    221#include "scip/pub_var.h"
    222#include "scip/scip_branch.h"
    223#include "scip/scip_conflict.h"
    224#include "scip/scip_cons.h"
    225#include "scip/scip_copy.h"
    226#include "scip/scip_cut.h"
    227#include "scip/scip_event.h"
    228#include "scip/scip_general.h"
    229#include "scip/scip_heur.h"
    230#include "scip/scip_lp.h"
    231#include "scip/scip_mem.h"
    232#include "scip/scip_message.h"
    233#include "scip/scip_nlp.h"
    234#include "scip/scip_numerics.h"
    235#include "scip/scip_param.h"
    236#include "scip/scip_prob.h"
    237#include "scip/scip_probing.h"
    238#include "scip/scip_sol.h"
    239#include "scip/scip_solve.h"
    241#include "scip/scip_tree.h"
    242#include "scip/scip_var.h"
    243#include "scip/symmetry_graph.h"
    245
    246
    247/* #define SCIP_OUTPUT */
    248/* #define SCIP_ENABLE_IISCHECK */
    249
    250/* constraint handler properties */
    251#define CONSHDLR_NAME "indicator"
    252#define CONSHDLR_DESC "indicator constraint handler"
    253#define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
    254#define CONSHDLR_ENFOPRIORITY -100 /**< priority of the constraint handler for constraint enforcing */
    255#define CONSHDLR_CHECKPRIORITY -6000000 /**< priority of the constraint handler for checking feasibility */
    256#define CONSHDLR_SEPAFREQ 10 /**< frequency for separating cuts; zero means to separate only in the root node */
    257#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
    258#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
    259 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
    260#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
    261#define CONSHDLR_DELAYSEPA FALSE /**< Should separation method be delayed, if other separators found cuts? */
    262#define CONSHDLR_DELAYPROP FALSE /**< Should propagation method be delayed, if other propagators found reductions? */
    263#define CONSHDLR_NEEDSCONS TRUE /**< Should the constraint handler be skipped, if no constraints are available? */
    264
    265#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_FAST
    266#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
    267
    268
    269/* event handler properties */
    270#define EVENTHDLR_BOUND_NAME "indicatorbound"
    271#define EVENTHDLR_BOUND_DESC "bound change event handler for indicator constraints"
    272
    273#define EVENTHDLR_LINCONSBOUND_NAME "indicatorlinconsbound"
    274#define EVENTHDLR_LINCONSBOUND_DESC "bound change event handler for lincons of indicator constraints"
    275
    276#define EVENTHDLR_RESTART_NAME "indicatorrestart"
    277#define EVENTHDLR_RESTART_DESC "force restart if absolute gap is 1 or enough binary variables have been fixed"
    278
    279
    280/* conflict handler properties */
    281#define CONFLICTHDLR_NAME "indicatorconflict"
    282#define CONFLICTHDLR_DESC "replace slack variables and generate logicor constraints"
    283#define CONFLICTHDLR_PRIORITY 200000
    284
    285/* upgrade properties */
    286#define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
    287
    288/* default values for parameters */
    289#define DEFAULT_BRANCHINDICATORS FALSE /**< Branch on indicator constraints in enforcing? */
    290#define DEFAULT_GENLOGICOR FALSE /**< Generate logicor constraints instead of cuts? */
    291#define DEFAULT_ADDCOUPLING TRUE /**< Add coupling constraints or rows if big-M is small enough? */
    292#define DEFAULT_MAXCOUPLINGVALUE 1e4 /**< maximum coefficient for binary variable in coupling constraint */
    293#define DEFAULT_ADDCOUPLINGCONS FALSE /**< Add initial variable upper bound constraints, if 'addcoupling' is true? */
    294#define DEFAULT_SEPACOUPLINGCUTS TRUE /**< Should the coupling inequalities be separated dynamically? */
    295#define DEFAULT_SEPACOUPLINGLOCAL FALSE /**< Allow to use local bounds in order to separate coupling inequalities? */
    296#define DEFAULT_SEPACOUPLINGVALUE 1e4 /**< maximum coefficient for binary variable in separated coupling constraint */
    297#define DEFAULT_SEPAALTERNATIVELP FALSE /**< Separate using the alternative LP? */
    298#define DEFAULT_SEPAPERSPECTIVE FALSE /**< Separate cuts based on perspective formulation? */
    299#define DEFAULT_SEPAPERSPLOCAL TRUE /**< Allow to use local bounds in order to separate perspectice cuts? */
    300#define DEFAULT_MAXSEPANONVIOLATED 3 /**< maximal number of separated non violated IISs, before separation is stopped */
    301#define DEFAULT_TRYSOLFROMCOVER FALSE /**< Try to construct a feasible solution from a cover? */
    302#define DEFAULT_UPGRADELINEAR FALSE /**< Try to upgrade linear constraints to indicator constraints? */
    303#define DEFAULT_USEOTHERCONSS FALSE /**< Collect other constraints to alternative LP? */
    304#define DEFAULT_USEOBJECTIVECUT FALSE /**< Use objective cut with current best solution to alternative LP? */
    305#define DEFAULT_UPDATEBOUNDS FALSE /**< Update bounds of original variables for separation? */
    306#define DEFAULT_MAXCONDITIONALTLP 0.0 /**< max. estimated condition of the solution basis matrix of the alt. LP to be trustworthy (0.0 to disable check) */
    307#define DEFAULT_MAXSEPACUTS 100 /**< maximal number of cuts separated per separation round */
    308#define DEFAULT_MAXSEPACUTSROOT 2000 /**< maximal number of cuts separated per separation round in the root node */
    309#define DEFAULT_REMOVEINDICATORS FALSE /**< Remove indicator constraint if corresponding variable bound constraint has been added? */
    310#define DEFAULT_GENERATEBILINEAR FALSE /**< Do not generate indicator constraint, but a bilinear constraint instead? */
    311#define DEFAULT_SCALESLACKVAR FALSE /**< Scale slack variable coefficient at construction time? */
    312#define DEFAULT_NOLINCONSCONT FALSE /**< Decompose problem (do not generate linear constraint if all variables are continuous)? */
    313#define DEFAULT_TRYSOLUTIONS TRUE /**< Try to make solutions feasible by setting indicator variables? */
    314#define DEFAULT_ENFORCECUTS FALSE /**< In enforcing try to generate cuts (only if sepaalternativelp is true)? */
    315#define DEFAULT_DUALREDUCTIONS TRUE /**< Should dual reduction steps be performed? */
    316#define DEFAULT_ADDOPPOSITE FALSE /**< Add opposite inequality in nodes in which the binary variable has been fixed to 0? */
    317#define DEFAULT_CONFLICTSUPGRADE FALSE /**< Try to upgrade bounddisjunction conflicts by replacing slack variables? */
    318#define DEFAULT_FORCERESTART FALSE /**< Force restart if absolute gap is 1 or enough binary variables have been fixed? */
    319#define DEFAULT_RESTARTFRAC 0.9 /**< fraction of binary variables that need to be fixed before restart occurs (in forcerestart) */
    320#define DEFAULT_USESAMESLACKVAR FALSE /**< Use same slack variable for indicator constraints with common binary variable? */
    321
    322
    323/* other values */
    324#define OBJEPSILON 0.001 /**< value to add to objective in alt. LP if the binary variable is 1 to get small IISs */
    325#define SEPAALTTHRESHOLD 10 /**< only separate IIS cuts if the number of separated coupling cuts is less than this value */
    326#define MAXROUNDINGROUNDS 1 /**< maximal number of rounds that produced cuts in separation */
    327
    328
    329/** constraint data for indicator constraints */
    330struct SCIP_ConsData
    331{
    332 SCIP_VAR* binvar; /**< binary variable for indicator constraint */
    333 SCIP_VAR* slackvar; /**< slack variable of inequality of indicator constraint */
    334 SCIP_CONS* lincons; /**< linear constraint corresponding to indicator constraint */
    335 SCIP_VAR** varswithevents; /**< linear constraint variables with bound change events */
    336 SCIP_EVENTTYPE* eventtypes; /**< eventtypes of linear constraint variables with bound change events */
    337 int nevents; /**< number of bound change events of linear constraint variables */
    338 SCIP_Bool activeone; /**< whether the constraint is active on 1 or 0 (only used at creation time) */
    339 SCIP_Bool lessthanineq; /**< whether the original linear constraint is less-than-rhs or greater-than-rhs (only used at creation time) */
    340 int nfixednonzero; /**< number of variables among binvar and slackvar fixed to be nonzero */
    341 int colindex; /**< column index in alternative LP */
    342 unsigned int linconsactive:1; /**< whether linear constraint and slack variable are active */
    343 unsigned int implicationadded:1; /**< whether corresponding implication has been added */
    344 unsigned int slacktypechecked:1; /**< whether it has been checked to convert the slack variable to be implicit integer */
    345};
    346
    347
    348/** indicator constraint handler data */
    349struct SCIP_ConshdlrData
    350{
    351 SCIP_EVENTHDLR* eventhdlrbound; /**< event handler for bound change events */
    352 SCIP_EVENTHDLR* eventhdlrlinconsbound; /**< event handler for bound change events on linear constraint */
    353 SCIP_EVENTHDLR* eventhdlrrestart; /**< event handler for performing restarts */
    354 SCIP_Bool boundhaschanged; /**< whether a bound of a binvar/slackvar of some indicator constraint has changed */
    355 SCIP_Bool linconsevents; /**< whether bound change events are added to variables of linear constraints */
    356 SCIP_Bool linconsboundschanged; /**< whether bounds of variables of linear constraints changed */
    357 SCIP_Bool removable; /**< whether the separated cuts should be removable */
    358 SCIP_Bool scaled; /**< if first row of alt. LP has been scaled */
    359 SCIP_Bool objindicatoronly; /**< whether the objective is nonzero only for indicator variables */
    360 SCIP_Bool objothervarsonly; /**< whether the objective is nonzero only for non-indicator variables */
    361 SCIP_Real minabsobj; /**< minimum absolute nonzero objective of indicator variables */
    362 SCIP_LPI* altlp; /**< alternative LP for cut separation */
    363 int nrows; /**< # rows in the alt. LP corr. to original variables in linear constraints and slacks */
    364 int nlbbounds; /**< # lower bounds of original variables */
    365 int nubbounds; /**< # upper bounds of original variables */
    366 SCIP_HASHMAP* varhash; /**< hash map from variable to row index in alternative LP */
    367 SCIP_HASHMAP* lbhash; /**< hash map from variable to index of lower bound column in alternative LP */
    368 SCIP_HASHMAP* ubhash; /**< hash map from variable to index of upper bound column in alternative LP */
    369 SCIP_HASHMAP* slackhash; /**< hash map from slack variable to row index in alternative LP */
    370 SCIP_HASHMAP* binvarhash; /**< hash map from binary indicator variable to indicator constraint */
    371 SCIP_HASHMAP* binslackvarhash; /**< hash map from binary indicator variable to slack variables */
    372 int nslackvars; /**< # slack variables */
    373 int niiscutsgen; /**< number of IIS-cuts generated */
    374 int nperspcutsgen; /**< number of cuts based on perspective formulation generated */
    375 int objcutindex; /**< index of objective cut in alternative LP (-1 if not added) */
    376 SCIP_Real objupperbound; /**< best upper bound on objective known */
    377 SCIP_Real objaltlpbound; /**< upper objective bound stored in alternative LP (infinity if not added) */
    378 int maxroundingrounds; /**< maximal number of rounds that produced cuts in separation */
    379 SCIP_Real roundingminthres; /**< minimal value for rounding in separation */
    380 SCIP_Real roundingmaxthres; /**< maximal value for rounding in separation */
    381 SCIP_Real roundingoffset; /**< offset for rounding in separation */
    382 SCIP_Bool branchindicators; /**< Branch on indicator constraints in enforcing? */
    383 SCIP_Bool genlogicor; /**< Generate logicor constraints instead of cuts? */
    384 SCIP_Bool addcoupling; /**< whether the coupling inequalities should be added at the beginning */
    385 SCIP_Bool addcouplingcons; /**< Add initial variable upper bound constraints, if 'addcoupling' is true? */
    386 SCIP_Bool sepacouplingcuts; /**< Should the coupling inequalities be separated dynamically? */
    387 SCIP_Bool sepacouplinglocal; /**< Allow to use local bounds in order to separate coupling inequalities? */
    388 SCIP_Bool sepaperspective; /**< Separate cuts based on perspective formulation? */
    389 SCIP_Bool sepapersplocal; /**< Allow to use local bounds in order to separate perspectice cuts? */
    390 SCIP_Bool removeindicators; /**< Remove indicator constraint if corresponding variable bound constraint has been added? */
    391 SCIP_Bool updatebounds; /**< whether the bounds of the original variables should be changed for separation */
    392 SCIP_Bool trysolutions; /**< Try to make solutions feasible by setting indicator variables? */
    393 SCIP_Bool enforcecuts; /**< in enforcing try to generate cuts (only if sepaalternativelp is true) */
    394 SCIP_Bool dualreductions; /**< Should dual reduction steps be performed? */
    395 SCIP_Bool addopposite; /**< Add opposite inequality in nodes in which the binary variable has been fixed to 0? */
    396 SCIP_Bool generatebilinear; /**< Do not generate indicator constraint, but a bilinear constraint instead? */
    397 SCIP_Bool scaleslackvar; /**< Scale slack variable coefficient at construction time? */
    398 SCIP_Bool conflictsupgrade; /**< Try to upgrade bounddisjunction conflicts by replacing slack variables? */
    399 SCIP_Bool performedrestart; /**< whether a restart has been performed already */
    400 int maxsepacuts; /**< maximal number of cuts separated per separation round */
    401 int maxsepacutsroot; /**< maximal number of cuts separated per separation round in root node */
    402 int maxsepanonviolated; /**< maximal number of separated non violated IISs, before separation is stopped */
    403 int nbinvarszero; /**< binary variables globally fixed to zero */
    404 int ninitconss; /**< initial number of indicator constraints (needed in event handlers) */
    405 SCIP_Real maxcouplingvalue; /**< maximum coefficient for binary variable in initial coupling constraint */
    406 SCIP_Real sepacouplingvalue; /**< maximum coefficient for binary variable in separated coupling constraint */
    407 SCIP_Real maxconditionaltlp; /**< maximum estimated condition number of the alternative LP to trust its solution */
    408 SCIP_Real restartfrac; /**< fraction of binary variables that need to be fixed before restart occurs (in forcerestart) */
    409 SCIP_HEUR* heurtrysol; /**< trysol heuristic */
    410 SCIP_Bool addedcouplingcons; /**< whether the coupling constraints have been added already */
    411 SCIP_CONS** addlincons; /**< additional linear constraints that should be added to the alternative LP */
    412 int naddlincons; /**< number of additional constraints */
    413 int maxaddlincons; /**< maximal number of additional constraints */
    414 SCIP_Bool useotherconss; /**< Collect other constraints to alternative LP? */
    415 SCIP_Bool useobjectivecut; /**< Use objective cut with current best solution to alternative LP? */
    416 SCIP_Bool trysolfromcover; /**< Try to construct a feasible solution from a cover? */
    417 SCIP_Bool upgradelinear; /**< Try to upgrade linear constraints to indicator constraints? */
    418 char normtype; /**< norm type for cut computation */
    419 SCIP_Bool usesameslackvar; /**< Use same slack variable for indicator constraints with common binary variable? */
    420 /* parameters that should not be changed after problem stage: */
    421 SCIP_Bool sepaalternativelp; /**< Separate using the alternative LP? */
    422 SCIP_Bool sepaalternativelp_; /**< used to store the sepaalternativelp parameter */
    423 SCIP_Bool nolinconscont; /**< decompose problem - do not generate linear constraint if all variables are continuous */
    424 SCIP_Bool nolinconscont_; /**< used to store the nolinconscont parameter */
    425 SCIP_Bool forcerestart; /**< Force restart if absolute gap is 1 or enough binary variables have been fixed? */
    426 SCIP_Bool forcerestart_; /**< used to store the forcerestart parameter */
    427};
    428
    429
    430/** indicator conflict handler data */
    431struct SCIP_ConflicthdlrData
    432{
    433 SCIP_CONSHDLR* conshdlr; /**< indicator constraint handler */
    434 SCIP_CONSHDLRDATA* conshdlrdata; /**< indicator constraint handler data */
    435};
    436
    437
    438/** type of enforcing/separation call */
    440{
    441 SCIP_TYPE_ENFOLP = 0, /**< enforce LP */
    442 SCIP_TYPE_ENFOPS = 1, /**< enforce pseudo solution */
    443 SCIP_TYPE_ENFORELAX = 2, /**< enforce relaxation solution */
    444 SCIP_TYPE_SEPALP = 3, /**< separate LP */
    445 SCIP_TYPE_SEPARELAX = 4, /**< separate relaxation solution */
    446 SCIP_TYPE_SEPASOL = 5 /**< separate relaxation solution */
    449
    450
    451/* macro for parameters */
    452#define SCIP_CALL_PARAM(x) /*lint -e527 */ do \
    453{ \
    454 SCIP_RETCODE _restat_; \
    455 if ( (_restat_ = (x)) != SCIP_OKAY && (_restat_ != SCIP_PARAMETERUNKNOWN) ) \
    456 { \
    457 SCIPerrorMessage("[%s:%d] Error <%d> in function call\n", __FILE__, __LINE__, _restat_); \
    458 SCIPABORT(); \
    459 return _restat_; \
    460 } \
    461} \
    462while ( FALSE )
    463
    464
    465/** adds symmetry information of constraint to a symmetry detection graph */
    466static
    468 SCIP* scip, /**< SCIP pointer */
    469 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
    470 SCIP_CONS* cons, /**< constraint */
    471 SYM_GRAPH* graph, /**< symmetry detection graph */
    472 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
    473 )
    474{
    475 SCIP_CONSDATA* consdata;
    476 SCIP_CONS* lincons;
    477 SCIP_VAR** vars;
    478 SCIP_Real* vals;
    479 SCIP_Real constant;
    480 SCIP_Real lhs;
    481 SCIP_Real rhs;
    482 int slacknodeidx;
    483 int consnodeidx;
    484 int eqnodeidx;
    485 int opnodeidx;
    486 int nodeidx;
    487 int nvarslincons;
    488 int nlocvars;
    489
    490 assert(scip != NULL);
    491 assert(cons != NULL);
    492 assert(graph != NULL);
    493 assert(success != NULL);
    494
    495 consdata = SCIPconsGetData(cons);
    496 assert(consdata != NULL);
    497
    498 lincons = consdata->lincons;
    499 assert(lincons != NULL);
    500
    501 /* get information about linear constraint */
    502 lhs = SCIPgetLhsLinear(scip, lincons);
    503 rhs = SCIPgetRhsLinear(scip, lincons);
    504 nvarslincons = SCIPgetNVarsLinear(scip, lincons);
    505
    506 nlocvars = MAX3(1, nvarslincons, SCIPgetNVars(scip)); /*lint !e666*/
    507 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlocvars) );
    508 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlocvars) );
    509 BMScopyMemoryArray(vars, SCIPgetVarsLinear(scip, lincons), nvarslincons);
    510 BMScopyMemoryArray(vals, SCIPgetValsLinear(scip, lincons), nvarslincons);
    511
    512 constant = 0.0;
    513 nlocvars = nvarslincons;
    514 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
    515
    516 /* update lhs/rhs due to possible variable aggregation */
    517 lhs -= constant;
    518 rhs -= constant;
    519
    520 /* create nodes and edges */
    521 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, lhs, rhs, &consnodeidx) );
    522 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &opnodeidx) ); /*lint !e641*/
    523 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, opnodeidx, FALSE, 0.0) );
    524
    525 /* add nodes/edes for variables in linear constraint */
    526 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, opnodeidx, vars, vals, nlocvars, 0.0) );
    527
    528 /* create nodes and edges for activation of constraint */
    529 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_EQ, &eqnodeidx) ); /*lint !e641*/
    530 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, eqnodeidx, FALSE, 0.0) );
    531
    532 /* create nodes and edges for (possibly aggregated) activation variable */
    533 vars[0] = consdata->binvar;
    534 vals[0] = 1.0;
    535 constant = 0.0;
    536 nlocvars = 1;
    537
    538 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
    539
    540 if( nlocvars > 1 || !SCIPisEQ(scip, vals[0], 1.0) || !SCIPisZero(scip, constant) )
    541 {
    542 /* encode aggregation by a sum-expression and connect it to indicator node */
    543 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &opnodeidx) ); /*lint !e641*/
    544 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, eqnodeidx, opnodeidx, TRUE, 1.0) );
    545
    546 /* add nodes and edges for variables in aggregation */
    547 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, opnodeidx, vars, vals, nlocvars, constant) );
    548 }
    549 else if( nlocvars == 1 )
    550 {
    551 if( symtype == SYM_SYMTYPE_SIGNPERM )
    552 {
    553 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
    554 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, eqnodeidx, nodeidx, TRUE, 1.0) );
    555
    556 nodeidx = SCIPgetSymgraphNegatedVarnodeidx(scip, graph, vars[0]);
    557 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, eqnodeidx, nodeidx, TRUE, -1.0) );
    558 }
    559 else
    560 {
    561 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
    562 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, eqnodeidx, nodeidx, TRUE, 1.0) );
    563 }
    564 }
    565
    566 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SLACK, &slacknodeidx) ); /*lint !e641*/
    567 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, slacknodeidx, FALSE, 0.0) );
    568
    569 /* create nodes and edges for (possibly aggregated) slack variable */
    570 vars[0] = consdata->slackvar;
    571 vals[0] = 1.0;
    572 constant = 0.0;
    573 nlocvars = 1;
    574
    575 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
    576
    577 if( nlocvars > 1 || !SCIPisEQ(scip, vals[0], 1.0) || !SCIPisZero(scip, constant) )
    578 {
    579 /* encode aggregation by a sum-expression and connect it to root node */
    580 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &opnodeidx) ); /*lint !e641*/
    581 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, slacknodeidx, opnodeidx, FALSE, 0.0) );
    582
    583 /* add nodes and edges for variables in aggregation */
    584 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, opnodeidx, vars, vals, nlocvars, constant) );
    585 }
    586 else if( nlocvars == 1 )
    587 {
    588 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
    589 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, slacknodeidx, nodeidx, FALSE, 0.0) );
    590 }
    591
    594
    595 *success = TRUE;
    596
    597 return SCIP_OKAY;
    598}
    599
    600
    601/* ---------------- Callback methods of event handlers ---------------- */
    602
    603/** execute the event handler for getting variable bound changes
    604 *
    605 * We update the number of variables fixed to be nonzero.
    606 */
    607static
    608SCIP_DECL_EVENTEXEC(eventExecIndicatorBound)
    609{
    610 SCIP_CONSHDLRDATA* conshdlrdata;
    611 SCIP_EVENTTYPE eventtype;
    612 SCIP_CONSDATA* consdata;
    613 SCIP_CONSHDLR* conshdlr;
    614 SCIP_CONS* cons;
    615 SCIP_Real oldbound;
    616 SCIP_Real newbound;
    617
    618 assert( eventhdlr != NULL );
    619 assert( eventdata != NULL );
    620 assert( event != NULL );
    621
    623
    624 cons = (SCIP_CONS*)eventdata;
    625 assert( cons != NULL );
    626 consdata = SCIPconsGetData(cons);
    627 assert( consdata != NULL );
    628 assert( 0 <= consdata->nfixednonzero && consdata->nfixednonzero <= 2 );
    629 assert( consdata->linconsactive );
    630
    631 conshdlr = SCIPconsGetHdlr(cons);
    632 assert( conshdlr != NULL );
    633 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    634 assert( conshdlrdata != NULL );
    635
    636 oldbound = SCIPeventGetOldbound(event);
    637 newbound = SCIPeventGetNewbound(event);
    638
    639 eventtype = SCIPeventGetType(event);
    640 switch ( eventtype )
    641 {
    643 /* if variable is now fixed to be positive */
    644 if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
    645 {
    646 ++(consdata->nfixednonzero);
    647#ifdef SCIP_MORE_DEBUG
    648 SCIPdebugMsg(scip, "Changed lower bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
    649 SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
    650#endif
    651 }
    652 break;
    653
    655 /* if variable is now fixed to be negative */
    656 if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
    657 {
    658 ++(consdata->nfixednonzero);
    659#ifdef SCIP_MORE_DEBUG
    660 SCIPdebugMsg(scip, "Changed upper bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
    661 SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
    662#endif
    663 }
    664 break;
    665
    667 /* if variable is not fixed to be positive anymore */
    668 if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
    669 {
    670 --(consdata->nfixednonzero);
    671#ifdef SCIP_MORE_DEBUG
    672 SCIPdebugMsg(scip, "Changed lower bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
    673 SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
    674#endif
    675 }
    676 break;
    677
    679 /* if variable is not fixed to be negative anymore */
    680 if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
    681 {
    682 --(consdata->nfixednonzero);
    683#ifdef SCIP_MORE_DEBUG
    684 SCIPdebugMsg(scip, "Changed upper bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
    685 SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
    686#endif
    687 }
    688 break;
    689
    690 default:
    691 SCIPerrorMessage("Invalid event type.\n");
    692 SCIPABORT();
    693 return SCIP_INVALIDDATA; /*lint !e527*/
    694 }
    695 assert( 0 <= consdata->nfixednonzero && consdata->nfixednonzero <= 2 );
    696
    697 /* mark that some variable has changed */
    698 conshdlrdata->boundhaschanged = TRUE;
    699
    700 return SCIP_OKAY;
    701}
    702
    703/** execute the event handler for getting variable bound changes on variables of linear constraint
    704 *
    705 * used for propagation of max activity of lincons to upper bound of slackvar; only important bounds for this purpose are catched
    706 */
    707static
    708SCIP_DECL_EVENTEXEC(eventExecIndicatorLinconsBound)
    709{
    710 SCIP_CONSHDLRDATA* conshdlrdata;
    711
    712 assert( eventhdlr != NULL );
    713 assert( eventdata != NULL );
    714 assert( event != NULL );
    716
    718
    719#ifdef SCIP_MORE_DEBUG
    720 SCIPdebugMsg(scip, "Changed upper bound of variable <%s> from %g to %g.\n",
    722#endif
    723
    724 /* mark that some variable has changed */
    725 conshdlrdata = (SCIP_CONSHDLRDATA*)eventdata;
    726 assert( conshdlrdata != NULL );
    727 conshdlrdata->linconsboundschanged = TRUE;
    728
    729 return SCIP_OKAY;
    730}
    731
    732/** exec the event handler for forcing a restart
    733 *
    734 * There are two cases in which we perform a (user) restart:
    735 * - If we have a max FS instance, i.e., the objective is 1 for indicator variables and 0 otherwise,
    736 * we can force a restart if the gap is 1. In this case, the remaining work consists of proving
    737 * infeasibility of the non-fixed indicators.
    738 * - If a large fraction of the binary indicator variables have been globally fixed, it makes sense
    739 * to force a restart.
    740 */
    741static
    742SCIP_DECL_EVENTEXEC(eventExecIndicatorRestart)
    743{
    744 SCIP_CONSHDLRDATA* conshdlrdata;
    745 SCIP_EVENTTYPE eventtype;
    746
    747 assert( scip != NULL );
    748 assert( eventhdlr != NULL );
    749 assert( eventdata != NULL );
    750 assert( event != NULL );
    751
    753
    754 conshdlrdata = (SCIP_CONSHDLRDATA*)eventdata;
    755 assert( conshdlrdata != NULL );
    756 assert( conshdlrdata->forcerestart );
    757
    758 eventtype = SCIPeventGetType(event);
    759 switch ( eventtype )
    760 {
    763 {
    764#ifndef NDEBUG
    765 SCIP_Real oldbound;
    766 SCIP_Real newbound;
    767
    768 assert( SCIPvarIsBinary(SCIPeventGetVar(event)) );
    769 assert( !SCIPvarIsImpliedIntegral(SCIPeventGetVar(event)) );
    770 oldbound = SCIPeventGetOldbound(event);
    771 newbound = SCIPeventGetNewbound(event);
    772 assert( SCIPisIntegral(scip, oldbound) );
    773 assert( SCIPisIntegral(scip, newbound) );
    774 assert( ! SCIPisEQ(scip, oldbound, newbound) );
    775 assert( SCIPisZero(scip, oldbound) || SCIPisEQ(scip, oldbound, 1.0) );
    776 assert( SCIPisZero(scip, newbound) || SCIPisEQ(scip, newbound, 1.0) );
    777#endif
    778
    779 /* do not treat this case if we have performed a restart already */
    780 if ( conshdlrdata->performedrestart )
    781 return SCIP_OKAY;
    782
    783 /* variable is now fixed */
    784 ++(conshdlrdata->nbinvarszero);
    785 SCIPdebugMsg(scip, "Fixed variable <%s> (nbinvarszero: %d, total: %d).\n",
    786 SCIPvarGetName(SCIPeventGetVar(event)), conshdlrdata->nbinvarszero, conshdlrdata->ninitconss);
    787
    789 break;
    790
    791 /* if enough variables have been fixed */
    792 if ( conshdlrdata->nbinvarszero > (int) ((SCIP_Real) conshdlrdata->ninitconss * conshdlrdata->restartfrac) )
    793 {
    795 "Forcing restart, since %d binary variables among %d have been fixed.\n", conshdlrdata->nbinvarszero, conshdlrdata->ninitconss);
    797
    798 /* drop event */
    799 if ( conshdlrdata->objindicatoronly )
    800 {
    801 SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, eventhdlr, (SCIP_EVENTDATA*) conshdlrdata, -1) );
    802 }
    803 conshdlrdata->performedrestart = TRUE;
    804 }
    805 break;
    806 }
    807
    809 assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
    810 assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0 ) );
    811
    813 break;
    814
    815 if ( ! conshdlrdata->objindicatoronly )
    816 break;
    817
    818 /* if the absolute gap is equal to minabsobj */
    819 if ( SCIPisEQ(scip, REALABS(SCIPgetPrimalbound(scip) - SCIPgetDualbound(scip)), conshdlrdata->minabsobj) )
    820 {
    821 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Forcing restart, since the absolute gap is %f.\n", conshdlrdata->minabsobj);
    823
    824 /* use inference branching, since the objective is not meaningful */
    825 if ( SCIPfindBranchrule(scip, "inference") != NULL && !SCIPisParamFixed(scip, "branching/inference/priority") )
    826 {
    827 SCIP_CALL( SCIPsetIntParam(scip, "branching/inference/priority", INT_MAX/4) );
    828 }
    829
    830 /* drop event */
    831 SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, eventhdlr, (SCIP_EVENTDATA*) conshdlrdata, -1) );
    832 conshdlrdata->performedrestart = TRUE;
    833 }
    834 break;
    835
    836 default:
    837 SCIPerrorMessage("invalid event type.\n");
    838 SCIPABORT();
    839 return SCIP_INVALIDDATA; /*lint !e527*/
    840 }
    841
    842 return SCIP_OKAY;
    843}
    844
    845
    846/* ------------------------ conflict handler ---------------------------------*/
    847
    848/** destructor of conflict handler to free conflict handler data (called when SCIP is exiting) */
    849static
    850SCIP_DECL_CONFLICTFREE(conflictFreeIndicator)
    851{
    852 SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
    853
    854 assert( scip != NULL );
    855 assert( conflicthdlr != NULL );
    856
    858
    859 conflicthdlrdata = SCIPconflicthdlrGetData(conflicthdlr);
    860 SCIPfreeBlockMemory(scip, &conflicthdlrdata);
    861
    862 return SCIP_OKAY;
    863}
    864
    865
    866/** conflict processing method of conflict handler (called when conflict was found)
    867 *
    868 * In this conflict handler we try to replace slack variables by binary indicator variables and
    869 * generate a logicor constraint if possible.
    870 *
    871 * @todo Extend to integral case.
    872 */
    873static
    874SCIP_DECL_CONFLICTEXEC(conflictExecIndicator)
    875{ /*lint --e{715}*/
    876 SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
    877 SCIP_Bool haveslack;
    878 SCIP_VAR* var;
    879 int i;
    880
    881 assert( conflicthdlr != NULL );
    882 assert( bdchginfos != NULL || nbdchginfos == 0 );
    883 assert( result != NULL );
    884
    886
    887 /* don't process already resolved conflicts */
    888 if ( resolved )
    889 {
    890 *result = SCIP_DIDNOTRUN;
    891 return SCIP_OKAY;
    892 }
    893
    894 SCIPdebugMsg(scip, "Indicator conflict handler.\n");
    895
    896 conflicthdlrdata = SCIPconflicthdlrGetData(conflicthdlr);
    897 assert( conflicthdlrdata != NULL );
    898
    899 /* possibly skip conflict handler */
    900 if ( ! ((SCIP_CONFLICTHDLRDATA*) conflicthdlrdata)->conshdlrdata->conflictsupgrade )
    901 return SCIP_OKAY;
    902
    903 *result = SCIP_DIDNOTFIND;
    904
    905 /* check whether there seems to be one slack variable and all other variables are binary */
    906 haveslack = FALSE;
    907 for (i = 0; i < nbdchginfos; ++i)
    908 {
    909 assert( bdchginfos != NULL ); /* for flexelint */
    910 assert( bdchginfos[i] != NULL );
    911
    912 var = SCIPbdchginfoGetVar(bdchginfos[i]);
    913
    914 /* check string for slack variable */
    915 if ( strstr(SCIPvarGetName(var), "indslack") != NULL )
    916 {
    917 /* make sure that the slack variable occurs with its lower bound */
    919 break;
    920
    921 /* make sure that the lower bound is 0 */
    922 if ( ! SCIPisFeasZero(scip, SCIPbdchginfoGetNewbound(bdchginfos[i])) )
    923 break;
    924
    925 haveslack = TRUE;
    926 continue;
    927 }
    928
    929 /* we only treat binary variables (other than slack variables) */
    930 if ( ! SCIPvarIsBinary(var) )
    931 break;
    932 }
    933
    934 /* if we have found at least one slack variable and all other variables are binary */
    935 if ( haveslack && i == nbdchginfos )
    936 {
    937 SCIP_CONS** conss;
    938 SCIP_VAR** vars;
    939 int nconss;
    940 int j;
    941
    942 SCIPdebugMsg(scip, "Found conflict involving slack variables that can be remodelled.\n");
    943
    944 assert( conflicthdlrdata->conshdlr != NULL );
    945
    946 SCIP_STRINGEQ( SCIPconshdlrGetName(conflicthdlrdata->conshdlr), CONSHDLR_NAME, SCIP_INVALIDCALL );
    947
    948 nconss = SCIPconshdlrGetNConss(conflicthdlrdata->conshdlr);
    949 conss = SCIPconshdlrGetConss(conflicthdlrdata->conshdlr);
    950
    951 /* create array of variables in conflict constraint */
    952 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nbdchginfos) );
    953 for (i = 0; i < nbdchginfos; ++i)
    954 {
    955 assert( bdchginfos != NULL ); /* for flexelint */
    956 assert( bdchginfos[i] != NULL );
    957
    958 var = SCIPbdchginfoGetVar(bdchginfos[i]);
    959
    960 SCIPdebugMsg(scip, " <%s> %s %g\n", SCIPvarGetName(var), SCIPbdchginfoGetBoundtype(bdchginfos[i]) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
    961 SCIPbdchginfoGetNewbound(bdchginfos[i]));
    962
    963 /* check string for slack variable */
    964 if ( strstr(SCIPvarGetName(var), "indslack") != NULL )
    965 {
    966 SCIP_VAR* slackvar;
    967
    968 /* search for slack variable */
    969 for (j = 0; j < nconss; ++j)
    970 {
    971 assert( conss[j] != NULL );
    972 slackvar = SCIPgetSlackVarIndicator(conss[j]);
    973 assert( slackvar != NULL );
    974
    975 /* check whether we found the variable */
    976 if ( slackvar == var )
    977 {
    978 /* replace slack variable by binary variable */
    979 var = SCIPgetBinaryVarIndicator(conss[j]);
    980 break;
    981 }
    982 }
    983
    984 /* check whether we found the slack variable */
    985 if ( j >= nconss )
    986 {
    987 SCIPdebugMsg(scip, "Could not find slack variable <%s>.\n", SCIPvarGetName(var));
    988 break;
    989 }
    990 }
    991 else
    992 {
    993 /* if the variable is fixed to one in the conflict set, we have to use its negation */
    994 if ( SCIPbdchginfoGetNewbound(bdchginfos[i]) > 0.5 )
    995 {
    996 SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
    997 }
    998 }
    999
    1000 vars[i] = var;
    1001 }
    1002
    1003 /* whether all slack variables have been found */
    1004 if ( i == nbdchginfos )
    1005 {
    1006 SCIP_CONS* cons;
    1007 char consname[SCIP_MAXSTRLEN];
    1008
    1009 SCIPdebugMsg(scip, "Generated logicor conflict constraint.\n");
    1010
    1011 /* create a logicor constraint out of the conflict set */
    1013 SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, consname, nbdchginfos, vars,
    1014 FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) );
    1015
    1016#ifdef SCIP_OUTPUT
    1017 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
    1018 SCIPinfoMessage(scip, NULL, ";\n");
    1019#endif
    1020
    1021 /* add constraint to SCIP */
    1022 SCIP_CALL( SCIPaddConflict(scip, node, &cons, validnode, conftype, cutoffinvolved) );
    1023
    1024 *result = SCIP_CONSADDED;
    1025 }
    1026
    1027 /* free temporary memory */
    1028 SCIPfreeBufferArray(scip, &vars);
    1029 }
    1030
    1031 return SCIP_OKAY;
    1032}
    1033
    1034
    1035/* ------------------------ parameter handling ---------------------------------*/
    1036
    1037/** check whether we transfer a changed parameter to the given value
    1038 *
    1039 * @see paramChangedIndicator()
    1040 */
    1041static
    1043 SCIP* scip, /**< SCIP data structure */
    1044 SCIP_PARAM* param, /**< parameter */
    1045 const char* name, /**< parameter name to check */
    1046 SCIP_Bool newvalue, /**< new value */
    1047 SCIP_Bool* value /**< old and possibly changed value of parameter */
    1048 )
    1049{
    1050 const char* paramname;
    1051
    1052 assert( scip != NULL );
    1053 assert( param != NULL );
    1054 assert( name != NULL );
    1055 assert( value != NULL );
    1056
    1057 if ( SCIPparamGetType(param) != SCIP_PARAMTYPE_BOOL )
    1058 return SCIP_OKAY;
    1059
    1060 if ( *value == newvalue )
    1061 return SCIP_OKAY;
    1062
    1063 paramname = SCIPparamGetName(param);
    1064 assert( paramname != NULL );
    1065
    1066 /* check whether the change parameter corresponds to our name to check */
    1067 if ( strcmp(paramname, name) == 0 )
    1068 {
    1069 /* check stage and possibly ignore parameter change */
    1071 {
    1072 SCIPwarningMessage(scip, "Cannot change parameter <%s> stage %d - reset to old value %s.\n", name, SCIPgetStage(scip), *value ? "true" : "false");
    1073 /* Note that the following command will create a recursive call, but then *value == newvalue above. */
    1074 SCIP_CALL( SCIPchgBoolParam(scip, param, *value) );
    1075 }
    1076 else
    1077 {
    1078 /* otherwise copy value */
    1079 *value = newvalue;
    1080 }
    1081 }
    1082
    1083 return SCIP_OKAY;
    1084}
    1085
    1086
    1087/** called after a parameter has been changed */
    1088static
    1089SCIP_DECL_PARAMCHGD(paramChangedIndicator)
    1090{
    1091 SCIP_CONSHDLR* conshdlr;
    1092 SCIP_CONSHDLRDATA* conshdlrdata;
    1093
    1094 assert( scip != NULL );
    1095 assert( param != NULL );
    1096
    1097 /* get indicator constraint handler */
    1098 conshdlr = SCIPfindConshdlr(scip, "indicator");
    1099 assert( conshdlr != NULL );
    1100
    1101 /* get constraint handler data */
    1102 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    1103 assert( conshdlrdata != NULL );
    1104
    1105 SCIP_CALL( checkTransferBoolParam(scip, param, "constraints/indicator/sepaalternativelp", conshdlrdata->sepaalternativelp_, &conshdlrdata->sepaalternativelp) );
    1106 SCIP_CALL( checkTransferBoolParam(scip, param, "constraints/indicator/forcerestart", conshdlrdata->forcerestart_, &conshdlrdata->forcerestart) );
    1107 SCIP_CALL( checkTransferBoolParam(scip, param, "constraints/indicator/nolinconscont", conshdlrdata->nolinconscont_, &conshdlrdata->nolinconscont) );
    1108
    1109 return SCIP_OKAY;
    1110}
    1111
    1112
    1113/* ------------------------ debugging routines ---------------------------------*/
    1114
    1115#ifdef SCIP_ENABLE_IISCHECK
    1116/** Check that indicator constraints corresponding to nonnegative entries in @a vector are infeasible in original problem
    1117 *
    1118 * @note This function will probably fail if the has been presolved by the cons_linear presolver. To make it complete
    1119 * we would have to substitute active variables.
    1120 */
    1121static
    1122SCIP_RETCODE checkIIS(
    1123 SCIP* scip, /**< SCIP pointer */
    1124 int nconss, /**< number of constraints */
    1125 SCIP_CONS** conss, /**< indicator constraints */
    1126 SCIP_Real* vector /**< vector */
    1127 )
    1128{
    1129 SCIP_CONSHDLRDATA* conshdlrdata;
    1130 SCIP_CONSHDLR* conshdlr;
    1131 SCIP_HASHMAP* varhash; /* hash map from variable to column index in auxiliary LP */
    1132 SCIP_LPI* lp;
    1133 int nvars = 0;
    1134 int c;
    1135
    1136 assert( scip != NULL );
    1137 assert( vector != NULL );
    1138
    1139 SCIPdebugMsg(scip, "Checking IIS ...\n");
    1140
    1141 /* now check indicator constraints */
    1142 conshdlr = SCIPfindConshdlr(scip, "indicator");
    1143 assert( conshdlr != NULL );
    1144
    1145 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    1146 assert( conshdlrdata != NULL );
    1147
    1148 conss = SCIPconshdlrGetConss(conshdlr);
    1149 nconss = SCIPconshdlrGetNConss(conshdlr);
    1150
    1151 /* create LP */
    1153
    1154 /* set up hash map */
    1156
    1157 /* loop through indicator constraints */
    1158 for (c = 0; c < nconss; ++c)
    1159 {
    1160 SCIP_CONSDATA* consdata;
    1161 consdata = SCIPconsGetData(conss[c]);
    1162 assert( consdata != NULL );
    1163
    1164 /* check whether constraint should be included */
    1165 if ( consdata->colindex >= 0 && (! SCIPisFeasZero(scip, vector[consdata->colindex]) || ! SCIPconsIsEnabled(conss[c])) )
    1166 {
    1167 SCIP_CONS* lincons;
    1168 SCIP_VAR** linvars;
    1169 SCIP_Real* linvals;
    1170 SCIP_Real linrhs;
    1171 SCIP_Real linlhs;
    1172 SCIP_VAR* slackvar;
    1173 int nlinvars;
    1174 SCIP_Real sign = 1.0;
    1175 int matbeg;
    1176 int* matind;
    1177 SCIP_Real* matval;
    1178 SCIP_VAR** newvars;
    1179 int nnewvars;
    1180 SCIP_Real lhs;
    1181 SCIP_Real rhs;
    1182 int cnt;
    1183 int v;
    1184
    1185 lincons = consdata->lincons;
    1186 assert( lincons != NULL );
    1187 assert( ! SCIPconsIsEnabled(conss[c]) || SCIPconsIsActive(lincons) );
    1188 assert( ! SCIPconsIsEnabled(conss[c]) || SCIPconsIsEnabled(lincons) );
    1189
    1190 slackvar = consdata->slackvar;
    1191 assert( slackvar != NULL );
    1192
    1193 /* if the slack variable is aggregated (multi-aggregation should not happen) */
    1194 assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
    1196 {
    1197 SCIP_VAR* var;
    1198 SCIP_Real scalar = 1.0;
    1199 SCIP_Real constant = 0.0;
    1200
    1201 var = slackvar;
    1202
    1203 SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
    1204 assert( ! SCIPisZero(scip, scalar) );
    1205
    1206 /* SCIPdebugMsg(scip, "slack variable aggregated (scalar: %f, constant: %f)\n", scalar, constant); */
    1207
    1208 /* otherwise construct a linear constraint */
    1209 SCIP_CALL( SCIPallocBufferArray(scip, &linvars, 1) );
    1210 SCIP_CALL( SCIPallocBufferArray(scip, &linvals, 1) );
    1211 linvars[0] = var;
    1212 linvals[0] = scalar;
    1213 nlinvars = 1;
    1214 linlhs = -SCIPinfinity(scip);
    1215 linrhs = constant;
    1216 }
    1217 else
    1218 {
    1219 /* in this case, the linear constraint is directly usable */
    1220 linvars = SCIPgetVarsLinear(scip, lincons);
    1221 linvals = SCIPgetValsLinear(scip, lincons);
    1222 nlinvars = SCIPgetNVarsLinear(scip, lincons);
    1223 linlhs = SCIPgetLhsLinear(scip, lincons);
    1224 linrhs = SCIPgetRhsLinear(scip, lincons);
    1225 }
    1226
    1227 /* adapt rhs of linear constraint */
    1228 assert( SCIPisInfinity(scip, -linlhs) || SCIPisInfinity(scip, linrhs) );
    1229 if ( SCIPisInfinity(scip, linrhs) )
    1230 {
    1231 linrhs = -linlhs;
    1232 assert( linrhs > -SCIPinfinity(scip) );
    1233 sign = -1.0;
    1234 }
    1235
    1236 SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4*nlinvars) );
    1237 SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4*nlinvars) );
    1238 SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nlinvars) );
    1239
    1240 /* set up row */
    1241 nnewvars = 0;
    1242 for (v = 0; v < nlinvars; ++v)
    1243 {
    1244 SCIP_VAR* var;
    1245 var = linvars[v];
    1246 assert( var != NULL );
    1247
    1248 /* skip slack variable */
    1249 if ( var == slackvar )
    1250 continue;
    1251
    1252 /* if variable is new */
    1253 if ( ! SCIPhashmapExists(varhash, var) )
    1254 {
    1255 /* add variable in map */
    1256 SCIP_CALL( SCIPhashmapInsertInt(varhash, var, nvars) );
    1257 assert( nvars == SCIPhashmapGetImageInt(varhash, var) );
    1258 /* SCIPdebugMsg(scip, "Inserted variable <%s> into hashmap (%d).\n", SCIPvarGetName(var), nvars); */
    1259 nvars++;
    1260
    1261 /* store new variables */
    1262 newvars[nnewvars++] = var;
    1263 }
    1264 assert( SCIPhashmapExists(varhash, var) );
    1265 }
    1266
    1267 /* add new columns */
    1268 if ( nnewvars > 0 )
    1269 {
    1270 SCIP_Real* lb;
    1271 SCIP_Real* ub;
    1272 SCIP_Real* obj;
    1273 char** colnames;
    1274
    1275 SCIP_CALL( SCIPallocBufferArray(scip, &lb, nnewvars) );
    1276 SCIP_CALL( SCIPallocBufferArray(scip, &ub, nnewvars) );
    1277 SCIP_CALL( SCIPallocBufferArray(scip, &obj, nnewvars) );
    1278 SCIP_CALL( SCIPallocBufferArray(scip, &colnames, nnewvars) );
    1279
    1280 for (v = 0; v < nnewvars; ++v)
    1281 {
    1282 SCIP_VAR* var;
    1283 var = newvars[v];
    1284 obj[v] = 0.0;
    1285 lb[v] = SCIPvarGetLbLocal(var);
    1286 ub[v] = SCIPvarGetUbLocal(var);
    1287 SCIP_CALL( SCIPallocBufferArray(scip, &(colnames[v]), SCIP_MAXSTRLEN) ); /*lint !e866*/
    1288 (void) SCIPsnprintf(colnames[v], SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var));
    1289 }
    1290
    1291 /* now add columns */
    1292 SCIP_CALL( SCIPlpiAddCols(lp, nnewvars, obj, lb, ub, colnames, 0, NULL, NULL, NULL) );
    1293
    1294 for (v = nnewvars - 1; v >= 0; --v)
    1295 {
    1296 SCIPfreeBufferArray(scip, &(colnames[v]));
    1297 }
    1298 SCIPfreeBufferArray(scip, &colnames);
    1302 }
    1303
    1304 /* set up row */
    1305 cnt = 0;
    1306 for (v = 0; v < nlinvars; ++v)
    1307 {
    1308 SCIP_VAR* var;
    1309 var = linvars[v];
    1310 assert( var != NULL );
    1311
    1312 /* skip slack variable */
    1313 if ( var == slackvar )
    1314 continue;
    1315
    1316 assert( SCIPhashmapExists(varhash, var) );
    1317 matind[cnt] = SCIPhashmapGetImageInt(varhash, var);
    1318 matval[cnt] = sign * linvals[v];
    1319 ++cnt;
    1320 }
    1321
    1322 lhs = -SCIPlpiInfinity(lp);
    1323 rhs = linrhs;
    1324
    1325 /* add new row */
    1326 matbeg = 0;
    1327 SCIP_CALL( SCIPlpiAddRows(lp, 1, &lhs, &rhs, NULL, cnt, &matbeg, matind, matval) );
    1328
    1329 SCIPfreeBufferArray(scip, &matind);
    1330 SCIPfreeBufferArray(scip, &matval);
    1331 SCIPfreeBufferArray(scip, &newvars);
    1332
    1333 assert( slackvar != NULL );
    1335 {
    1336 SCIPfreeBufferArray(scip, &linvals);
    1337 SCIPfreeBufferArray(scip, &linvars);
    1338 }
    1339 }
    1340 }
    1341
    1342 /* possibly handle additional linear constraints */
    1343 if ( conshdlrdata->useotherconss )
    1344 {
    1345 /* get all linear constraints */
    1346 conss = SCIPgetConss(scip);
    1347 nconss = SCIPgetNConss(scip);
    1348
    1349 /* loop through constraints */
    1350 for (c = 0; c < nconss; ++c)
    1351 {
    1352 SCIP_CONS* cons;
    1353 SCIP_VAR** linvars;
    1354 SCIP_Real* linvals;
    1355 SCIP_Real linrhs;
    1356 SCIP_Real linlhs;
    1357 SCIP_Real* matval;
    1358 SCIP_VAR** newvars;
    1359 int nnewvars = 0;
    1360 int* matind;
    1361 int nlinvars;
    1362 int matbeg = 0;
    1363 int cnt = 0;
    1364 int v;
    1365
    1366 cons = conss[c];
    1367 assert( cons != NULL );
    1368
    1369 /* avoid non-active, local constraints */
    1370 if ( ! SCIPconsIsEnabled(cons) || ! SCIPconsIsActive(cons) || SCIPconsIsLocal(cons) )
    1371 continue;
    1372
    1373 /* check type of constraint (only take linear constraints) */
    1374 if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") != 0 )
    1375 continue;
    1376
    1377 /* avoid adding linear constraints that correspond to indicator constraints */
    1378 if ( strncmp(SCIPconsGetName(cons), "indlin", 6) == 0 )
    1379 continue;
    1380
    1381 /* get data of linear constraint */
    1382 linvars = SCIPgetVarsLinear(scip, cons);
    1383 linvals = SCIPgetValsLinear(scip, cons);
    1384 nlinvars = SCIPgetNVarsLinear(scip, cons);
    1385 linlhs = SCIPgetLhsLinear(scip, cons);
    1386 linrhs = SCIPgetRhsLinear(scip, cons);
    1387
    1388 /* reserve space */
    1389 SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4*nlinvars) );
    1390 SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4*nlinvars) );
    1391 SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nlinvars) );
    1392
    1393 /* collect possibly new variables */
    1394 for (v = 0; v < nlinvars; ++v)
    1395 {
    1396 SCIP_VAR* var;
    1397 var = linvars[v];
    1398 assert( var != NULL );
    1399
    1400 /* if variable is new */
    1401 if ( ! SCIPhashmapExists(varhash, var) )
    1402 {
    1403 /* add variable in map */
    1404 SCIP_CALL( SCIPhashmapInsertInt(varhash, var, nvars) );
    1405 assert( nvars == SCIPhashmapGetImageInt(varhash, var) );
    1406 /* SCIPdebugMsg(scip, "Inserted variable <%s> into hashmap (%d).\n", SCIPvarGetName(var), nvars); */
    1407 nvars++;
    1408
    1409 /* store new variables */
    1410 newvars[nnewvars++] = var;
    1411 }
    1412 assert( SCIPhashmapExists(varhash, var) );
    1413 }
    1414
    1415 /* add new columns */
    1416 if ( nnewvars > 0 )
    1417 {
    1418 SCIP_Real* lb;
    1419 SCIP_Real* ub;
    1420 SCIP_Real* obj;
    1421 char** colnames;
    1422
    1423 SCIP_CALL( SCIPallocBufferArray(scip, &lb, nnewvars) );
    1424 SCIP_CALL( SCIPallocBufferArray(scip, &ub, nnewvars) );
    1425 SCIP_CALL( SCIPallocBufferArray(scip, &obj, nnewvars) );
    1426 SCIP_CALL( SCIPallocBufferArray(scip, &colnames, nnewvars) );
    1427
    1428 for (v = 0; v < nnewvars; ++v)
    1429 {
    1430 SCIP_VAR* var;
    1431 var = newvars[v];
    1432 obj[v] = 0.0;
    1433 lb[v] = SCIPvarGetLbLocal(var);
    1434 ub[v] = SCIPvarGetUbLocal(var);
    1435 SCIP_CALL( SCIPallocBufferArray(scip, &(colnames[v]), SCIP_MAXSTRLEN) ); /*lint !e866*/
    1436 (void) SCIPsnprintf(colnames[v], SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var));
    1437 }
    1438
    1439 /* now add columns */
    1440 SCIP_CALL( SCIPlpiAddCols(lp, nnewvars, obj, lb, ub, colnames, 0, NULL, NULL, NULL) );
    1441
    1442 for (v = nnewvars - 1; v >= 0; --v)
    1443 {
    1444 SCIPfreeBufferArray(scip, &(colnames[v]));
    1445 }
    1446 SCIPfreeBufferArray(scip, &colnames);
    1450 }
    1451
    1452 /* set up row */
    1453 for (v = 0; v < nlinvars; ++v)
    1454 {
    1455 SCIP_VAR* var;
    1456 var = linvars[v];
    1457 assert( var != NULL );
    1458
    1459 assert( SCIPhashmapExists(varhash, var) );
    1460 matind[cnt] = SCIPhashmapGetImageInt(varhash, var);
    1461 matval[cnt] = linvals[v];
    1462 ++cnt;
    1463 }
    1464
    1465 /* add new row */
    1466 SCIP_CALL( SCIPlpiAddRows(lp, 1, &linlhs, &linrhs, NULL, cnt, &matbeg, matind, matval) );
    1467
    1468 SCIPfreeBufferArray(scip, &matind);
    1469 SCIPfreeBufferArray(scip, &matval);
    1470 SCIPfreeBufferArray(scip, &newvars);
    1471 }
    1472 }
    1473
    1474 /* solve LP and check status */
    1476
    1477 if ( ! SCIPlpiIsPrimalInfeasible(lp) )
    1478 {
    1479 SCIPerrorMessage("Detected IIS is not infeasible in original problem!\n");
    1480
    1481 SCIP_CALL( SCIPlpiWriteLP(lp, "check.lp") );
    1482 SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "altdebug.lp") );
    1483 SCIPABORT();
    1484 return SCIP_ERROR; /*lint !e527*/
    1485 }
    1486 SCIPdebugMsg(scip, "Check successful!\n");
    1487
    1488 SCIPhashmapFree(&varhash);
    1489 SCIP_CALL( SCIPlpiFree(&lp) );
    1490
    1491 return SCIP_OKAY;
    1492}
    1493#endif
    1494
    1495
    1496/* ------------------------ auxiliary operations -------------------------------*/
    1497
    1498/** return objective contribution of variable
    1499 *
    1500 * Special treatment of negated variables: return negative of objective of original
    1501 * variable. SCIPvarGetObj() would return 0 in these cases.
    1502 */
    1503static
    1505 SCIP_VAR* var /**< variable */
    1506 )
    1507{
    1508 if ( SCIPvarIsBinary(var) && SCIPvarIsNegated(var) )
    1509 {
    1510 assert( SCIPvarGetNegatedVar(var) != NULL );
    1511 return -SCIPvarGetObj(SCIPvarGetNegatedVar(var));
    1512 }
    1514 {
    1515 assert( SCIPvarGetAggrVar(var) != NULL );
    1517 }
    1518
    1519 return SCIPvarGetObj(var);
    1520}
    1521
    1522
    1523/** ensures that the addlincons array can store at least num entries */
    1524static
    1526 SCIP* scip, /**< SCIP data structure */
    1527 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    1528 int num /**< minimum number of entries to store */
    1529 )
    1530{
    1531 SCIP_CONSHDLRDATA* conshdlrdata;
    1532
    1533 assert( scip != NULL );
    1534 assert( conshdlr != NULL );
    1535
    1537
    1538 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    1539 assert( conshdlrdata != NULL );
    1540 assert( conshdlrdata->naddlincons <= conshdlrdata->maxaddlincons );
    1541
    1542 if ( num > conshdlrdata->maxaddlincons )
    1543 {
    1544 int newsize;
    1545
    1546 newsize = SCIPcalcMemGrowSize(scip, num);
    1547 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons, newsize) );
    1548 conshdlrdata->maxaddlincons = newsize;
    1549 }
    1550 assert( num <= conshdlrdata->maxaddlincons );
    1551
    1552 return SCIP_OKAY;
    1553}
    1554
    1555
    1556/* ------------------------ operations on the alternative LP -------------------*/
    1557
    1558/** initialize alternative LP
    1559 *
    1560 * The alternative system is organized as follows:
    1561 * - The first row corresponds to the right hand side of the original system.
    1562 * - The next nconss constraints correspond to the slack variables.
    1563 * - The rows after that correspond to the original variables.
    1564 */
    1565static
    1567 SCIP* scip, /**< SCIP pointer */
    1568 SCIP_CONSHDLR* conshdlr /**< constraint handler */
    1569 )
    1570{
    1571 SCIP_CONSHDLRDATA* conshdlrdata;
    1572 SCIP_Real lhs = -1.0;
    1573 SCIP_Real rhs = -1.0;
    1574
    1575 assert( scip != NULL );
    1576
    1578
    1579 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    1580 assert( conshdlrdata != NULL );
    1581 assert( conshdlrdata->altlp == NULL );
    1582 assert( conshdlrdata->varhash == NULL );
    1583 assert( conshdlrdata->lbhash == NULL );
    1584 assert( conshdlrdata->ubhash == NULL );
    1585 assert( conshdlrdata->slackhash != NULL );
    1586
    1587 /* create hash map of variables */
    1588 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
    1589 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->lbhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
    1590 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->ubhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
    1591
    1592 /* create alternative LP */
    1593 SCIP_CALL( SCIPlpiCreate(&conshdlrdata->altlp, SCIPgetMessagehdlr(scip), "altlp", SCIP_OBJSEN_MINIMIZE) );
    1594
    1595 /* add first row */
    1596 SCIP_CALL( SCIPlpiAddRows(conshdlrdata->altlp, 1, &lhs, &rhs, NULL, 0, NULL, NULL, NULL) );
    1597 conshdlrdata->nrows = 1;
    1598
    1599 /* set parameters */
    1602 SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_SCALING, 1) );
    1603 SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_FASTMIP, FALSE) );
    1604
    1605 SCIPdebugMsg(scip, "Initialized alternative LP.\n");
    1606
    1607 /* uncomment the following for debugging */
    1608 /* SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_LPINFO, TRUE) ); */
    1609
    1610 return SCIP_OKAY;
    1611}
    1612
    1613
    1614/** check whether the bounds in given (alternative) LP are set correctly (for debugging) */
    1615#ifndef NDEBUG
    1616static
    1618 SCIP* scip, /**< SCIP pointer */
    1619 SCIP_LPI* lp, /**< LP for which bounds should be checked */
    1620 int nconss, /**< number of constraints */
    1621 SCIP_CONS** conss /**< constraints */
    1622 )
    1623{
    1624 SCIP_Real* lb;
    1625 SCIP_Real* ub;
    1626 SCIP_Bool* covered;
    1627 int nCols;
    1628 int j;
    1629
    1630 assert( scip != NULL );
    1631 assert( lp != NULL );
    1632
    1633 SCIP_CALL( SCIPlpiGetNCols(lp, &nCols) );
    1634
    1635 SCIP_CALL( SCIPallocBufferArray(scip, &lb, nCols) );
    1636 SCIP_CALL( SCIPallocBufferArray(scip, &ub, nCols) );
    1637 SCIP_CALL( SCIPallocBufferArray(scip, &covered, nCols) );
    1638
    1639 for (j = 0; j < nCols; ++j)
    1640 covered[j] = FALSE;
    1641
    1642 /* check columns used by constraints */
    1643 SCIP_CALL( SCIPlpiGetBounds(lp, 0, nCols-1, lb, ub) );
    1644 for (j = 0; j < nconss; ++j)
    1645 {
    1646 SCIP_CONSDATA* consdata;
    1647 int ind;
    1648
    1649 assert( conss[j] != NULL );
    1650 consdata = SCIPconsGetData(conss[j]);
    1651 assert( consdata != NULL );
    1652 ind = consdata->colindex;
    1653
    1654 if ( ind >= 0 )
    1655 {
    1656 assert( ind < nCols );
    1657 covered[ind] = TRUE;
    1658 if ( ! SCIPisFeasZero(scip, lb[ind]) || ! SCIPlpiIsInfinity(lp, ub[ind]) )
    1659 {
    1660 SCIPABORT();
    1661 }
    1662 }
    1663 }
    1664
    1665 /* check other columns */
    1666 for (j = 0; j < nCols; ++j)
    1667 {
    1668 if (! covered[j] )
    1669 {
    1670 /* some columns can be fixed to 0, since they correspond to disabled constraints */
    1671 if ( ( ! SCIPlpiIsInfinity(lp, -lb[j]) && ! SCIPisFeasZero(scip, lb[j])) || (! SCIPlpiIsInfinity(lp, ub[j]) && ! SCIPisFeasZero(scip, ub[j])) )
    1672 {
    1673 SCIPABORT();
    1674 }
    1675 }
    1676 }
    1677
    1678 SCIPfreeBufferArray(scip, &covered);
    1681
    1682 return SCIP_OKAY;
    1683}
    1684#endif
    1685
    1686
    1687/** set the alternative system objective function
    1688 *
    1689 * We assume that the objective function coefficients of the variables other than the binary
    1690 * indicators are always 0 and hence do not have to be changed.
    1691 *
    1692 * We already use the tranformation \f$y' = 1 - y\f$.
    1693 */
    1694static
    1696 SCIP* scip, /**< SCIP pointer */
    1697 SCIP_LPI* lp, /**< alternative LP */
    1698 SCIP_SOL* sol, /**< solution to be dealt with */
    1699 int nconss, /**< number of constraints */
    1700 SCIP_CONS** conss /**< indicator constraints */
    1701 )
    1702{
    1703 int j;
    1704 SCIP_Real* obj = NULL;
    1705 int* indices = NULL;
    1706 int cnt = 0;
    1707
    1708 assert( scip != NULL );
    1709 assert( lp != NULL );
    1710 assert( conss != NULL );
    1711
    1712 SCIP_CALL( SCIPallocBufferArray(scip, &obj, nconss) );
    1713 SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
    1714
    1715 for (j = 0; j < nconss; ++j)
    1716 {
    1717 SCIP_CONSDATA* consdata;
    1718
    1719 assert( conss[j] != NULL );
    1720 consdata = SCIPconsGetData(conss[j]);
    1721 assert( consdata != NULL );
    1722
    1723 if ( consdata->colindex >= 0 )
    1724 {
    1725 SCIP_Real val = SCIPgetSolVal(scip, sol, consdata->binvar);
    1726 if ( SCIPisFeasEQ(scip, val, 1.0) )
    1727 obj[cnt] = OBJEPSILON; /* set objective to some small number to get small IISs */
    1728 else
    1729 obj[cnt] = 1.0 - val;
    1730 indices[cnt++] = consdata->colindex;
    1731 }
    1732 }
    1733
    1734 if ( cnt > 0 )
    1735 {
    1736 SCIP_CALL( SCIPlpiChgObj(lp, cnt, indices, obj) );
    1737 }
    1738
    1739 SCIPfreeBufferArray(scip, &indices);
    1741
    1742 return SCIP_OKAY;
    1743}
    1744
    1745
    1746/** set the alternative system objective function to some small value */
    1747static
    1749 SCIP* scip, /**< SCIP pointer */
    1750 SCIP_LPI* lp, /**< alternative LP */
    1751 int nconss, /**< number of constraints */
    1752 SCIP_CONS** conss /**< indicator constraints */
    1753 )
    1754{
    1755 int j;
    1756 SCIP_Real* obj = NULL;
    1757 int* indices = NULL;
    1758 int cnt = 0;
    1759
    1760 assert( scip != NULL );
    1761 assert( lp != NULL );
    1762 assert( conss != NULL );
    1763
    1764 SCIP_CALL( SCIPallocBufferArray(scip, &obj, nconss) );
    1765 SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
    1766
    1767 for (j = 0; j < nconss; ++j)
    1768 {
    1769 SCIP_CONSDATA* consdata;
    1770
    1771 assert( conss[j] != NULL );
    1772 consdata = SCIPconsGetData(conss[j]);
    1773 assert( consdata != NULL );
    1774
    1775 if ( consdata->colindex >= 0 )
    1776 {
    1777 obj[cnt] = OBJEPSILON;
    1778 indices[cnt++] = consdata->colindex;
    1779 }
    1780 }
    1781
    1782 if ( cnt > 0 )
    1783 {
    1784 SCIP_CALL( SCIPlpiChgObj(lp, cnt, indices, obj) );
    1785 }
    1786
    1787 SCIPfreeBufferArray(scip, &indices);
    1789
    1790 return SCIP_OKAY;
    1791}
    1792
    1793
    1794/** fix variable given by @a S to 0 */
    1795static
    1797 SCIP* scip, /**< SCIP pointer */
    1798 SCIP_LPI* lp, /**< alternative LP */
    1799 int nconss, /**< number of constraints */
    1800 SCIP_CONS** conss, /**< indicator constraints */
    1801 SCIP_Bool* S /**< bitset of variables */
    1802 )
    1803{
    1804 SCIP_Real* lb = NULL;
    1805 SCIP_Real* ub = NULL;
    1806 int* indices = NULL;
    1807 int cnt = 0;
    1808 int j;
    1809
    1810 assert( scip != NULL );
    1811 assert( lp != NULL );
    1812 assert( conss != NULL );
    1813
    1814 SCIP_CALL( SCIPallocBufferArray(scip, &lb, nconss) );
    1815 SCIP_CALL( SCIPallocBufferArray(scip, &ub, nconss) );
    1816 SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
    1817
    1818 /* collect bounds to be changed */
    1819 for (j = 0; j < nconss; ++j)
    1820 {
    1821 SCIP_CONSDATA* consdata;
    1822
    1823 assert( conss[j] != NULL );
    1824 consdata = SCIPconsGetData(conss[j]);
    1825 assert( consdata != NULL );
    1826
    1827 if ( consdata->colindex >= 0 )
    1828 {
    1829 if ( S[j] )
    1830 {
    1831 indices[cnt] = consdata->colindex;
    1832 lb[cnt] = 0.0;
    1833 ub[cnt] = 0.0;
    1834 ++cnt;
    1835 }
    1836 }
    1837 }
    1838
    1839 /* change bounds */
    1840 if ( cnt > 0 )
    1841 {
    1842 SCIP_CALL( SCIPlpiChgBounds(lp, cnt, indices, lb, ub) );
    1843 }
    1844
    1845 SCIPfreeBufferArray(scip, &indices);
    1848
    1849 return SCIP_OKAY;
    1850}
    1851
    1852
    1853/** fix variable @a ind to 0 */
    1854static
    1856 SCIP_LPI* lp, /**< alternative LP */
    1857 int ind /**< variable that should be fixed to 0 */
    1858 )
    1859{
    1860 SCIP_Real lb = 0.0;
    1861 SCIP_Real ub = 0.0;
    1862
    1863 /* change bounds */
    1864 SCIP_CALL( SCIPlpiChgBounds(lp, 1, &ind, &lb, &ub) );
    1865
    1866 return SCIP_OKAY;
    1867}
    1868
    1869
    1870/** unfix variable @a ind to 0 */
    1871static
    1873 SCIP_LPI* lp, /**< alternative LP */
    1874 int ind /**< variable that should be fixed to 0 */
    1875 )
    1876{
    1877 SCIP_Real lb = 0.0;
    1878 SCIP_Real ub = SCIPlpiInfinity(lp);
    1879
    1880 /* change bounds */
    1881 SCIP_CALL( SCIPlpiChgBounds(lp, 1, &ind, &lb, &ub) );
    1882
    1883 return SCIP_OKAY;
    1884}
    1885
    1886/** unfix variable given by @a S to 0 */
    1887static
    1889 SCIP* scip, /**< SCIP pointer */
    1890 SCIP_LPI* lp, /**< alternative LP */
    1891 int nconss, /**< number of constraints */
    1892 SCIP_CONS** conss, /**< indicator constraints */
    1893 SCIP_Bool* S /**< bitset of variables */
    1894 )
    1895{
    1896 SCIP_Real* lb = NULL;
    1897 SCIP_Real* ub = NULL;
    1898 int* indices = NULL;
    1899 int cnt = 0;
    1900 int j;
    1901
    1902 assert( scip != NULL );
    1903 assert( lp != NULL );
    1904 assert( conss != NULL );
    1905
    1906 SCIP_CALL( SCIPallocBufferArray(scip, &lb, nconss) );
    1907 SCIP_CALL( SCIPallocBufferArray(scip, &ub, nconss) );
    1908 SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
    1909
    1910 /* collect bounds to be changed */
    1911 for (j = 0; j < nconss; ++j)
    1912 {
    1913 if ( S[j] )
    1914 {
    1915 SCIP_CONSDATA* consdata;
    1916
    1917 assert( conss[j] != NULL );
    1918 consdata = SCIPconsGetData(conss[j]);
    1919 assert( consdata != NULL );
    1920
    1921 if ( consdata->colindex >= 0 )
    1922 {
    1923 indices[cnt] = consdata->colindex;
    1924 lb[cnt] = 0.0;
    1925 ub[cnt] = SCIPlpiInfinity(lp);
    1926 ++cnt;
    1927 }
    1928 }
    1929 }
    1930
    1931 /* change bounds */
    1932 if ( cnt > 0 )
    1933 {
    1934 SCIP_CALL( SCIPlpiChgBounds(lp, cnt, indices, lb, ub) );
    1935 }
    1936
    1937 SCIPfreeBufferArray(scip, &indices);
    1940
    1941 return SCIP_OKAY;
    1942}
    1943
    1944
    1945/** update bounds in first row to the current ones */
    1946static
    1948 SCIP* scip, /**< SCIP pointer */
    1949 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
    1950 )
    1951{
    1952 SCIP_HASHMAP* lbhash;
    1953 SCIP_HASHMAP* ubhash;
    1954 SCIP_VAR** vars;
    1955 SCIP_LPI* altlp;
    1956 int nvars;
    1957 int cnt;
    1958 int v;
    1959
    1960 assert( scip != NULL );
    1961 assert( conshdlrdata != NULL );
    1962
    1963 altlp = conshdlrdata->altlp;
    1964 lbhash = conshdlrdata->lbhash;
    1965 ubhash = conshdlrdata->ubhash;
    1966 assert( lbhash != NULL && ubhash != NULL );
    1967
    1968 /* check all variables */
    1969 vars = SCIPgetVars(scip);
    1970 nvars = SCIPgetNVars(scip);
    1971 cnt = 0;
    1972
    1973 for (v = 0; v < nvars; ++v)
    1974 {
    1975 SCIP_VAR* var;
    1976 var = vars[v];
    1977 if ( SCIPhashmapExists(lbhash, var) )
    1978 {
    1979 int col;
    1980
    1981 col = SCIPhashmapGetImageInt(lbhash, var);
    1982 SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, -SCIPvarGetLbLocal(var)) );
    1984 ++cnt;
    1985 }
    1986 if ( SCIPhashmapExists(ubhash, var) )
    1987 {
    1988 int col;
    1989
    1990 col = SCIPhashmapGetImageInt(ubhash, var);
    1991 SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, SCIPvarGetUbLocal(var)) );
    1993 ++cnt;
    1994 }
    1995 }
    1996 if ( cnt > 10 )
    1997 {
    1998 /* possible force a rescaling: */
    1999 conshdlrdata->scaled = FALSE;
    2000
    2001 /* SCIP_CALL( SCIPlpiWriteLP(altlp, "altChg.lp") ); */
    2002 SCIPdebugMsg(scip, "Updated bounds of original variables: %d.\n", cnt);
    2003 }
    2004
    2005 return SCIP_OKAY;
    2006}
    2007
    2008
    2009/** update bounds in first row to the global bounds */
    2010static
    2012 SCIP* scip, /**< SCIP pointer */
    2013 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
    2014 )
    2015{
    2016 SCIP_HASHMAP* lbhash;
    2017 SCIP_HASHMAP* ubhash;
    2018 SCIP_VAR** vars;
    2019 SCIP_LPI* altlp;
    2020 int nvars;
    2021 int cnt;
    2022 int v;
    2023
    2024 assert( scip != NULL );
    2025 assert( conshdlrdata != NULL );
    2026
    2027 altlp = conshdlrdata->altlp;
    2028 lbhash = conshdlrdata->lbhash;
    2029 ubhash = conshdlrdata->ubhash;
    2030 assert( lbhash != NULL && ubhash != NULL );
    2031
    2032 /* check all variables */
    2033 vars = SCIPgetVars(scip);
    2034 nvars = SCIPgetNVars(scip);
    2035 cnt = 0;
    2036
    2037 for (v = 0; v < nvars; ++v)
    2038 {
    2039 SCIP_VAR* var;
    2040 int col;
    2041
    2042 var = vars[v];
    2043 if ( SCIPhashmapExists(lbhash, var) )
    2044 {
    2045 col = SCIPhashmapGetImageInt(lbhash, var);
    2046 SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, -SCIPvarGetLbGlobal(var)) );
    2047 ++cnt;
    2048 }
    2049 if ( SCIPhashmapExists(ubhash, var) )
    2050 {
    2051 col = SCIPhashmapGetImageInt(ubhash, var);
    2052 SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, SCIPvarGetUbGlobal(var)) );
    2053 ++cnt;
    2054 }
    2055 }
    2056
    2057 if ( cnt > 0 )
    2058 {
    2059 /* SCIP_CALL( SCIPlpiWriteLP(altlp, "altChg.lp") ); */
    2060 SCIPdebugMsg(scip, "Updated bounds of original variables: %d.\n", cnt);
    2061 }
    2062
    2063 /* possible force a rescaling: */
    2064 /* conshdlrdata->scaled = FALSE; */
    2065
    2066 return SCIP_OKAY;
    2067}
    2068
    2069
    2070/** check whether IIS defined by @a vector corresponds to a local cut */
    2071static
    2073 SCIP* scip, /**< SCIP pointer */
    2074 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler */
    2075 SCIP_Real* vector, /**< solution to alternative LP defining IIS */
    2076 SCIP_Bool* isLocal /**< whether the IIS uses local bounds different from the global ones */
    2077 )
    2078{
    2079 SCIP_HASHMAP* lbhash;
    2080 SCIP_HASHMAP* ubhash;
    2081 SCIP_VAR** vars;
    2082#ifndef NDEBUG
    2083 int nCols;
    2084#endif
    2085 int nvars;
    2086 int v;
    2087
    2088 assert( scip != NULL );
    2089 assert( conshdlrdata != NULL );
    2090 assert( vector != NULL );
    2091 assert( isLocal != NULL );
    2092
    2093 *isLocal = FALSE;
    2094
    2095#ifndef NDEBUG
    2096 SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &nCols) );
    2097#endif
    2098
    2099 lbhash = conshdlrdata->lbhash;
    2100 ubhash = conshdlrdata->ubhash;
    2101 assert( lbhash != NULL && ubhash != NULL );
    2102
    2103 /* get all variables */
    2104 vars = SCIPgetVars(scip);
    2105 nvars = SCIPgetNVars(scip);
    2106
    2107 /* check all variables */
    2108 for (v = 0; v < nvars; ++v)
    2109 {
    2110 SCIP_VAR* var;
    2111 var = vars[v];
    2112
    2113 /* if local bound is different from global bound */
    2115 {
    2116 /* check whether the variable corresponding to the lower bounds has been used */
    2117 if ( SCIPhashmapExists(lbhash, var) )
    2118 {
    2119 int col;
    2120
    2121 col = SCIPhashmapGetImageInt(lbhash, var);
    2122 assert( 0 <= col && col < nCols );
    2123 if ( ! SCIPisFeasZero(scip, vector[col]) )
    2124 {
    2125 *isLocal = TRUE;
    2126 return SCIP_OKAY;
    2127 }
    2128 }
    2129 }
    2130
    2131 /* if local bound is different from global bound */
    2133 {
    2134 /* check whether the variable corresponding to the upper bounds has been used */
    2135 if ( SCIPhashmapExists(ubhash, var) )
    2136 {
    2137 int col;
    2138
    2139 col = SCIPhashmapGetImageInt(ubhash, var);
    2140 assert( 0 <= col && col < nCols );
    2141 if ( ! SCIPisFeasZero(scip, vector[col]) )
    2142 {
    2143 *isLocal = TRUE;
    2144 return SCIP_OKAY;
    2145 }
    2146 }
    2147 }
    2148 }
    2149
    2150 return SCIP_OKAY;
    2151}
    2152
    2153
    2154/** compute scaling for first row
    2155 *
    2156 * If the coefficients in the first row are large, a right hand side of -1 might not be
    2157 * adequate. Here, we replace the right hand side by the sum of the coefficients divided by the
    2158 * number of nonzeros.
    2159 */
    2160static
    2162 SCIP* scip, /**< SCIP pointer */
    2163 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
    2164 )
    2165{
    2166 assert( scip != NULL );
    2167 assert( conshdlrdata != NULL );
    2168
    2169 if ( ! conshdlrdata->scaled )
    2170 {
    2171 SCIP_Real* val;
    2172 SCIP_LPI* altlp;
    2173 int* ind;
    2174 SCIP_Real sum = 0.0;
    2175 int beg[1];
    2176 int nCols;
    2177 int cnt;
    2178 int j;
    2179
    2180 altlp = conshdlrdata->altlp;
    2181 SCIP_CALL( SCIPlpiGetNCols(altlp, &nCols) );
    2182 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nCols) );
    2183 SCIP_CALL( SCIPallocBufferArray(scip, &val, nCols) );
    2184
    2185 SCIP_CALL( SCIPlpiGetRows(altlp, 0, 0, NULL, NULL, &cnt, beg, ind, val) );
    2186
    2187 if ( cnt > 0 )
    2188 {
    2189 /* compute sum */
    2190 for (j = 0; j < cnt; ++j)
    2191 sum += REALABS(val[j]);
    2192
    2193 /* set rhs */
    2194 sum = - REALABS(sum) / ((double) cnt);
    2195 j = 0;
    2196 SCIP_CALL( SCIPlpiChgSides(altlp, 1, &j, &sum, &sum) );
    2197 }
    2198
    2201
    2202 conshdlrdata->scaled = TRUE;
    2203 }
    2204
    2205 return SCIP_OKAY;
    2206}
    2207
    2208
    2209/** add column to alternative LP
    2210 *
    2211 * See the description at the top of the file for more information.
    2212 */
    2213static
    2215 SCIP* scip, /**< SCIP pointer */
    2216 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2217 SCIP_CONSHDLRDATA* conshdlrdata, /**< data of constraint handler */
    2218 SCIP_VAR* slackvar, /**< slack variable or NULL */
    2219 int nvars, /**< number of variables in column */
    2220 SCIP_VAR** vars, /**< variables for column */
    2221 SCIP_Real* vals, /**< values for column */
    2222 SCIP_Real rhscoef, /**< coefficient for first row */
    2223 SCIP_Real objcoef, /**< objective in alternative LP */
    2224 SCIP_Real sign, /**< sign (+1,-1) for column */
    2225 SCIP_Bool colfree, /**< whether column should be free, e.g., for equations */
    2226 int* colindex /**< index of new column (return value) */
    2227 )
    2228{
    2229 SCIP_VAR** newvars;
    2230 SCIP_Real val;
    2231 SCIP_Real* matval;
    2232 SCIP_Bool* newrowsslack;
    2233 SCIP_Real* obj;
    2234 SCIP_Real* lb;
    2235 SCIP_Real* ub;
    2236 int* matbeg;
    2237 int* matind;
    2238 int nnewvars = 0;
    2239 int nnewcols = 0;
    2240 int nnewrows = 0;
    2241 int ncols = 0;
    2242 int cnt = 0;
    2243 int v;
    2244
    2245 assert( scip != NULL );
    2246 assert( conshdlrdata != NULL );
    2247 assert( vars != NULL || nvars == 0 );
    2248 assert( vals != NULL || nvars == 0 );
    2249 assert( ! SCIPisInfinity(scip, rhscoef) && ! SCIPisInfinity(scip, -rhscoef) );
    2250 assert( SCIPisEQ(scip, sign, 1.0) || SCIPisEQ(scip, sign, -1.0) );
    2251 assert( colindex != NULL );
    2252
    2253 *colindex = -1;
    2254
    2255 if ( conshdlrdata->altlp == NULL )
    2256 {
    2257 SCIP_CALL( initAlternativeLP(scip, conshdlr) );
    2258 }
    2259 assert( conshdlrdata->altlp != NULL );
    2260 assert( conshdlrdata->varhash != NULL );
    2261 assert( conshdlrdata->lbhash != NULL );
    2262 assert( conshdlrdata->ubhash != NULL );
    2263 assert( conshdlrdata->slackhash != NULL );
    2264
    2265#ifndef NDEBUG
    2266 {
    2267 int nrows;
    2268 SCIP_CALL( SCIPlpiGetNRows(conshdlrdata->altlp, &nrows) );
    2269 assert( nrows == conshdlrdata->nrows );
    2270 }
    2271#endif
    2272
    2273 /* set up data for construction */
    2274 SCIP_CALL( SCIPallocBufferArray(scip, &matbeg, nvars) );
    2275 SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4 * nvars) );
    2276 SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4 * nvars) );
    2277 SCIP_CALL( SCIPallocBufferArray(scip, &obj, 2 * nvars) );
    2278 SCIP_CALL( SCIPallocBufferArray(scip, &lb, 2 * nvars) );
    2279 SCIP_CALL( SCIPallocBufferArray(scip, &ub, 2 * nvars) );
    2280 SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nvars) );
    2281 SCIP_CALL( SCIPallocBufferArray(scip, &newrowsslack, 2 * nvars) );
    2282
    2283 /* store index of column in constraint */
    2284 /* coverity[var_deref_model] */
    2285 SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &ncols) );
    2286 *colindex = ncols;
    2287
    2288 /* handle first row */
    2289 if ( ! SCIPisFeasZero(scip, rhscoef) )
    2290 {
    2291 matind[cnt] = 0;
    2292 matval[cnt++] = sign * rhscoef;
    2293 }
    2294
    2295 /* set up column (recognize new original variables) */
    2296 for (v = 0; v < nvars; ++v)
    2297 {
    2298 SCIP_VAR* var;
    2299
    2300 var = vars[v];
    2301 assert( var != NULL );
    2302
    2303 /* if variable is a slack variable */
    2304 if ( SCIPhashmapExists(conshdlrdata->slackhash, var) )
    2305 {
    2306 /* to avoid trivial rows: only add row corresponding to slack variable if it appears outside its own constraint */
    2307 if ( var != slackvar )
    2308 {
    2309 int ind;
    2310
    2311 ind = SCIPhashmapGetImageInt(conshdlrdata->slackhash, var);
    2312
    2313 if ( ind < INT_MAX )
    2314 matind[cnt] = ind;
    2315 else
    2316 {
    2317 /* correct number of variable already in map/array and remember to add a new row */
    2318 SCIP_CALL( SCIPhashmapSetImageInt(conshdlrdata->slackhash, var, conshdlrdata->nrows) );
    2319 assert( conshdlrdata->nrows == SCIPhashmapGetImageInt(conshdlrdata->slackhash, var) );
    2320 SCIPdebugMsg(scip, "Inserted slack variable <%s> into hashmap (row: %d).\n", SCIPvarGetName(var), conshdlrdata->nrows);
    2321 matind[cnt] = (conshdlrdata->nrows)++;
    2322
    2323 /* store new variables */
    2324 newrowsslack[nnewrows++] = TRUE;
    2325 }
    2326 assert( conshdlrdata->nrows >= SCIPhashmapGetImageInt(conshdlrdata->slackhash, var) );
    2327 matval[cnt++] = sign * vals[v];
    2328 }
    2329 }
    2330 else
    2331 {
    2332 /* if variable exists */
    2333 if ( SCIPhashmapExists(conshdlrdata->varhash, var) )
    2334 matind[cnt] = SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
    2335 else
    2336 {
    2337 /* add variable in map and array and remember to add a new row */
    2338 SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->varhash, var, conshdlrdata->nrows) );
    2339 assert( conshdlrdata->nrows == SCIPhashmapGetImageInt(conshdlrdata->varhash, var) );
    2340 SCIPdebugMsg(scip, "Inserted variable <%s> into hashmap (row: %d).\n", SCIPvarGetName(var), conshdlrdata->nrows);
    2341 matind[cnt] = (conshdlrdata->nrows)++;
    2342
    2343 /* store new variables */
    2344 newrowsslack[nnewrows++] = FALSE;
    2345 newvars[nnewvars++] = var;
    2346 }
    2347 assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
    2348 matval[cnt++] = sign * vals[v];
    2349 }
    2350 }
    2351
    2352 /* add new rows */
    2353 if ( nnewrows > 0 )
    2354 {
    2355 SCIP_Real* lhs;
    2356 SCIP_Real* rhs;
    2357 int i;
    2358
    2359 SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nnewrows) );
    2360 SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nnewrows) );
    2361 for (i = 0; i < nnewrows; ++i)
    2362 {
    2363 if ( newrowsslack[i] )
    2364 lhs[i] = -SCIPlpiInfinity(conshdlrdata->altlp);
    2365 else
    2366 lhs[i] = 0.0;
    2367 rhs[i] = 0.0;
    2368 }
    2369 /* add new rows */
    2370 SCIP_CALL( SCIPlpiAddRows(conshdlrdata->altlp, nnewrows, lhs, rhs, NULL, 0, NULL, NULL, NULL) );
    2371
    2374 }
    2375
    2376 /* now add column */
    2377 obj[0] = objcoef;
    2378 if ( colfree )
    2379 {
    2380 /* create a free variable -> should only happen for additional linear constraints */
    2381 assert( slackvar == NULL );
    2382 lb[0] = -SCIPlpiInfinity(conshdlrdata->altlp);
    2383 }
    2384 else
    2385 lb[0] = 0.0;
    2386 ub[0] = SCIPlpiInfinity(conshdlrdata->altlp);
    2387 matbeg[0] = 0;
    2388
    2389 SCIP_CALL( SCIPlpiAddCols(conshdlrdata->altlp, 1, obj, lb, ub, NULL, cnt, matbeg, matind, matval) );
    2390
    2391 /* add columns corresponding to bounds of original variables - no bounds needed for slack vars */
    2392 cnt = 0;
    2393 for (v = 0; v < nnewvars; ++v)
    2394 {
    2395 SCIP_VAR* var = newvars[v];
    2396 assert( var != NULL );
    2397
    2398 /* if the lower bound is finite */
    2399 val = SCIPvarGetLbGlobal(var);
    2400 if ( ! SCIPisInfinity(scip, -val) )
    2401 {
    2402 matbeg[nnewcols] = cnt;
    2403 if ( ! SCIPisZero(scip, val) )
    2404 {
    2405 matind[cnt] = 0;
    2406 matval[cnt++] = -val;
    2407 }
    2408 assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
    2409
    2410 matind[cnt] = SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
    2411 matval[cnt++] = -1.0;
    2412 obj[nnewcols] = 0.0;
    2413 lb[nnewcols] = 0.0;
    2414 ub[nnewcols] = SCIPlpiInfinity(conshdlrdata->altlp);
    2415 ++conshdlrdata->nlbbounds;
    2416
    2417 SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->lbhash, var, ncols + 1 + nnewcols) );
    2418 assert( SCIPhashmapExists(conshdlrdata->lbhash, var) );
    2419 SCIPdebugMsg(scip, "Added column for lower bound (%f) of variable <%s> to alternative polyhedron (col: %d).\n",
    2420 val, SCIPvarGetName(var), ncols + 1 + nnewcols);
    2421 ++nnewcols;
    2422 }
    2423
    2424 /* if the upper bound is finite */
    2425 val = SCIPvarGetUbGlobal(var);
    2426 if ( ! SCIPisInfinity(scip, val) )
    2427 {
    2428 matbeg[nnewcols] = cnt;
    2429 if ( ! SCIPisZero(scip, val) )
    2430 {
    2431 matind[cnt] = 0;
    2432 matval[cnt++] = val;
    2433 }
    2434 assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
    2435
    2436 matind[cnt] = SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
    2437 matval[cnt++] = 1.0;
    2438 obj[nnewcols] = 0.0;
    2439 lb[nnewcols] = 0.0;
    2440 ub[nnewcols] = SCIPlpiInfinity(conshdlrdata->altlp);
    2441 ++conshdlrdata->nubbounds;
    2442
    2443 SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->ubhash, var, ncols + 1 + nnewcols) );
    2444 assert( SCIPhashmapExists(conshdlrdata->ubhash, var) );
    2445 SCIPdebugMsg(scip, "Added column for upper bound (%f) of variable <%s> to alternative polyhedron (col: %d).\n",
    2446 val, SCIPvarGetName(var), ncols + 1 + nnewcols);
    2447 ++nnewcols;
    2448 }
    2449 }
    2450
    2451 /* add columns if necessary */
    2452 if ( nnewcols > 0 )
    2453 {
    2454 SCIP_CALL( SCIPlpiAddCols(conshdlrdata->altlp, nnewcols, obj, lb, ub, NULL, cnt, matbeg, matind, matval) );
    2455 }
    2456
    2457#ifndef NDEBUG
    2458 SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &cnt) );
    2459 assert( cnt == ncols + nnewcols + 1 );
    2460#endif
    2461
    2465 SCIPfreeBufferArray(scip, &matind);
    2466 SCIPfreeBufferArray(scip, &matval);
    2467 SCIPfreeBufferArray(scip, &matbeg);
    2468 SCIPfreeBufferArray(scip, &newvars);
    2469 SCIPfreeBufferArray(scip, &newrowsslack);
    2470
    2471 conshdlrdata->scaled = FALSE;
    2472
    2473#ifdef SCIP_OUTPUT
    2474 SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "alt.lp") );
    2475#endif
    2476
    2477 return SCIP_OKAY;
    2478}
    2479
    2480
    2481/** add column corresponding to constraint to alternative LP
    2482 *
    2483 * See the description at the top of the file for more information.
    2484 */
    2485static
    2487 SCIP* scip, /**< SCIP pointer */
    2488 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2489 SCIP_CONS* lincons, /**< linear constraint */
    2490 SCIP_VAR* slackvar, /**< slack variable or NULL */
    2491 SCIP_Real objcoef, /**< objective coefficient */
    2492 int* colindex /**< index of new column */
    2493 )
    2494{
    2495 SCIP_CONSHDLRDATA* conshdlrdata;
    2496 SCIP_VAR** linvars;
    2497 SCIP_Real* linvals;
    2498 SCIP_Real linrhs;
    2499 SCIP_Real linlhs;
    2500 int nlinvars;
    2501
    2502 assert( scip != NULL );
    2503 assert( conshdlr != NULL );
    2504 assert( lincons != NULL );
    2505 assert( colindex != NULL );
    2506
    2508
    2509 *colindex = -1;
    2510
    2511 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2512 assert( conshdlrdata != NULL );
    2513
    2514 /* if the slack variable is aggregated (multi-aggregation should not happen) */
    2515 assert( slackvar == NULL || SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
    2516 if ( slackvar != NULL && SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
    2517 {
    2518 SCIP_VAR* var;
    2519 SCIP_Real scalar = 1.0;
    2520 SCIP_Real constant = 0.0;
    2521
    2522 var = slackvar;
    2523
    2524 SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
    2525
    2526 SCIPdebugMsg(scip, "Slack variable is aggregated (scalar: %f, constant: %f).\n", scalar, constant);
    2527
    2528 /* if the slack variable is fixed */
    2529 if ( SCIPisZero(scip, scalar) && ! SCIPconsIsActive(lincons) )
    2530 return SCIP_OKAY;
    2531
    2532 /* otherwise construct a linear constraint */
    2533 SCIP_CALL( SCIPallocBufferArray(scip, &linvars, 1) );
    2534 SCIP_CALL( SCIPallocBufferArray(scip, &linvals, 1) );
    2535 linvars[0] = var;
    2536 linvals[0] = scalar;
    2537 nlinvars = 1;
    2538 linlhs = -SCIPinfinity(scip);
    2539 linrhs = constant;
    2540 }
    2541 else
    2542 {
    2543 /* exit if linear constraint is not active */
    2544 if ( ! SCIPconsIsActive(lincons) && slackvar != NULL )
    2545 return SCIP_OKAY;
    2546
    2547 /* in this case, the linear constraint is directly usable */
    2548 linvars = SCIPgetVarsLinear(scip, lincons);
    2549 linvals = SCIPgetValsLinear(scip, lincons);
    2550 nlinvars = SCIPgetNVarsLinear(scip, lincons);
    2551 linlhs = SCIPgetLhsLinear(scip, lincons);
    2552 linrhs = SCIPgetRhsLinear(scip, lincons);
    2553 }
    2554
    2555 /* create column */
    2556 if ( SCIPisEQ(scip, linlhs, linrhs) )
    2557 {
    2558 /* create free variable for equations (should only happen for additional linear constraints) */
    2559 SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, slackvar, nlinvars, linvars, linvals, linrhs, objcoef, 1.0, TRUE, colindex) );
    2560 }
    2561 else if ( ! SCIPisInfinity(scip, linrhs) )
    2562 {
    2563 /* create column for rhs */
    2564 SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, slackvar, nlinvars, linvars, linvals, linrhs, objcoef, 1.0, FALSE, colindex) );
    2565 }
    2566 else
    2567 {
    2568 /* create column for lhs */
    2569 assert( ! SCIPisInfinity(scip, -linlhs) );
    2570 SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, slackvar, nlinvars, linvars, linvals, linlhs, objcoef, -1.0, FALSE, colindex) );
    2571 }
    2572
    2573 if ( slackvar != NULL && SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
    2574 {
    2575 SCIPfreeBufferArray(scip, &linvals);
    2576 SCIPfreeBufferArray(scip, &linvars);
    2577 }
    2578
    2579 return SCIP_OKAY;
    2580}
    2581
    2582
    2583/** add column corresponding to row to alternative LP
    2584 *
    2585 * See the description at the top of the file for more information.
    2586 */
    2587static
    2589 SCIP* scip, /**< SCIP pointer */
    2590 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2591 SCIP_ROW* row, /**< row to add */
    2592 SCIP_Real objcoef, /**< objective coefficient */
    2593 int* colindex /**< index of new column */
    2594 )
    2595{
    2596 SCIP_CONSHDLRDATA* conshdlrdata;
    2597 SCIP_COL** rowcols;
    2598 SCIP_Real* rowvals;
    2599 SCIP_VAR** rowvars;
    2600 SCIP_Real rowrhs;
    2601 SCIP_Real rowlhs;
    2602 int nrowcols;
    2603 int j;
    2604
    2605 assert( scip != NULL );
    2606 assert( conshdlr != NULL );
    2607 assert( row != NULL );
    2608 assert( colindex != NULL );
    2609
    2611
    2612 /* initialize data */
    2613 *colindex = -1;
    2614
    2615 /* exit if row is not global */
    2616 if ( SCIProwIsLocal(row) )
    2617 return SCIP_OKAY;
    2618
    2619 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2620 assert( conshdlrdata != NULL );
    2621
    2622 /* get row data */
    2623 rowcols = SCIProwGetCols(row);
    2624 rowvals = SCIProwGetVals(row);
    2625 nrowcols = SCIProwGetNNonz(row);
    2626 rowlhs = SCIProwGetLhs(row) - SCIProwGetConstant(row);
    2627 rowrhs = SCIProwGetRhs(row) - SCIProwGetConstant(row);
    2628
    2629 SCIP_CALL( SCIPallocBufferArray(scip, &rowvars, nrowcols) );
    2630 for (j = 0; j < nrowcols; ++j)
    2631 {
    2632 rowvars[j] = SCIPcolGetVar(rowcols[j]);
    2633 assert( rowvars[j] != NULL );
    2634 }
    2635
    2636 /* create column */
    2637 if ( SCIPisEQ(scip, rowlhs, rowrhs) )
    2638 {
    2639 /* create free variable for equations (should only happen for additional linear constraints) */
    2640 SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nrowcols, rowvars, rowvals, rowrhs, objcoef, 1.0, TRUE, colindex) );
    2641 }
    2642 else if ( ! SCIPisInfinity(scip, rowrhs) )
    2643 {
    2644 /* create column for rhs */
    2645 SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nrowcols, rowvars, rowvals, rowrhs, objcoef, 1.0, FALSE, colindex) );
    2646 }
    2647 else
    2648 {
    2649 /* create column for lhs */
    2650 assert( ! SCIPisInfinity(scip, -rowlhs) );
    2651 SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nrowcols, rowvars, rowvals, rowlhs, objcoef, -1.0, FALSE, colindex) );
    2652 }
    2653
    2654 SCIPfreeBufferArray(scip, &rowvars);
    2655
    2656 return SCIP_OKAY;
    2657}
    2658
    2659
    2660/** try to add objective cut as column to alternative LP */
    2661static
    2663 SCIP* scip, /**< SCIP pointer */
    2664 SCIP_CONSHDLR* conshdlr /**< constraint handler */
    2665 )
    2666{
    2667 SCIP_CONSHDLRDATA* conshdlrdata;
    2668 SCIP_VAR** objvars;
    2669 SCIP_Real* objvals;
    2670 SCIP_VAR** vars;
    2671 int nobjvars = 0;
    2672 int nvars;
    2673 int v;
    2674
    2675 assert( scip != NULL );
    2676 assert( conshdlr != NULL );
    2677
    2679
    2680 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2681 assert( conshdlrdata != NULL );
    2682
    2683 /* skip procedure if already added */
    2684 if ( conshdlrdata->objcutindex >= 0 )
    2685 return SCIP_OKAY;
    2686
    2687 /* check whether we can add objective cut: all indicator variables have zero objective */
    2688 if ( ! conshdlrdata->objothervarsonly )
    2689 return SCIP_OKAY;
    2690
    2691 assert( ! SCIPisInfinity(scip, conshdlrdata->objupperbound) );
    2692 SCIPdebugMsg(scip, "Add objective cut to alternative LP (obj. bound: %g).\n", conshdlrdata->objupperbound);
    2693
    2694 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    2695 SCIP_CALL( SCIPallocBufferArray(scip, &objvars, nvars) );
    2696 SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
    2697
    2698 /* collect nonzeros */
    2699 for (v = 0; v < nvars; ++v)
    2700 {
    2701 SCIP_VAR* var;
    2702 SCIP_Real objval;
    2703
    2704 var = vars[v];
    2705 assert( var != NULL );
    2706 objval = SCIPvarGetObj(var);
    2707
    2708 /* skip variables with zero objective - this includes slack and indicator variables */
    2709 if ( ! SCIPisZero(scip, objval) )
    2710 {
    2711 objvars[nobjvars] = var;
    2712 objvals[nobjvars++] = objval;
    2713 }
    2714 }
    2715
    2716 /* create column (with rhs = upperbound, objective 0, and scaling factor 1.0) */
    2717 SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nobjvars, objvars, objvals, conshdlrdata->objupperbound, 0.0, 1.0, FALSE, &conshdlrdata->objcutindex) );
    2718 assert( conshdlrdata->objcutindex >= 0 );
    2719 conshdlrdata->objaltlpbound = conshdlrdata->objupperbound;
    2720
    2721 SCIPfreeBufferArray(scip, &objvals);
    2722 SCIPfreeBufferArray(scip, &objvars);
    2723
    2724 return SCIP_OKAY;
    2725}
    2726
    2727
    2728/** delete column corresponding to constraint in alternative LP
    2729 *
    2730 * We currently just fix the corresponding variable to 0.
    2731 */
    2732static
    2734 SCIP* scip, /**< SCIP pointer */
    2735 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2736 SCIP_CONS* cons /**< indicator constraint */
    2737 )
    2738{
    2739 SCIP_CONSHDLRDATA* conshdlrdata;
    2740
    2741 assert( scip != NULL );
    2742 assert( conshdlr != NULL );
    2743 assert( cons != NULL );
    2744
    2746
    2747 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2748 assert( conshdlrdata != NULL );
    2749
    2750 if ( conshdlrdata->altlp != NULL )
    2751 {
    2752 SCIP_CONSDATA* consdata;
    2753
    2754 consdata = SCIPconsGetData(cons);
    2755 assert( consdata != NULL );
    2756
    2757 if ( consdata->colindex >= 0 )
    2758 {
    2759 SCIP_CALL( fixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
    2760 }
    2761 consdata->colindex = -1;
    2762
    2763 SCIPdebugMsg(scip, "Fixed variable for column %d (constraint: <%s>) from alternative LP to 0.\n", consdata->colindex, SCIPconsGetName(cons));
    2764 }
    2765 conshdlrdata->scaled = FALSE;
    2766
    2767 return SCIP_OKAY;
    2768}
    2769
    2770
    2771/** update upper bound in alternative LP */
    2772static
    2774 SCIP* scip, /**< SCIP pointer */
    2775 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2776 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
    2777 )
    2778{
    2779 SCIP_Real objbnd;
    2780
    2781 assert( scip != NULL );
    2782 assert( conshdlrdata != NULL );
    2783
    2784 if ( ! conshdlrdata->useobjectivecut )
    2785 return SCIP_OKAY;
    2786
    2787 if ( conshdlrdata->altlp == NULL )
    2788 return SCIP_OKAY;
    2789
    2790 /* first check whether we can improve the upper bound */
    2791 objbnd = SCIPgetUpperbound(scip);
    2792 if ( ! SCIPisInfinity(scip, objbnd) )
    2793 {
    2794 if ( SCIPisObjIntegral(scip) )
    2795 objbnd = SCIPfeasCeil(scip, objbnd) - (1.0 - SCIPcutoffbounddelta(scip));
    2796 else
    2797 objbnd -= SCIPcutoffbounddelta(scip);
    2798
    2799 if ( SCIPisLT(scip, objbnd, conshdlrdata->objupperbound) )
    2800 conshdlrdata->objupperbound = objbnd;
    2801 }
    2802
    2803 if ( SCIPisInfinity(scip, conshdlrdata->objupperbound) )
    2804 return SCIP_OKAY;
    2805
    2806 /* if we can improve on the bound stored in the alternative LP */
    2807 if ( SCIPisLT(scip, conshdlrdata->objupperbound, conshdlrdata->objaltlpbound) )
    2808 {
    2809 SCIPdebugMsg(scip, "Update objective bound to %g.\n", conshdlrdata->objupperbound);
    2810
    2811 /* possibly add column for objective cut */
    2812 if ( conshdlrdata->objcutindex < 0 )
    2813 {
    2814 SCIP_CALL( addObjcut(scip, conshdlr) );
    2815 }
    2816 else
    2817 {
    2818#ifndef NDEBUG
    2819 SCIP_Real oldbnd;
    2820 SCIP_CALL( SCIPlpiGetCoef(conshdlrdata->altlp, 0, conshdlrdata->objcutindex, &oldbnd) );
    2821 assert( SCIPisEQ(scip, oldbnd, conshdlrdata->objaltlpbound) );
    2822#endif
    2823
    2824 /* update bound */
    2825 SCIP_CALL( SCIPlpiChgCoef(conshdlrdata->altlp, 0, conshdlrdata->objcutindex, conshdlrdata->objupperbound) );
    2826 conshdlrdata->objaltlpbound = conshdlrdata->objupperbound;
    2827
    2828#ifdef SCIP_OUTPUT
    2829 SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "alt.lp") );
    2830#endif
    2831 }
    2832 }
    2833
    2834 return SCIP_OKAY;
    2835}
    2836
    2837
    2838/** check whether the given LP is infeasible
    2839 *
    2840 * If @a primal is false we assume that the problem is <em>dual feasible</em>, e.g., the problem
    2841 * was only changed by fixing bounds!
    2842 *
    2843 * This is the workhorse for all methods that have to solve the alternative LP. We try in several
    2844 * ways to recover from possible stability problems.
    2845 *
    2846 * @pre It is assumed that all parameters for the alternative LP are set.
    2847 */
    2848static
    2850 SCIP* scip, /**< SCIP pointer */
    2851 SCIP_LPI* lp, /**< LP */
    2852 SCIP_Real maxcondition, /**< maximal allowed condition of LP solution basis matrix */
    2853 SCIP_Bool primal, /**< whether we are using the primal or dual simplex */
    2854 SCIP_Bool* infeasible, /**< output: whether the LP is infeasible */
    2855 SCIP_Bool* error /**< output: whether an error occurred */
    2856 )
    2857{
    2858 SCIP_RETCODE retcode;
    2859 SCIP_Real condition;
    2860
    2861 assert( scip != NULL );
    2862 assert( lp != NULL );
    2863 assert( infeasible != NULL );
    2864 assert( error != NULL );
    2865
    2866 *error = FALSE;
    2867
    2868 /* solve LP */
    2869 if ( primal )
    2870 retcode = SCIPlpiSolvePrimal(lp); /* use primal simplex */
    2871 else
    2872 retcode = SCIPlpiSolveDual(lp); /* use dual simplex */
    2873 if ( retcode == SCIP_LPERROR )
    2874 {
    2875 *error = TRUE;
    2876 return SCIP_OKAY;
    2877 }
    2878 SCIP_CALL( retcode );
    2879
    2880 /* resolve if LP is not stable */
    2881 if ( ! SCIPlpiIsStable(lp) )
    2882 {
    2885 SCIPwarningMessage(scip, "Numerical problems, retrying ...\n");
    2886
    2887 /* re-solve LP */
    2888 if ( primal )
    2889 retcode = SCIPlpiSolvePrimal(lp); /* use primal simplex */
    2890 else
    2891 retcode = SCIPlpiSolveDual(lp); /* use dual simplex */
    2892
    2893 /* reset parameters */
    2896
    2897 if ( retcode == SCIP_LPERROR )
    2898 {
    2899 *error = TRUE;
    2900 return SCIP_OKAY;
    2901 }
    2902 SCIP_CALL( retcode );
    2903 }
    2904
    2905 /* check whether we want to ignore the result, because the condition number is too large */
    2906 if ( maxcondition > 0.0 )
    2907 {
    2908 /* check estimated condition number of basis matrix */
    2910 if ( condition != SCIP_INVALID && condition > maxcondition ) /*lint !e777*/
    2911 {
    2912 SCIPdebugMsg(scip, "Estimated condition number of basis matrix (%e) exceeds maximal allowance (%e).\n", condition, maxcondition);
    2913
    2914 *error = TRUE;
    2915
    2916 return SCIP_OKAY;
    2917 }
    2918 else if ( condition != SCIP_INVALID ) /*lint !e777*/
    2919 {
    2920 SCIPdebugMsg(scip, "Estimated condition number of basis matrix (%e) is below maximal allowance (%e).\n", condition, maxcondition);
    2921 }
    2922 else
    2923 {
    2924 SCIPdebugMsg(scip, "Estimated condition number of basis matrix not available.\n");
    2925 }
    2926 }
    2927
    2928 /* check whether we are in the paradoxical situation that
    2929 * - the primal is not infeasible
    2930 * - the primal is not unbounded
    2931 * - the LP is not optimal
    2932 * - we have a primal ray
    2933 *
    2934 * If we ran the dual simplex algorithm, then we run again with the primal simplex
    2935 */
    2937 ! SCIPlpiIsOptimal(lp) && SCIPlpiExistsPrimalRay(lp) && ! primal )
    2938 {
    2939 SCIPwarningMessage(scip, "The dual simplex produced a primal ray. Retrying with primal ...\n");
    2940
    2941 /* the following settings might be changed: */
    2945
    2946 SCIP_CALL( SCIPlpiSolvePrimal(lp) ); /* use primal simplex */
    2947
    2948 /* reset parameters */
    2952 }
    2953
    2954 /* examine LP solution status */
    2955 if ( SCIPlpiIsPrimalInfeasible(lp) ) /* the LP is provably infeasible */
    2956 {
    2957 assert( ! SCIPlpiIsPrimalUnbounded(lp) ); /* can't be unbounded or optimal */
    2958 assert( ! SCIPlpiIsOptimal(lp) ); /* if it is infeasible! */
    2959
    2960 *infeasible = TRUE; /* LP is infeasible */
    2961 return SCIP_OKAY;
    2962 }
    2963 else
    2964 {
    2965 /* By assumption the dual is feasible if the dual simplex is run, therefore
    2966 * the status has to be primal unbounded or optimal. */
    2967 if ( ! SCIPlpiIsPrimalUnbounded(lp) && ! SCIPlpiIsOptimal(lp) )
    2968 {
    2969 /* We have a status different from unbounded or optimal. This should not be the case ... */
    2970 if (primal)
    2971 SCIPwarningMessage(scip, "Primal simplex returned with unknown status: %d\n", SCIPlpiGetInternalStatus(lp));
    2972 else
    2973 SCIPwarningMessage(scip, "Dual simplex returned with unknown status: %d\n", SCIPlpiGetInternalStatus(lp));
    2974
    2975 /* SCIP_CALL( SCIPlpiWriteLP(lp, "debug.lp") ); */
    2976 *error = TRUE;
    2977 return SCIP_OKAY;
    2978 }
    2979 }
    2980
    2981 /* at this point we have a feasible solution */
    2982 *infeasible = FALSE;
    2983 return SCIP_OKAY;
    2984}
    2985
    2986
    2987/** tries to extend a given set of variables to a cover
    2988 *
    2989 * At each step we include a variable which covers a new IIS. The corresponding IIS inequalities are added to the LP,
    2990 * if this not already happened.
    2991 *
    2992 * @pre It is assumed that all parameters for the alternative LP are set and that the variables
    2993 * corresponding to @a S are fixed. Furthermore @c xVal_ should contain the current LP solution.
    2994 */
    2995static
    2997 SCIP* scip, /**< SCIP pointer */
    2998 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2999 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    3000 SCIP_LPI* lp, /**< LP */
    3001 SCIP_SOL* sol, /**< solution to be separated */
    3002 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
    3003 SCIP_Bool removable, /**< whether cuts should be removable */
    3004 SCIP_Bool genlogicor, /**< should logicor constraints be generated? */
    3005 int nconss, /**< number of constraints */
    3006 SCIP_CONS** conss, /**< indicator constraints */
    3007 SCIP_Bool* S, /**< bitset of variables */
    3008 int* size, /**< size of S */
    3009 SCIP_Real* value, /**< objective value of S */
    3010 SCIP_Bool* error, /**< output: whether an error occurred */
    3011 SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
    3012 int* nGen /**< number of generated cuts */
    3013 )
    3014{
    3015#ifdef SCIP_DEBUG
    3016 char name[SCIP_MAXSTRLEN];
    3017#endif
    3018 SCIP_Real* primsol;
    3019 int nnonviolated = 0;
    3020 int step = 0;
    3021 int nCols;
    3022
    3023 assert( scip != NULL );
    3024 assert( lp != NULL );
    3025 assert( conss != NULL );
    3026 assert( S != NULL );
    3027 assert( size != NULL );
    3028 assert( value != NULL );
    3029 assert( error != NULL );
    3030 assert( cutoff != NULL );
    3031 assert( nGen != NULL );
    3032
    3033 *error = FALSE;
    3034 *cutoff = FALSE;
    3035 *nGen = 0;
    3036
    3037 SCIP_CALL( SCIPlpiGetNCols(lp, &nCols) );
    3038 SCIP_CALL( SCIPallocBufferArray(scip, &primsol, nCols) );
    3039 assert( nconss <= nCols );
    3040
    3041 do
    3042 {
    3043 SCIP_Bool infeasible;
    3044 SCIP_Real sum = 0.0;
    3045 SCIP_Real candobj = -1.0;
    3046 SCIP_Real candval = 2.0;
    3047 SCIP_Real norm = 1.0;
    3048 int sizeIIS = 0;
    3049 int candidate = -1;
    3050 int candindex = -1;
    3051 int j;
    3052
    3053 if ( step == 0 )
    3054 {
    3055 /* the first LP is solved without warm start, after that we use a warmstart. */
    3057 SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, TRUE, &infeasible, error) );
    3059 }
    3060 else
    3061 SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, FALSE, &infeasible, error) );
    3062
    3063 if ( *error )
    3064 break;
    3065
    3066 /* if the alternative polyhedron is infeasible, we found a cover */
    3067 if ( infeasible )
    3068 {
    3069 /* Note: checking for a primal solution is done in extendToCover(). */
    3070 SCIPdebugMsg(scip, " size: %4d produced possible cover with indicator variable objective value %f.\n", *size, *value);
    3071
    3072 /* we currently cannot call probing if there are cuts in the sepastore; @todo fix this */
    3073 if ( conshdlrdata->trysolfromcover )
    3074 {
    3075 /* Check whether we want to try to construct a feasible solution: there should be no integer/binary variables
    3076 * except the indicator variables. Thus, there should be no integral variables and the number of indicator
    3077 * variables should be at least (actually equal to) the number of binary variables. */
    3078 if ( SCIPgetNIntVars(scip) == 0 && nconss >= SCIPgetNBinVars(scip) )
    3079 {
    3080 SCIP_HEUR* heurindicator;
    3081
    3082 heurindicator = SCIPfindHeur(scip, "indicator");
    3083 if ( heurindicator == NULL )
    3084 {
    3085 SCIPerrorMessage("Could not find heuristic \"indicator\".\n");
    3086 return SCIP_PLUGINNOTFOUND;
    3087 }
    3088
    3089 SCIP_CALL( SCIPheurPassIndicator(scip, heurindicator, nconss, conss, S, -*value) );
    3090 SCIPdebugMsg(scip, "Passed feasible solution to indicator heuristic.\n");
    3091 }
    3092 }
    3093 break;
    3094 }
    3095
    3096 /* get solution of alternative LP */
    3097 SCIP_CALL( SCIPlpiGetSol(lp, NULL, primsol, NULL, NULL, NULL) );
    3098
    3099 /* get value of cut and find candidate for variable to add */
    3100 for (j = 0; j < nconss; ++j)
    3101 {
    3102 SCIP_CONSDATA* consdata;
    3103 int ind;
    3104
    3105 consdata = SCIPconsGetData(conss[j]);
    3106 assert( consdata != NULL );
    3107 ind = consdata->colindex;
    3108
    3109 if ( ind >= 0 )
    3110 {
    3111 assert( ind < nCols );
    3112
    3113 /* check support of the solution, i.e., the corresponding IIS */
    3114 if ( ! SCIPisFeasZero(scip, primsol[ind]) )
    3115 {
    3116 SCIP_Real val;
    3117
    3118 assert( ! S[j] );
    3119 ++sizeIIS;
    3120 val = SCIPgetSolVal(scip, sol, consdata->binvar);
    3121 sum += val;
    3122
    3123 /* take element with smallest relaxation value */
    3124 if ( val < candval )
    3125 {
    3126 candidate = j;
    3127 candindex = ind;
    3128 candval = val;
    3129 candobj = varGetObjDelta(consdata->binvar);
    3130 }
    3131 }
    3132 }
    3133 }
    3134
    3135 /* check for error */
    3136 if ( candidate < 0 )
    3137 {
    3138 /* Because of numerical problems it might happen that the solution primsol above is zero
    3139 * within the tolerances. In this case we quit. */
    3140 break;
    3141 }
    3142 assert( candidate >= 0 );
    3143 assert( ! S[candidate] );
    3144 assert( sizeIIS > 0 );
    3145
    3146 /* get the type of norm to use for efficacy calculations */
    3147 switch ( conshdlrdata->normtype )
    3148 {
    3149 case 'e':
    3150 norm = sqrt((SCIP_Real) sizeIIS);
    3151 break;
    3152 case 'm':
    3153 norm = 1.0;
    3154 break;
    3155 case 's':
    3156 norm = (SCIP_Real) sizeIIS;
    3157 break;
    3158 case 'd':
    3159 norm = 1.0;
    3160 break;
    3161 default:
    3162 SCIPerrorMessage("Invalid efficacy norm parameter '%c'.\n", conshdlrdata->normtype);
    3163 SCIPABORT();
    3164 norm = 1.0; /*lint !e527*/
    3165 }
    3166
    3167 SCIPdebugMsg(scip, " size: %4d, add var. %4d (obj: %-6g, alt-LP sol: %-8.4f); IIS size: %4d, eff.: %g.\n",
    3168 *size, candidate, candobj, primsol[SCIPconsGetData(conss[candidate])->colindex], sizeIIS, (sum - (SCIP_Real) (sizeIIS - 1))/norm);
    3169
    3170 /* update new set S */
    3171 S[candidate] = TRUE;
    3172 ++(*size);
    3173 *value += candobj;
    3174
    3175 /* fix chosen variable to 0 */
    3176 SCIP_CALL( fixAltLPVariable(lp, candindex) );
    3177
    3178 /* if cut is violated, i.e., sum - sizeIIS + 1 > 0 */
    3179 if ( SCIPisEfficacious(scip, (sum - (SCIP_Real) (sizeIIS - 1))/norm) )
    3180 {
    3181 SCIP_Bool isLocal = FALSE;
    3182
    3183#ifdef SCIP_ENABLE_IISCHECK
    3184 /* check whether we really have an infeasible subsystem */
    3185 SCIP_CALL( checkIIS(scip, nconss, conss, primsol) );
    3186#endif
    3187
    3188 /* check whether IIS corresponds to a local cut */
    3189 if ( conshdlrdata->updatebounds )
    3190 {
    3191 SCIP_CALL( checkIISlocal(scip, conshdlrdata, primsol, &isLocal) );
    3192 }
    3193
    3194 if ( genlogicor )
    3195 {
    3196 SCIP_RESULT result;
    3197 SCIP_CONS* cons;
    3198 SCIP_VAR** vars;
    3199 int cnt = 0;
    3200
    3201 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nconss) );
    3202
    3203 /* collect variables corresponding to support to cut */
    3204 for (j = 0; j < nconss; ++j)
    3205 {
    3206 SCIP_CONSDATA* consdata;
    3207 int ind;
    3208
    3209 consdata = SCIPconsGetData(conss[j]);
    3210 ind = consdata->colindex;
    3211
    3212 if ( ind >= 0 )
    3213 {
    3214 assert( ind < nCols );
    3215 assert( consdata->binvar != NULL );
    3216
    3217 /* check support of the solution, i.e., the corresponding IIS */
    3218 if ( ! SCIPisFeasZero(scip, primsol[ind]) )
    3219 {
    3220 SCIP_VAR* var;
    3221 SCIP_CALL( SCIPgetNegatedVar(scip, consdata->binvar, &var) );
    3222 vars[cnt++] = var;
    3223 }
    3224 }
    3225 }
    3226 assert( cnt == sizeIIS );
    3227
    3228#ifdef SCIP_DEBUG
    3229 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "iis%d", conshdlrdata->niiscutsgen + *nGen);
    3230 SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, name, cnt, vars, FALSE, TRUE, TRUE, TRUE, TRUE, isLocal, FALSE, TRUE, removable, FALSE) );
    3231#else
    3232 SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, "", cnt, vars, FALSE, TRUE, TRUE, TRUE, TRUE, isLocal, FALSE, TRUE, removable, FALSE) );
    3233#endif
    3234
    3235#ifdef SCIP_OUTPUT
    3236 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
    3237 SCIPinfoMessage(scip, NULL, ";\n");
    3238#endif
    3239
    3240 /* enforce or separate logicor constraint to make sure that this has an effect in this round */
    3241 switch ( enfosepatype )
    3242 {
    3243 case SCIP_TYPE_ENFOLP:
    3244 SCIP_CALL( SCIPenfolpCons(scip, cons, FALSE, &result) );
    3245 break;
    3246 case SCIP_TYPE_ENFOPS:
    3247 SCIP_CALL( SCIPenfopsCons(scip, cons, FALSE, FALSE, &result) );
    3248 break;
    3250 SCIP_CALL( SCIPenforelaxCons(scip, cons, sol, FALSE, &result) );
    3251 break;
    3252 case SCIP_TYPE_SEPALP:
    3253 SCIP_CALL( SCIPsepalpCons(scip, cons, &result) );
    3254 break;
    3256 case SCIP_TYPE_SEPASOL:
    3257 SCIP_CALL( SCIPsepasolCons(scip, cons, sol, &result) );
    3258 break;
    3259 default:
    3260 SCIPerrorMessage("Wrong enforcing/separation type.\n");
    3261 SCIPABORT();
    3262 }
    3263
    3264 SCIP_CALL( SCIPaddCons(scip, cons) );
    3265 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    3266
    3267 SCIPfreeBufferArray(scip, &vars);
    3268 ++(*nGen);
    3269 }
    3270 else
    3271 {
    3272 SCIP_ROW* row;
    3273
    3274 /* create row */
    3275#ifdef SCIP_DEBUG
    3276 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "iis%d", conshdlrdata->niiscutsgen + *nGen);
    3277 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, name, -SCIPinfinity(scip), (SCIP_Real) (sizeIIS - 1), isLocal, FALSE, removable) );
    3278#else
    3279 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, "", -SCIPinfinity(scip), (SCIP_Real) (sizeIIS - 1), isLocal, FALSE, removable) );
    3280#endif
    3282
    3283 /* add variables corresponding to support to cut */
    3284 for (j = 0; j < nconss; ++j)
    3285 {
    3286 int ind;
    3287 SCIP_CONSDATA* consdata;
    3288
    3289 consdata = SCIPconsGetData(conss[j]);
    3290 ind = consdata->colindex;
    3291
    3292 if ( ind >= 0 )
    3293 {
    3294 assert( ind < nCols );
    3295 assert( consdata->binvar != NULL );
    3296
    3297 /* check support of the solution, i.e., the corresponding IIS */
    3298 if ( ! SCIPisFeasZero(scip, primsol[ind]) )
    3299 {
    3300 SCIP_VAR* var = consdata->binvar;
    3301 SCIP_CALL( SCIPaddVarToRow(scip, row, var, 1.0) );
    3302 }
    3303 }
    3304 }
    3306#ifdef SCIP_OUTPUT
    3307 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
    3308#endif
    3309 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    3310 if ( *cutoff )
    3311 {
    3312 SCIPfreeBufferArray(scip, &primsol);
    3313 return SCIP_OKAY;
    3314 }
    3315
    3316 /* cut should be violated: */
    3318
    3319 /* add cuts to pool if they are globally valid */
    3320 if ( ! isLocal )
    3321 SCIP_CALL( SCIPaddPoolCut(scip, row) );
    3322 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    3323 ++(*nGen);
    3324 }
    3325 nnonviolated = 0;
    3326 }
    3327 else
    3328 ++nnonviolated;
    3329 ++step;
    3330
    3331 if ( nnonviolated > conshdlrdata->maxsepanonviolated )
    3332 {
    3333 SCIPdebugMsg(scip, "Stop separation after %d non violated IISs.\n", nnonviolated);
    3334 break;
    3335 }
    3336 }
    3337 while (step < nconss);
    3338
    3339 SCIPfreeBufferArray(scip, &primsol);
    3340
    3341 return SCIP_OKAY;
    3342}
    3343
    3344
    3345/* ---------------------------- constraint handler local methods ----------------------*/
    3346
    3347/** creates and initializes consdata */
    3348static
    3350 SCIP* scip, /**< SCIP data structure */
    3351 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    3352 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    3353 const char* consname, /**< name of constraint (or NULL) */
    3354 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
    3355 SCIP_EVENTHDLR* eventhdlrrestart, /**< event handler for handling restarts */
    3356 SCIP_VAR* binvar, /**< binary variable (or NULL) */
    3357 SCIP_Bool activeone, /**< whether the constraint is active on 1 or not */
    3358 SCIP_Bool lessthanineq, /**< whether the original linear constraint is a less-than-rhs (TRUE) or not */
    3359 SCIP_VAR* slackvar, /**< slack variable */
    3360 SCIP_CONS* lincons, /**< linear constraint (or NULL) */
    3361 SCIP_Bool linconsactive /**< whether the linear constraint is active */
    3362 )
    3363{
    3364 SCIP_VAR* binvarinternal;
    3365
    3366 assert( scip != NULL );
    3367 assert( conshdlr != NULL );
    3368 assert( conshdlrdata != NULL );
    3369 assert( consdata != NULL );
    3370 assert( slackvar != NULL );
    3371 assert( eventhdlrrestart != NULL );
    3372
    3373 /* if active on 0, a provided binary variable is negated */
    3374 if ( activeone || binvar == NULL )
    3375 binvarinternal = binvar;
    3376 else
    3377 {
    3378 assert( SCIPvarIsBinary(binvar) );
    3379 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
    3380 }
    3381
    3382 /* create constraint data */
    3383 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
    3384 (*consdata)->nfixednonzero = 0;
    3385 (*consdata)->colindex = -1;
    3386 (*consdata)->linconsactive = linconsactive;
    3387 (*consdata)->binvar = binvarinternal;
    3388 (*consdata)->slackvar = slackvar;
    3389 (*consdata)->activeone = activeone;
    3390 (*consdata)->lessthanineq = lessthanineq;
    3391 (*consdata)->lincons = lincons;
    3392 (*consdata)->implicationadded = FALSE;
    3393 (*consdata)->slacktypechecked = FALSE;
    3394 (*consdata)->varswithevents = NULL;
    3395 (*consdata)->eventtypes = NULL;
    3396 (*consdata)->nevents = 0;
    3397
    3398 /* if we are transformed, obtain transformed variables and catch events */
    3399 if ( SCIPisTransformed(scip) )
    3400 {
    3401 SCIP_VAR* var;
    3402
    3403 /* handle binary variable */
    3404 if ( binvarinternal != NULL )
    3405 {
    3406 SCIP_CALL( SCIPgetTransformedVar(scip, binvarinternal, &var) );
    3407 assert( var != NULL );
    3408 (*consdata)->binvar = var;
    3409
    3410 /* check type */
    3411 if ( !SCIPvarIsBinary(var) || SCIPvarIsImpliedIntegral(var) )
    3412 {
    3413 SCIPerrorMessage("Indicator variable <%s> is not binary %d.\n", SCIPvarGetName(var), SCIPvarGetType(var));
    3414 return SCIP_ERROR;
    3415 }
    3416
    3417 /* the indicator variable must not be multi-aggregated because the constraint handler propagation tries
    3418 * to tighten its bounds, which is not allowed for multi-aggregated variables
    3419 */
    3421
    3422 /* catch global bound change events on binary variable */
    3423 if ( conshdlrdata->forcerestart )
    3424 {
    3425 SCIPdebugMsg(scip, "Catching GBDCHANGED event for <%s>.\n", SCIPvarGetName(var));
    3426 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
    3427 }
    3428
    3429 /* if binary variable is fixed to be nonzero */
    3430 if ( SCIPvarGetLbLocal(var) > 0.5 )
    3431 ++((*consdata)->nfixednonzero);
    3432 }
    3433
    3434 /* handle slack variable */
    3435 SCIP_CALL( SCIPgetTransformedVar(scip, slackvar, &var) );
    3436 assert( var != NULL );
    3437 (*consdata)->slackvar = var;
    3438
    3439 /* catch bound change events on slack variable and adjust nfixednonzero */
    3440 if ( linconsactive )
    3441 {
    3442 /* if slack variable is fixed to be nonzero */
    3444 ++((*consdata)->nfixednonzero);
    3445 }
    3446
    3447 /* add corresponding column to alternative LP if the constraint is new */
    3448 if ( conshdlrdata->sepaalternativelp && SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && lincons != NULL )
    3449 {
    3450 assert( lincons != NULL );
    3451 assert( consname != NULL );
    3452
    3453 SCIP_CALL( addAltLPConstraint(scip, conshdlr, lincons, var, 1.0, &(*consdata)->colindex) );
    3454
    3455 SCIPdebugMsg(scip, "Added column for <%s> to alternative LP with column index %d.\n", consname, (*consdata)->colindex);
    3456#ifdef SCIP_OUTPUT
    3457 SCIP_CALL( SCIPprintCons(scip, lincons, NULL) );
    3458 SCIPinfoMessage(scip, NULL, ";\n");
    3459#endif
    3460 }
    3461
    3462#ifdef SCIP_DEBUG
    3463 if ( (*consdata)->nfixednonzero > 0 )
    3464 {
    3465 SCIPdebugMsg(scip, "Constraint <%s> has %d variables fixed to be nonzero.\n", consname, (*consdata)->nfixednonzero);
    3466 }
    3467#endif
    3468 }
    3469
    3470 return SCIP_OKAY;
    3471}
    3472
    3473
    3474/** create variable upper bounds for constraints */
    3475static
    3477 SCIP* scip, /**< SCIP pointer */
    3478 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    3479 SCIP_CONS** conss, /**< constraints */
    3480 int nconss, /**< number of constraints */
    3481 int* ngen /**< number of successful operations */
    3482 )
    3483{
    3484 char name[50] = "";
    3485 int c;
    3486
    3487 assert( scip != NULL );
    3488 assert( conshdlrdata != NULL );
    3489 assert( ngen != NULL );
    3490
    3491 *ngen = 0;
    3492
    3493 /* check each constraint */
    3494 for (c = 0; c < nconss; ++c)
    3495 {
    3496 SCIP_CONSDATA* consdata;
    3497 SCIP_Real ub;
    3498
    3499 consdata = SCIPconsGetData(conss[c]);
    3500 assert( consdata != NULL );
    3501
    3502 ub = SCIPvarGetUbGlobal(consdata->slackvar);
    3503 assert( ! SCIPisNegative(scip, ub) );
    3504
    3505 /* insert corresponding row if helpful and coefficient is not too large */
    3506 if ( ub <= conshdlrdata->maxcouplingvalue )
    3507 {
    3508 SCIP_CONS* cons;
    3509
    3510#ifndef NDEBUG
    3511 (void) SCIPsnprintf(name, 50, "couple%d", c);
    3512#endif
    3513
    3514 SCIPdebugMsg(scip, "Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
    3515
    3516 /* add variable upper bound:
    3517 * - check constraint if we remove the indicator constraint afterwards
    3518 * - constraint is dynamic if we do not remove indicator constraints
    3519 * - constraint is removable if we do not remove indicator constraints
    3520 */
    3521 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
    3522 TRUE, TRUE, TRUE, conshdlrdata->removeindicators, TRUE, FALSE, FALSE,
    3523 !conshdlrdata->removeindicators, !conshdlrdata->removeindicators, FALSE) );
    3524
    3525 SCIP_CALL( SCIPaddCons(scip, cons) );
    3526 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    3527
    3528 /* remove indicator constraint if required */
    3529 if ( conshdlrdata->removeindicators )
    3530 {
    3531 SCIPdebugMsg(scip, "Removing indicator constraint <%s>.\n", SCIPconsGetName(conss[c]));
    3532 assert( ! SCIPconsIsModifiable(conss[c]) );
    3533 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
    3534 }
    3535
    3536 ++(*ngen);
    3537 }
    3538 }
    3539
    3540 return SCIP_OKAY;
    3541}
    3542
    3543
    3544/** perform one presolving round */
    3545static
    3547 SCIP* scip, /**< SCIP pointer */
    3548 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    3549 SCIP_CONS* cons, /**< constraint */
    3550 SCIP_CONSDATA* consdata, /**< constraint data */
    3551 SCIP_Bool dualreductions, /**< should dual reductions be performed? */
    3552 SCIP_Bool* cutoff, /**< whether a cutoff happened */
    3553 SCIP_Bool* success, /**< whether we performed a successful reduction */
    3554 int* ndelconss, /**< pointer to store the number of deleted constraints */
    3555 int* nfixedvars /**< pointer to store the number of fixed variables */
    3556 )
    3557{
    3558 SCIP_Bool infeasible;
    3559 SCIP_Bool fixed;
    3560
    3561 assert( scip != NULL );
    3562 assert( cons != NULL );
    3563 assert( consdata != NULL );
    3564 assert( cutoff != NULL );
    3565 assert( success != NULL );
    3566 assert( ndelconss != NULL );
    3567 assert( nfixedvars != NULL );
    3568 assert( consdata->binvar != NULL );
    3569 assert( consdata->slackvar != NULL );
    3570
    3571 *cutoff = FALSE;
    3572 *success = FALSE;
    3573
    3574 /* if the binary variable is fixed to nonzero */
    3575 if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
    3576 {
    3577 SCIPdebugMsg(scip, "Presolving <%s>: Binary variable fixed to 1.\n", SCIPconsGetName(cons));
    3578
    3579 /* if slack variable is fixed to nonzero, we are infeasible */
    3580 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
    3581 {
    3582 SCIPdebugMsg(scip, "The problem is infeasible: binary and slack variable are fixed to be nonzero.\n");
    3583 *cutoff = TRUE;
    3584 return SCIP_OKAY;
    3585 }
    3586
    3587 /* otherwise fix slack variable to 0 */
    3588 SCIPdebugMsg(scip, "Fix slack variable to 0 and delete constraint.\n");
    3589 SCIP_CALL( SCIPfixVar(scip, consdata->slackvar, 0.0, &infeasible, &fixed) );
    3590 assert( ! infeasible );
    3591 if ( fixed )
    3592 ++(*nfixedvars);
    3593
    3594 /* delete indicator constraint (leave linear constraint) */
    3595 assert( ! SCIPconsIsModifiable(cons) );
    3596 SCIP_CALL( SCIPdelCons(scip, cons) );
    3597 ++(*ndelconss);
    3598 *success = TRUE;
    3599 return SCIP_OKAY;
    3600 }
    3601
    3602 /* if the binary variable is fixed to zero */
    3603 if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
    3604 {
    3605 SCIPdebugMsg(scip, "Presolving <%s>: Binary variable <%s> fixed to 0, deleting indicator constraint.\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->binvar));
    3606
    3607 /* delete indicator constraint */
    3608 assert( ! SCIPconsIsModifiable(cons) );
    3609 SCIP_CALL( SCIPdelCons(scip, cons) );
    3610 ++(*ndelconss);
    3611 *success = TRUE;
    3612 return SCIP_OKAY;
    3613 }
    3614
    3615 /* if the slack variable is fixed to nonzero */
    3616 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
    3617 {
    3618 SCIPdebugMsg(scip, "Presolving <%s>: Slack variable fixed to nonzero.\n", SCIPconsGetName(cons));
    3619
    3620 /* if binary variable is fixed to nonzero, we are infeasible */
    3621 if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
    3622 {
    3623 SCIPdebugMsg(scip, "The problem is infeasible: binary and slack variable are fixed to be nonzero.\n");
    3624 *cutoff = TRUE;
    3625 return SCIP_OKAY;
    3626 }
    3627
    3628 /* otherwise fix binary variable to 0 */
    3629 SCIPdebugMsg(scip, "Fix binary variable to 0 and delete indicator constraint.\n");
    3630 SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
    3631 assert( ! infeasible );
    3632 if ( fixed )
    3633 ++(*nfixedvars);
    3634
    3635 /* delete constraint */
    3636 assert( ! SCIPconsIsModifiable(cons) );
    3637 SCIP_CALL( SCIPdelCons(scip, cons) );
    3638 ++(*ndelconss);
    3639 *success = TRUE;
    3640 return SCIP_OKAY;
    3641 }
    3642
    3643 /* if the slack variable is fixed to zero */
    3644 if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
    3645 {
    3646 /* perform dual reductions - if required */
    3647 if ( dualreductions )
    3648 {
    3649 SCIP_VAR* binvar;
    3650 SCIP_Real obj;
    3651
    3652 /* check objective of binary variable */
    3653 binvar = consdata->binvar;
    3654 obj = varGetObjDelta(binvar);
    3655
    3656 /* if obj = 0, we prefer fixing the binary variable to 1 (if possible) */
    3657 if ( obj <= 0.0 )
    3658 {
    3659 /* In this case we would like to fix the binary variable to 1, if it is not locked up
    3660 * except by this indicator constraint. If more than one indicator constraint is
    3661 * affected, we have to hope that they are all fulfilled - in this case the last
    3662 * constraint will fix the binary variable to 1. */
    3663 if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
    3664 {
    3665 if ( SCIPvarGetUbGlobal(binvar) > 0.5 )
    3666 {
    3667 SCIPdebugMsg(scip, "Presolving <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
    3668 SCIP_CALL( SCIPfixVar(scip, binvar, 1.0, &infeasible, &fixed) );
    3669 assert( ! infeasible );
    3670 if ( fixed )
    3671 ++(*nfixedvars);
    3672 /* make sure that the other case does not occur */
    3673 obj = -1.0;
    3674 }
    3675 }
    3676 }
    3677
    3678 if ( obj >= 0.0 )
    3679 {
    3680 /* In this case we would like to fix the binary variable to 0, if it is not locked down
    3681 * (should also have been performed by other dual reductions). */
    3683 {
    3684 if ( SCIPvarGetLbGlobal(binvar) < 0.5 )
    3685 {
    3686 SCIPdebugMsg(scip, "Presolving <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
    3687 SCIP_CALL( SCIPfixVar(scip, binvar, 0.0, &infeasible, &fixed) );
    3688 assert( ! infeasible );
    3689 if ( fixed )
    3690 ++(*nfixedvars);
    3691 }
    3692 }
    3693 }
    3694 }
    3695
    3696 SCIPdebugMsg(scip, "Presolving <%s>: Slack variable fixed to zero, delete redundant indicator constraint.\n", SCIPconsGetName(cons));
    3697
    3698 /* delete constraint */
    3699 assert( ! SCIPconsIsModifiable(cons) );
    3700 SCIP_CALL( SCIPdelCons(scip, cons) );
    3701 ++(*ndelconss);
    3702 *success = TRUE;
    3703 return SCIP_OKAY;
    3704 }
    3705
    3706 /* check whether indicator variable is aggregated */
    3707 if ( SCIPvarGetStatus(consdata->binvar) == SCIP_VARSTATUS_AGGREGATED )
    3708 {
    3709 SCIP_Bool negated = FALSE;
    3710 SCIP_VAR* var;
    3711
    3712 /* possibly get representation of indicator variable by active variable */
    3713 var = consdata->binvar;
    3714 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
    3715 assert( var == consdata->binvar || SCIPvarIsActive(var) || SCIPvarIsNegated(var) );
    3716
    3717 /* we can replace the binary variable by the active variable if it is not negated */
    3718 if ( var != consdata->binvar && ! negated )
    3719 {
    3720 SCIPdebugMsg(scip, "Indicator variable <%s> is aggregated and replaced by active/negated variable <%s>.\n", SCIPvarGetName(consdata->binvar), SCIPvarGetName(var) );
    3721
    3722 /* we need to update the events and locks */
    3723 assert( conshdlrdata->eventhdlrbound != NULL );
    3724 SCIP_CALL( SCIPdropVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, -1) );
    3725 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, NULL) );
    3726
    3727 /* We also need to update the events and locks if restart is forced, since global bound change events on binary
    3728 * variables are also caught in this case. If it would not be updated and forcerestart = TRUE, then an event
    3729 * might be dropped on a wrong variable. */
    3730 if ( conshdlrdata->forcerestart )
    3731 {
    3732 assert( conshdlrdata->eventhdlrrestart != NULL );
    3734 conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, -1) );
    3735 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
    3736 (SCIP_EVENTDATA*) conshdlrdata, NULL) );
    3737 }
    3738
    3739 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->binvar, SCIP_LOCKTYPE_MODEL, 0, -1) );
    3741
    3742 /* change binary variable */
    3743 SCIP_CALL( SCIPcaptureVar(scip, var) );
    3744 SCIP_CALL( SCIPreleaseVar(scip, &consdata->binvar) );
    3745 consdata->binvar = var;
    3746 }
    3747 }
    3748 else if ( SCIPvarGetStatus(consdata->binvar) == SCIP_VARSTATUS_NEGATED )
    3749 {
    3750 SCIP_VAR* var;
    3751
    3752 var = SCIPvarGetNegatedVar(consdata->binvar);
    3753 assert( var != NULL );
    3754
    3755 /* if the binary variable is the negated slack variable, we have 1 - s = 1 -> s = 0, i.e., the constraint is redundant */
    3756 if ( var == consdata->slackvar )
    3757 {
    3758 /* delete constraint */
    3759 assert( ! SCIPconsIsModifiable(cons) );
    3760 SCIP_CALL( SCIPdelCons(scip, cons) );
    3761 ++(*ndelconss);
    3762 *success = TRUE;
    3763 return SCIP_OKAY;
    3764 }
    3765 }
    3766
    3767 /* check whether slack variable is aggregated */
    3768 if ( SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_AGGREGATED || SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_NEGATED )
    3769 {
    3772 SCIP_VAR* var;
    3773
    3774 /* possibly get representation of slack variable by active variable */
    3775 var = consdata->slackvar;
    3777
    3778 SCIP_CALL( SCIPvarGetProbvarBound(&var, &bound, &boundtype) );
    3779 assert( var != consdata->slackvar );
    3780
    3781 /* we can replace the slack variable by the active variable if it is also a >= variable */
    3782 if ( var != consdata->binvar && boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisEQ(scip, bound, 0.0) )
    3783 {
    3784 assert( SCIPvarIsActive(var) );
    3785 SCIPdebugMsg(scip, "Slack variable <%s> is aggregated or negated and replaced by active variable <%s>.\n", SCIPvarGetName(consdata->slackvar), SCIPvarGetName(var) );
    3786
    3787 /* we need to update the events, locks, and captures */
    3788 assert( conshdlrdata->eventhdlrbound != NULL );
    3789 SCIP_CALL( SCIPdropVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, -1) );
    3790 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, NULL) );
    3791
    3792 SCIP_CALL( SCIPunlockVarCons(scip, consdata->slackvar, cons, FALSE, TRUE) );
    3793 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
    3794
    3795 SCIP_CALL( SCIPreleaseVar(scip, &consdata->slackvar) );
    3796 SCIP_CALL( SCIPcaptureVar(scip, var) );
    3797
    3798 /* change slack variable */
    3799 consdata->slackvar = var;
    3800 }
    3801 else if ( var == consdata->binvar )
    3802 {
    3803 /* check special case that aggregating variable is equal to the indicator variable */
    3804 assert( SCIPisEQ(scip, bound, 0.0) || SCIPisEQ(scip, bound, 1.0) );
    3805
    3806 /* if the lower bound is transformed to an upper bound, we have "y = 1 -> 1 - y = 0", i.e., the constraint is redundant */
    3807 if ( boundtype == SCIP_BOUNDTYPE_UPPER )
    3808 {
    3809 SCIPdebugMsg(scip, "Slack variable <%s> is aggregated to negated indicator variable <%s> -> constraint redundant.\n",
    3810 SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
    3811 assert( SCIPisEQ(scip, bound, 1.0) );
    3812
    3813 /* delete constraint */
    3814 assert( ! SCIPconsIsModifiable(cons) );
    3815 SCIP_CALL( SCIPdelCons(scip, cons) );
    3816 ++(*ndelconss);
    3817 *success = TRUE;
    3818 return SCIP_OKAY;
    3819 }
    3820 else
    3821 {
    3822 /* if the lower bound is transformed to a lower bound, we have "y = 1 -> y = 0", i.e., we can fix the binary variable to 0 */
    3823 SCIPdebugMsg(scip, "Slack variable <%s> is aggregated to the indicator variable <%s> -> fix indicator variable to 0.\n",
    3824 SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
    3825 assert( boundtype == SCIP_BOUNDTYPE_LOWER );
    3826 assert( SCIPisEQ(scip, bound, 0.0) );
    3827
    3828 SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
    3829 assert( ! infeasible );
    3830
    3831 if ( fixed )
    3832 ++(*nfixedvars);
    3833
    3834 SCIP_CALL( SCIPdelCons(scip, cons) );
    3835
    3836 ++(*ndelconss);
    3837 *success = TRUE;
    3838
    3839 return SCIP_OKAY;
    3840 }
    3841 }
    3842 }
    3843
    3844 /* Note that because of possible multi-aggregation we cannot simply remove the indicator
    3845 * constraint if the linear constraint is not active or disabled - see the note in @ref
    3846 * PREPROC. */
    3847
    3848 return SCIP_OKAY;
    3849}
    3850
    3851
    3852/** propagate indicator constraint */
    3853static
    3855 SCIP* scip, /**< SCIP pointer */
    3856 SCIP_CONS* cons, /**< constraint */
    3857 SCIP_CONSDATA* consdata, /**< constraint data */
    3858 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    3859 SCIP_Bool dualreductions, /**< should dual reductions be performed? */
    3860 SCIP_Bool addopposite, /**< add opposite inequalities if binary var = 0? */
    3861 SCIP_Bool* cutoff, /**< whether a cutoff happened */
    3862 int* nGen /**< number of domain changes */
    3863 )
    3864{
    3865 SCIP_Bool infeasible;
    3866 SCIP_Bool tightened;
    3867
    3868 assert( scip != NULL );
    3869 assert( cons != NULL );
    3870 assert( consdata != NULL );
    3871 assert( cutoff != NULL );
    3872 assert( nGen != NULL );
    3873
    3874 *cutoff = FALSE;
    3875 *nGen = 0;
    3876
    3877 /* if the linear constraint has not been generated, we do nothing */
    3878 if ( ! consdata->linconsactive )
    3879 return SCIP_OKAY;
    3880
    3881 assert( consdata->slackvar != NULL );
    3882 assert( consdata->binvar != NULL );
    3883 assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(consdata->slackvar), 0.0) );
    3884
    3885 /* increase age of constraint; age will be reset to zero, if a conflict or a propagation was found */
    3886 if ( ! SCIPinRepropagation(scip) )
    3887 {
    3888 SCIP_CALL( SCIPincConsAge(scip, cons) );
    3889 }
    3890
    3891 /* if both slackvar and binvar are fixed to be nonzero */
    3892 if ( consdata->nfixednonzero > 1 )
    3893 {
    3894 SCIPdebugMsg(scip, "The node is infeasible, both the slack variable and the binary variable are fixed to be nonzero.\n");
    3895 *cutoff = TRUE;
    3896
    3898 assert( SCIPvarGetLbLocal(consdata->binvar) > 0.5 );
    3899 assert( SCIPisPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) );
    3900
    3901 /* check if conflict analysis is turned on */
    3903 return SCIP_OKAY;
    3904
    3905 /* conflict analysis can only be applied in solving stage */
    3907
    3908 /* perform conflict analysis */
    3910
    3911 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->binvar) );
    3912 SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, NULL) );
    3914
    3915 return SCIP_OKAY;
    3916 }
    3917
    3918 /* if exactly one of the variables is fixed to be nonzero */
    3919 if ( consdata->nfixednonzero == 1 )
    3920 {
    3921 /* if binvar is fixed to be nonzero */
    3922 if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
    3923 {
    3924 assert( SCIPvarGetStatus(consdata->slackvar) != SCIP_VARSTATUS_MULTAGGR );
    3925
    3926 /* if slack variable is not already fixed to 0 */
    3927 if ( ! SCIPisZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
    3928 {
    3929 SCIPdebugMsg(scip, "Binary variable <%s> is fixed to be nonzero, fixing slack variable <%s> to 0.\n",
    3930 SCIPvarGetName(consdata->binvar), SCIPvarGetName(consdata->slackvar));
    3931
    3932 /* fix slack variable to 0 */
    3933 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->slackvar, 0.0, cons, 0, FALSE, &infeasible, &tightened) );
    3934 assert( ! infeasible );
    3935 if ( tightened )
    3936 ++(*nGen);
    3937 }
    3938 }
    3939
    3940 /* if slackvar is fixed to be nonzero */
    3941 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
    3942 {
    3943 /* if binary variable is not yet fixed to 0 */
    3944 if ( SCIPvarGetUbLocal(consdata->binvar) > 0.5 )
    3945 {
    3946 SCIPdebugMsg(scip, "Slack variable <%s> is fixed to be nonzero, fixing binary variable <%s> to 0.\n",
    3947 SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
    3948
    3949 /* fix binary variable to 0 */
    3950 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->binvar, 0.0, cons, 1, FALSE, &infeasible, &tightened) );
    3951 assert( ! infeasible );
    3952 if ( tightened )
    3953 ++(*nGen);
    3954 }
    3955 }
    3956
    3957 /* remove constraint if we are not in probing */
    3958 if ( ! SCIPinProbing(scip) )
    3959 {
    3960 /* delete constraint locally */
    3961 assert( ! SCIPconsIsModifiable(cons) );
    3963 }
    3964 }
    3965 else
    3966 {
    3967 /* if the binary variable is fixed to zero */
    3968 if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
    3969 {
    3970 if ( addopposite && consdata->linconsactive )
    3971 {
    3972 char name[SCIP_MAXSTRLEN];
    3973 SCIP_CONS* reversecons;
    3974 SCIP_VAR** linvars;
    3975 SCIP_Real* linvals;
    3976 SCIP_Bool allintegral = TRUE;
    3977 SCIP_VAR* slackvar;
    3978 SCIP_VAR** vars;
    3979 SCIP_Real* vals;
    3980 SCIP_Real lhs;
    3981 SCIP_Real rhs;
    3982 int nlinvars;
    3983 int nvars = 0;
    3984 int j;
    3985
    3986 /* determine lhs/rhs (first exchange lhs/rhs) */
    3987 lhs = SCIPgetRhsLinear(scip, consdata->lincons);
    3988 if ( SCIPisInfinity(scip, lhs) )
    3989 lhs = -SCIPinfinity(scip);
    3990 rhs = SCIPgetLhsLinear(scip, consdata->lincons);
    3991 if ( SCIPisInfinity(scip, -rhs) )
    3992 rhs = SCIPinfinity(scip);
    3993
    3994 assert( ! SCIPisInfinity(scip, lhs) );
    3995 assert( ! SCIPisInfinity(scip, -rhs) );
    3996
    3997 /* consider only finite lhs/rhs */
    3998 if ( ! SCIPisInfinity(scip, -lhs) || ! SCIPisInfinity(scip, rhs) )
    3999 {
    4000 /* ignore equations (cannot add opposite constraint) */
    4001 if ( ! SCIPisEQ(scip, lhs, rhs) )
    4002 {
    4003 assert( consdata->lincons != NULL );
    4004 nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    4005 linvars = SCIPgetVarsLinear(scip, consdata->lincons);
    4006 linvals = SCIPgetValsLinear(scip, consdata->lincons);
    4007 slackvar = consdata->slackvar;
    4008 assert( slackvar != NULL );
    4009
    4010 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlinvars) );
    4011 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlinvars) );
    4012
    4013 /* copy data and check whether the linear constraint is integral */
    4014 for (j = 0; j < nlinvars; ++j)
    4015 {
    4016 if ( linvars[j] != slackvar )
    4017 {
    4018 if (! SCIPvarIsIntegral(linvars[j]) || ! SCIPisIntegral(scip, linvals[j]) )
    4019 allintegral = FALSE;
    4020
    4021 vars[nvars] = linvars[j];
    4022 vals[nvars++] = linvals[j];
    4023 }
    4024 }
    4025 assert( nlinvars == nvars + 1 );
    4026
    4027 /* possibly adjust lhs/rhs */
    4028 if ( allintegral && ! SCIPisInfinity(scip, REALABS(lhs)) )
    4029 lhs += 1.0;
    4030
    4031 if ( allintegral && ! SCIPisInfinity(scip, REALABS(rhs)) )
    4032 rhs -= 1.0;
    4033
    4034 /* create reverse constraint */
    4035 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "reverse_%s", SCIPconsGetName(consdata->lincons));
    4036
    4037 /* constraint is initial, separated, not enforced, not checked, propagated, local, not modifiable, dynamic, removable */
    4038 SCIP_CALL( SCIPcreateConsLinear(scip, &reversecons, name, nvars, vars, vals, lhs, rhs,
    4040
    4041 SCIPdebugMsg(scip, "Binary variable <%s> fixed to 0. Adding opposite linear inequality.\n", SCIPvarGetName(consdata->binvar));
    4042 SCIPdebugPrintCons(scip, reversecons, NULL);
    4043
    4044 /* add constraint */
    4045 SCIP_CALL( SCIPaddCons(scip, reversecons) );
    4046 SCIP_CALL( SCIPreleaseCons(scip, &reversecons) );
    4047
    4048 SCIPfreeBufferArray(scip, &vals);
    4049 SCIPfreeBufferArray(scip, &vars);
    4050 }
    4051 }
    4052 }
    4053
    4054 /* remove constraint if we are not in probing */
    4055 if ( ! SCIPinProbing(scip) )
    4056 {
    4057 /* delete constraint locally */
    4058 assert( ! SCIPconsIsModifiable(cons) );
    4060 }
    4061 }
    4062 /* if the slack variable is fixed to zero */
    4063 else if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
    4064 {
    4065 /* perform dual reduction - if required */
    4066 if ( dualreductions )
    4067 {
    4068 SCIP_VAR* binvar;
    4069 SCIP_Real obj;
    4070
    4071 /* check objective of binary variable */
    4072 binvar = consdata->binvar;
    4073 obj = varGetObjDelta(binvar);
    4074
    4075 /* if obj = 0, we prefer setting the binary variable to 1 (if possible) */
    4076 if ( obj <= 0.0 )
    4077 {
    4078 /* In this case we would like to fix the binary variable to 1, if it is not locked up
    4079 * except by this indicator constraint. If more than one indicator constraint is
    4080 * affected, we have to hope that they are all fulfilled - in this case the last
    4081 * constraint will fix the binary variable to 1. */
    4082 if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
    4083 {
    4084 if ( SCIPvarGetUbLocal(binvar) > 0.5 )
    4085 {
    4086 SCIPdebugMsg(scip, "Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
    4087 SCIP_CALL( SCIPinferVarLbCons(scip, binvar, 1.0, cons, 2, FALSE, &infeasible, &tightened) );
    4088 assert( ! infeasible );
    4089 if ( tightened )
    4090 ++(*nGen);
    4091 /* Make sure that the other case does not occur, since we are not sure whether SCIPinferVarLbCons() directly changes the bounds. */
    4092 obj = -1.0;
    4093 }
    4094 }
    4095 }
    4096
    4097 if ( obj >= 0.0 )
    4098 {
    4099 /* In this case we would like to fix the binary variable to 0, if it is not locked down
    4100 * (should also have been performed by other dual reductions). */
    4102 {
    4103 if ( SCIPvarGetLbLocal(binvar) < 0.5 )
    4104 {
    4105 SCIPdebugMsg(scip, "Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
    4106 SCIP_CALL( SCIPinferVarUbCons(scip, binvar, 0.0, cons, 2, FALSE, &infeasible, &tightened) );
    4107 assert( ! infeasible );
    4108 if ( tightened )
    4109 ++(*nGen);
    4110 }
    4111 }
    4112 }
    4113 }
    4114
    4115 SCIPdebugMsg(scip, "Slack variable fixed to zero, delete redundant indicator constraint <%s>.\n", SCIPconsGetName(cons));
    4116
    4117 /* delete constraint */
    4118 assert( ! SCIPconsIsModifiable(cons) );
    4119
    4120 /* remove constraint if we are not in probing */
    4121 if ( ! SCIPinProbing(scip) )
    4122 {
    4124 }
    4125 }
    4126
    4127 /* Note that because of possible multi-aggregation we cannot simply remove the indicator
    4128 * constraint if the linear constraint is not active or disabled - see the note in @ref
    4129 * PREPROC and consPresolIndicator(). Moreover, it would drastically increase memory
    4130 * consumption, because the linear constraints have to be stored in each node. */
    4131 }
    4132
    4133 /* propagate maximal activity of linear constraint to upper bound of slack variable
    4134 *
    4135 * It is especially worth to tighten the upper bound if it is greater than maxcouplingvalue or sepacouplingvalue.
    4136 * But do not tighten it if slackvar is locked down by other constraints,
    4137 * or if it has a nonzero coefficient in the objective function.
    4138 *
    4139 * ax - c * s <= rhs -> s <= (maxActivity(ax) - rhs) / c;
    4140 */
    4141 if ( (SCIPvarGetUbLocal(consdata->slackvar) > conshdlrdata->maxcouplingvalue
    4142 || SCIPvarGetUbLocal(consdata->slackvar) > conshdlrdata->sepacouplingvalue)
    4143 && SCIPvarGetNLocksDownType(consdata->slackvar, SCIP_LOCKTYPE_MODEL) <= 1
    4144 && SCIPvarGetObj(consdata->slackvar) == 0.0 && SCIPconsIsActive(consdata->lincons) )
    4145 {
    4146 SCIP_VAR** linconsvars;
    4147 SCIP_Real* linconsvals;
    4148 SCIP_Real maxactivity = 0.0;
    4149 SCIP_Real coeffslack = SCIP_INVALID; /* -c */
    4150 SCIP_Real newub;
    4151 SCIP_Real rhs;
    4152 int nlinconsvars;
    4153 int j;
    4154
    4155 nlinconsvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    4156 linconsvars = SCIPgetVarsLinear(scip, consdata->lincons);
    4157 linconsvals = SCIPgetValsLinear(scip, consdata->lincons);
    4158
    4159 /* calculate maximal activity of linear constraint without slackvar */
    4160 for (j = 0; j < nlinconsvars; ++j)
    4161 {
    4162 SCIP_VAR* var;
    4163 SCIP_Real val;
    4165
    4166 val = linconsvals[j];
    4167 assert( ! SCIPisZero(scip, val) );
    4168
    4169 var = linconsvars[j];
    4170 assert( var != NULL );
    4171
    4172 /* store slackvar coefficient */
    4173 if ( var == consdata->slackvar )
    4174 {
    4175 coeffslack = val;
    4176 continue;
    4177 }
    4178
    4179 if ( val > 0.0 )
    4180 bound = SCIPvarGetUbLocal(var);
    4181 else
    4182 bound = SCIPvarGetLbLocal(var);
    4183
    4185 {
    4186 maxactivity = SCIPinfinity(scip);
    4187 break;
    4188 }
    4189 else
    4190 maxactivity += val * bound;
    4191 }
    4192
    4193 /* continue only if maxactivity is not infinity */
    4194 if ( !SCIPisInfinity(scip, maxactivity) && coeffslack != SCIP_INVALID && coeffslack < 0.0 ) /*lint !e777*/
    4195 {
    4196 rhs = SCIPgetRhsLinear(scip, consdata->lincons);
    4197
    4198 /* continue if rhs is not finite; happens, e.g., if variables are multiaggregated; we would need the minimal activity in this case */
    4199 if ( !SCIPisInfinity(scip, rhs) )
    4200 {
    4201 /* divide by coeff of slackvar */
    4202 newub = (maxactivity - rhs) / (-1.0 * coeffslack);
    4203 assert( !SCIPisInfinity(scip, newub) );
    4204
    4205 /* adjust bound if slackvar is (implicit) integer */
    4206 newub = SCIPadjustedVarUb(scip, consdata->slackvar, newub);
    4207
    4208 if ( SCIPisFeasLT(scip, newub, SCIPvarGetUbLocal(consdata->slackvar))
    4209 && newub > SCIPvarGetLbLocal(consdata->slackvar) )
    4210 {
    4211 SCIPdebugMsg(scip, "Adjusting upper bound of slack variable <%s> to %g for indicator constraint <%s>.\n",
    4212 SCIPvarGetName(consdata->slackvar), newub, SCIPconsGetName(cons));
    4213
    4214 /* propagate bound */
    4215 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->slackvar, newub, cons, 3, FALSE, &infeasible, &tightened) );
    4216 assert( !infeasible );
    4217 if ( tightened )
    4218 ++(*nGen);
    4219 }
    4220 }
    4221 }
    4222 }
    4223
    4224 /* reset constraint age counter */
    4225 if ( *nGen > 0 )
    4226 {
    4228 }
    4229
    4230 return SCIP_OKAY;
    4231}
    4232
    4233
    4234/** enforcement method that produces cuts if possible
    4235 *
    4236 * This is a variant of the enforcement method that generates cuts/constraints via the alternative
    4237 * LP, if possible.
    4238 */
    4239static
    4241 SCIP* scip, /**< SCIP pointer */
    4242 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4243 int nconss, /**< number of constraints */
    4244 SCIP_CONS** conss, /**< indicator constraints */
    4245 SCIP_SOL* sol, /**< solution to be enforced */
    4246 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
    4247 SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
    4248 SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
    4249 int* nGen /**< number of cuts generated */
    4250 )
    4251{
    4252 SCIP_CONSHDLRDATA* conshdlrdata;
    4253 SCIP_LPI* lp;
    4254 SCIP_Bool* S;
    4255 SCIP_Real value = 0.0;
    4256 SCIP_Bool error;
    4257 int size = 0;
    4258 int nCuts;
    4259 int j;
    4260
    4261 assert( scip != NULL );
    4262 assert( conshdlr != NULL );
    4263 assert( conss != NULL );
    4264 assert( cutoff != NULL );
    4265 assert( nGen != NULL );
    4266
    4267 SCIPdebugMsg(scip, "Enforcing via cuts ...\n");
    4268 *cutoff = FALSE;
    4269 *nGen = 0;
    4270
    4271 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4272 assert( conshdlrdata != NULL );
    4273 lp = conshdlrdata->altlp;
    4274 assert( lp != NULL );
    4275
    4276#ifndef NDEBUG
    4277 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    4278#endif
    4279
    4280 /* change coefficients of bounds in alternative LP */
    4281 if ( conshdlrdata->updatebounds )
    4282 SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
    4283
    4284 /* possibly update upper bound */
    4285 SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
    4286
    4287 /* scale first row if necessary */
    4288 SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
    4289
    4290 /* set objective function to current solution */
    4291 SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
    4292
    4293 SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
    4294
    4295 /* set up variables fixed to 1 */
    4296 for (j = 0; j < nconss; ++j)
    4297 {
    4298 SCIP_CONSDATA* consdata;
    4299
    4300 assert( conss[j] != NULL );
    4301 consdata = SCIPconsGetData(conss[j]);
    4302 assert( consdata != NULL );
    4303
    4304 assert( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
    4305 if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
    4306 {
    4307 ++size;
    4308 value += varGetObjDelta(consdata->binvar);
    4309 S[j] = TRUE;
    4310 }
    4311 else
    4312 S[j] = FALSE;
    4313 }
    4314
    4315 /* fix the variables in S */
    4316 SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
    4317
    4318 /* extend set S to a cover and generate cuts */
    4319 error = FALSE;
    4320 SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, genlogicor, nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
    4321 *nGen = nCuts;
    4322
    4323 /* return with an error if no cuts have been produced and and error occurred in extendToCover() */
    4324 if ( nCuts == 0 && error )
    4325 return SCIP_LPERROR;
    4326
    4327 SCIPdebugMsg(scip, "Generated %d IIS-cuts.\n", nCuts);
    4328
    4329 /* reset bounds */
    4330 SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
    4331
    4332#ifndef NDEBUG
    4333 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    4334#endif
    4335
    4337
    4338 return SCIP_OKAY;
    4339}
    4340
    4341
    4342/** enforcement method
    4343 *
    4344 * We check whether the current solution is feasible, i.e., if binvar = 1
    4345 * implies that slackvar = 0. If not, we branch as follows:
    4346 *
    4347 * In one branch we fix binvar = 1 and slackvar = 0. In the other branch
    4348 * we fix binvar = 0 and leave slackvar unchanged.
    4349 */
    4350static
    4352 SCIP* scip, /**< SCIP pointer */
    4353 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4354 int nconss, /**< number of constraints */
    4355 SCIP_CONS** conss, /**< indicator constraints */
    4356 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
    4357 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
    4358 SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
    4359 SCIP_RESULT* result /**< result */
    4360 )
    4361{
    4362 SCIP_CONSHDLRDATA* conshdlrdata;
    4363 SCIP_CONSDATA* consdata;
    4364 SCIP_NODE* node1;
    4365 SCIP_NODE* node2;
    4366 SCIP_VAR* slackvar;
    4367 SCIP_VAR* binvar;
    4369 SCIP_Real maxSlack = -1.0;
    4370 SCIP_Bool someLinconsNotActive = FALSE;
    4371 SCIP_Bool dualreductions;
    4372 int c;
    4373
    4374 assert( scip != NULL );
    4375 assert( conshdlr != NULL );
    4376 assert( conss != NULL );
    4377 assert( result != NULL );
    4378
    4379 *result = SCIP_FEASIBLE;
    4380
    4381 SCIPdebugMsg(scip, "Enforcing indicator constraints for <%s> ...\n", SCIPconshdlrGetName(conshdlr) );
    4382
    4383 /* get constraint handler data */
    4384 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4385 assert( conshdlrdata != NULL );
    4386
    4387 dualreductions = conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip);
    4388
    4389 /* check each constraint */
    4390 for (c = 0; c < nconss; ++c)
    4391 {
    4392 SCIP_Bool cutoff;
    4393 SCIP_Real valSlack;
    4394 int cnt;
    4395
    4396 assert( conss[c] != NULL );
    4397 consdata = SCIPconsGetData(conss[c]);
    4398 assert( consdata != NULL );
    4399 assert( consdata->lincons != NULL );
    4400
    4401 /* if the linear constraint has not been generated, we do nothing */
    4402 if ( ! consdata->linconsactive )
    4403 {
    4404 someLinconsNotActive = TRUE;
    4405 continue;
    4406 }
    4407
    4408 /* first perform propagation (it might happen that standard propagation is turned off) */
    4409 SCIP_CALL( propIndicator(scip, conss[c], consdata, conshdlrdata, dualreductions, conshdlrdata->addopposite, &cutoff, &cnt) );
    4410 if ( cutoff )
    4411 {
    4412 SCIPdebugMsg(scip, "Propagation in enforcing <%s> detected cutoff.\n", SCIPconsGetName(conss[c]));
    4413 *result = SCIP_CUTOFF;
    4414 return SCIP_OKAY;
    4415 }
    4416 if ( cnt > 0 )
    4417 {
    4418 SCIPdebugMsg(scip, "Propagation in enforcing <%s> reduced domains: %d.\n", SCIPconsGetName(conss[c]), cnt);
    4419 *result = SCIP_REDUCEDDOM;
    4420 return SCIP_OKAY;
    4421 }
    4422
    4423 /* check whether constraint is infeasible */
    4424 binvar = consdata->binvar;
    4425 valSlack = SCIPgetSolVal(scip, sol, consdata->slackvar);
    4426 assert( ! SCIPisFeasNegative(scip, valSlack) );
    4427 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, binvar)) && ! SCIPisFeasZero(scip, valSlack) )
    4428 {
    4429 /* binary variable is not fixed - otherwise we would not be infeasible */
    4430 assert( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 );
    4431
    4432 if ( valSlack > maxSlack )
    4433 {
    4434 maxSlack = valSlack;
    4435 branchCons = conss[c];
    4436#ifdef SCIP_OUTPUT
    4437 SCIPinfoMessage(scip, NULL, "Violated indicator constraint:\n");
    4438 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
    4439 SCIPinfoMessage(scip, NULL, ";\n");
    4440 SCIPinfoMessage(scip, NULL, "Corresponding linear constraint:\n");
    4441 SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
    4442 SCIPinfoMessage(scip, NULL, ";\n");
    4443#endif
    4444 }
    4445 }
    4446 }
    4447
    4448 /* if some constraint has a linear constraint that is not active, we need to check feasibility via the alternative polyhedron */
    4449 if ( (someLinconsNotActive || conshdlrdata->enforcecuts) && conshdlrdata->sepaalternativelp )
    4450 {
    4451 SCIP_Bool cutoff;
    4452 int ngen;
    4453
    4454 SCIP_CALL( enforceCuts(scip, conshdlr, nconss, conss, sol, enfosepatype, genlogicor, &cutoff, &ngen) );
    4455 if ( cutoff )
    4456 {
    4457 conshdlrdata->niiscutsgen += ngen;
    4458 *result = SCIP_CUTOFF;
    4459 return SCIP_OKAY;
    4460 }
    4461
    4462 if ( ngen > 0 )
    4463 {
    4464 conshdlrdata->niiscutsgen += ngen;
    4465 if ( genlogicor )
    4466 {
    4467 SCIPdebugMsg(scip, "Generated %d constraints.\n", ngen);
    4468 *result = SCIP_CONSADDED;
    4469 }
    4470 else
    4471 {
    4472 SCIPdebugMsg(scip, "Generated %d cuts.\n", ngen);
    4473 *result = SCIP_SEPARATED;
    4474 }
    4475 return SCIP_OKAY;
    4476 }
    4477 SCIPdebugMsg(scip, "Enforcing produced no cuts.\n");
    4478
    4479 assert( ! someLinconsNotActive || branchCons == NULL );
    4480 }
    4481
    4482 /* if all constraints are feasible */
    4483 if ( branchCons == NULL )
    4484 {
    4485 SCIPdebugMsg(scip, "All indicator constraints are feasible.\n");
    4486 return SCIP_OKAY;
    4487 }
    4488
    4489 /* skip branching if required */
    4490 if ( ! conshdlrdata->branchindicators )
    4491 {
    4492 *result = SCIP_INFEASIBLE;
    4493 return SCIP_OKAY;
    4494 }
    4495
    4496 /* otherwise create branches */
    4497 SCIPdebugMsg(scip, "Branching on constraint <%s> (slack value: %f).\n", SCIPconsGetName(branchCons), maxSlack);
    4498 consdata = SCIPconsGetData(branchCons);
    4499 assert( consdata != NULL );
    4500 binvar = consdata->binvar;
    4501 slackvar = consdata->slackvar;
    4502
    4503 /* node1: binvar = 1, slackvar = 0 */
    4504 SCIP_CALL( SCIPcreateChild(scip, &node1, 0.0, SCIPcalcChildEstimate(scip, binvar, 1.0) ) );
    4505
    4506 if ( SCIPvarGetLbLocal(binvar) < 0.5 )
    4507 {
    4508 SCIP_CALL( SCIPchgVarLbNode(scip, node1, binvar, 1.0) );
    4509 }
    4510
    4511 /* if slack-variable is multi-aggregated */
    4512 assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
    4513 if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(slackvar)) )
    4514 {
    4515 SCIP_CALL( SCIPchgVarUbNode(scip, node1, slackvar, 0.0) );
    4516 }
    4517
    4518 /* node2: binvar = 0, no restriction on slackvar */
    4519 SCIP_CALL( SCIPcreateChild(scip, &node2, 0.0, SCIPcalcChildEstimate(scip, binvar, 0.0) ) );
    4520
    4521 if ( SCIPvarGetUbLocal(binvar) > 0.5 )
    4522 {
    4523 SCIP_CALL( SCIPchgVarUbNode(scip, node2, binvar, 0.0) );
    4524 }
    4525
    4527 *result = SCIP_BRANCHED;
    4528
    4529 return SCIP_OKAY;
    4530}
    4531
    4532
    4533/** separate IIS-cuts via rounding
    4534 *
    4535 * @todo Check whether the cover produced at the end is a feasible solution.
    4536 */
    4537static
    4539 SCIP* scip, /**< SCIP pointer */
    4540 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4541 SCIP_SOL* sol, /**< solution to be separated */
    4542 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
    4543 int nconss, /**< number of constraints */
    4544 SCIP_CONS** conss, /**< indicator constraints */
    4545 int maxsepacuts, /**< maximal number of cuts to be generated */
    4546 SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
    4547 int* nGen /**< number of domain changes */
    4548 )
    4549{ /*lint --e{850}*/
    4550 SCIP_CONSHDLRDATA* conshdlrdata;
    4551 SCIP_LPI* lp;
    4552 int rounds;
    4553 SCIP_Real threshold;
    4554 SCIP_Bool* S;
    4555 SCIP_Bool error;
    4556 int oldsize = -1;
    4557 SCIPdebug( int nGenOld = *nGen; )
    4558
    4559 assert( scip != NULL );
    4560 assert( conshdlr != NULL );
    4561 assert( conss != NULL );
    4562 assert( cutoff != NULL );
    4563 assert( nGen != NULL );
    4564
    4565 if ( *nGen >= maxsepacuts )
    4566 return SCIP_OKAY;
    4567
    4568 *cutoff = FALSE;
    4569 rounds = 0;
    4570
    4571 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4572 assert( conshdlrdata != NULL );
    4573 lp = conshdlrdata->altlp;
    4574 assert( lp != NULL );
    4575
    4576 SCIPdebugMsg(scip, "Separating IIS-cuts by rounding ...\n");
    4577
    4578#ifndef NDEBUG
    4579 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    4580#endif
    4581
    4582 /* change coefficients of bounds in alternative LP */
    4583 if ( conshdlrdata->updatebounds )
    4584 {
    4585 /* update to local bounds */
    4586 SCIP_CALL( updateFirstRow(scip, conshdlrdata) );
    4587 }
    4588
    4589 /* possibly update upper bound */
    4590 SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
    4591
    4592 /* scale first row if necessary */
    4593 SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
    4594
    4595 /* set objective function to current solution */
    4596 SCIP_CALL( setAltLPObj(scip, lp, sol, nconss, conss) );
    4597
    4598 SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
    4599
    4600 /* loop through the possible thresholds */
    4601 for (threshold = conshdlrdata->roundingmaxthres;
    4602 rounds < conshdlrdata->maxroundingrounds && threshold >= conshdlrdata->roundingminthres && *nGen < maxsepacuts && ! (*cutoff);
    4603 threshold -= conshdlrdata->roundingoffset )
    4604 {
    4605 SCIP_Real value = 0.0;
    4606 int size = 0;
    4607 int nCuts = 0;
    4608 int j;
    4609#ifdef SCIP_DEBUG
    4610 int nvarsone = 0;
    4611 int nvarszero = 0;
    4612 int nvarsfrac = 0;
    4613#endif
    4614
    4615 SCIPdebugMsg(scip, "Threshold: %g.\n", threshold);
    4616
    4617 /* choose variables that have a value < current threshold value */
    4618 for (j = 0; j < nconss; ++j)
    4619 {
    4620 SCIP_CONSDATA* consdata;
    4621 SCIP_Real binvarval;
    4622 SCIP_VAR* binvarneg;
    4623
    4624 assert( conss[j] != NULL );
    4625 consdata = SCIPconsGetData(conss[j]);
    4626 assert( consdata != NULL );
    4627
    4628 binvarval = SCIPgetVarSol(scip, consdata->binvar);
    4629
    4630#ifdef SCIP_DEBUG
    4631 if ( SCIPisFeasEQ(scip, binvarval, 1.0) )
    4632 ++nvarsone;
    4633 else if ( SCIPisFeasZero(scip, binvarval) )
    4634 ++nvarszero;
    4635 else
    4636 ++nvarsfrac;
    4637#endif
    4638
    4639 /* check whether complementary (negated) variable is present as well */
    4640 binvarneg = SCIPvarGetNegatedVar(consdata->binvar);
    4641 assert( conshdlrdata->binvarhash != NULL );
    4642 if ( binvarneg != NULL && SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarneg) )
    4643 {
    4644 SCIP_Real binvarnegval = SCIPgetVarSol(scip, binvarneg);
    4645
    4646 /* take larger one */
    4647 if ( binvarval > binvarnegval )
    4648 S[j] = TRUE;
    4649 else
    4650 S[j] = FALSE;
    4651 continue;
    4652 }
    4653
    4654 /* check for threshold */
    4655 if ( SCIPisFeasLT(scip, SCIPgetVarSol(scip, consdata->binvar), threshold) )
    4656 {
    4657 S[j] = TRUE;
    4658 value += varGetObjDelta(consdata->binvar);
    4659 ++size;
    4660 }
    4661 else
    4662 S[j] = FALSE;
    4663 }
    4664
    4665 if ( size == nconss )
    4666 {
    4667 SCIPdebugMsg(scip, "All variables in the set. Continue ...\n");
    4668 continue;
    4669 }
    4670
    4671 /* skip computation if size has not changed (computation is likely the same) */
    4672 if ( size == oldsize )
    4673 {
    4674 SCIPdebugMsg(scip, "Skipping computation: size support has not changed.\n");
    4675 continue;
    4676 }
    4677 oldsize = size;
    4678
    4679#ifdef SCIP_DEBUG
    4680 SCIPdebugMsg(scip, " Vars with value 1: %d 0: %d and fractional: %d.\n", nvarsone, nvarszero, nvarsfrac);
    4681#endif
    4682
    4683 /* fix the variables in S */
    4684 SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
    4685
    4686 /* extend set S to a cover and generate cuts */
    4687 SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, conshdlrdata->genlogicor,
    4688 nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
    4689
    4690 /* we ignore errors in extendToCover */
    4691 if ( nCuts > 0 )
    4692 {
    4693 *nGen += nCuts;
    4694 ++rounds;
    4695 }
    4696 else
    4697 {
    4698 /* possibly update upper bound */
    4699 SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
    4700 }
    4701
    4702 /* reset bounds */
    4703 SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
    4704 }
    4705 SCIPdebug( SCIPdebugMsg(scip, "Generated %d IISs.\n", *nGen - nGenOld); )
    4706
    4707#ifndef NDEBUG
    4708 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    4709#endif
    4710
    4712
    4713 return SCIP_OKAY;
    4714}
    4715
    4716
    4717
    4718/** separate cuts based on perspective formulation
    4719 *
    4720 * Hijazi, Bonami, and Ouorou (2014) introduced the following cuts: We consider an indicator constraint
    4721 * \f[
    4722 * y = 1 \rightarrow \alpha^T x \leq \beta
    4723 * \f]
    4724 * and assume finite bounds \f$\ell \leq x \leq u\f$. Then for \f$I \subseteq \{1, \dots, n\}\f$ define
    4725 * \f[
    4726 * \Sigma(I,x,y) = \sum_{i \notin I} \alpha_i x_i +
    4727 * y \Big(\sum_{i \in I, \alpha_i < 0} \alpha_i u_i + \sum_{i \in I, \alpha_i > 0} \alpha_i \ell_i +
    4728 * \sum_{i \notin I, \alpha_i < 0} \alpha_i \ell_i + \sum_{i \notin I, \alpha_i > 0} \alpha_i u_i - \beta\Big).
    4729 * \f]
    4730 * Then the cuts
    4731 * \f[
    4732 * \Sigma(I,x,y) \leq \sum_{i \notin I, \alpha_i < 0} \alpha_i \ell_i + \sum_{i \notin I, \alpha_i > 0} \alpha_i u_i
    4733 * \f]
    4734 * are valid for the disjunction
    4735 * \f[
    4736 * \{y = 0,\; \ell \leq x \leq u\} \cup \{y = 1,\; \ell \leq x \leq u,\; \alpha^T x \leq \beta\}.
    4737 * \f]
    4738 * These cuts can easily be separated for a given point \f$(x^*, y^*)\f$ by checking for each \f$i \in \{1, \dots, n\}\f$ whether
    4739 * \f[
    4740 * y^*(\alpha_i\, u_i\, [\alpha_i < 0] + \alpha_i\, \ell_i\, [\alpha_i > 0]) >
    4741 * \alpha_i x_i^* + y^* )\alpha_i \ell_i [\alpha_i < 0] + \alpha_i u_i [\alpha_i > 0]),
    4742 * \f]
    4743 * where \f$[C] = 1\f$ if condition \f$C\f$ is satisfied, otherwise it is 0.
    4744 * If the above inequality holds, \f$i\f$ is included in \f$I\f$, otherwise not.
    4745 */
    4746static
    4748 SCIP* scip, /**< SCIP pointer */
    4749 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4750 SCIP_SOL* sol, /**< solution to be separated */
    4751 int nconss, /**< number of constraints */
    4752 SCIP_CONS** conss, /**< indicator constraints */
    4753 int maxsepacuts, /**< maximal number of cuts to be generated */
    4754 int* nGen /**< number of generated cuts */
    4755 )
    4756{ /*lint --e{850}*/
    4757 SCIP_CONSHDLRDATA* conshdlrdata;
    4758 SCIP_VAR** cutvars;
    4759 SCIP_Real* cutvals;
    4760 int nvars;
    4761 int c;
    4762
    4763 assert( scip != NULL );
    4764 assert( conshdlr != NULL );
    4765 assert( conss != NULL );
    4766 assert( nGen != NULL );
    4767
    4768 if ( *nGen >= maxsepacuts )
    4769 return SCIP_OKAY;
    4770
    4771 nvars = SCIPgetNVars(scip);
    4772 SCIP_CALL( SCIPallocBufferArray(scip, &cutvars, nvars+1) );
    4773 SCIP_CALL( SCIPallocBufferArray(scip, &cutvals, nvars+1) );
    4774
    4775 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4776 assert( conshdlrdata != NULL );
    4777
    4778 /* loop through constraints */
    4779 for (c = 0; c < nconss; ++c)
    4780 {
    4781 SCIP_CONSDATA* consdata;
    4782 SCIP_CONS* lincons;
    4783 SCIP_VAR* slackvar;
    4784 SCIP_VAR* binvar;
    4785 SCIP_Real binval;
    4786
    4787 assert( conss[c] != NULL );
    4788 consdata = SCIPconsGetData(conss[c]);
    4789 assert( consdata != NULL );
    4790 slackvar = consdata->slackvar;
    4791
    4792 lincons = consdata->lincons;
    4793 assert( lincons != NULL );
    4794
    4795 binvar = consdata->binvar;
    4796 assert( binvar != NULL );
    4797 binval = SCIPgetSolVal(scip, sol, binvar);
    4798
    4799 if ( SCIPconsIsActive(lincons) )
    4800 {
    4801 SCIP_VAR** linvars;
    4802 SCIP_Real* linvals;
    4803 SCIP_Real linrhs;
    4804 SCIP_Bool finitebound = TRUE;
    4805 SCIP_Real cutrhs = 0.0;
    4806 SCIP_Real cutval;
    4807 SCIP_Real signfactor = 1.0;
    4808 SCIP_Real ypart;
    4809 SCIP_Bool islocal = FALSE;
    4810 int nlinvars;
    4811 int cnt = 0;
    4812 int j;
    4813
    4814 linvars = SCIPgetVarsLinear(scip, lincons);
    4815 linvals = SCIPgetValsLinear(scip, lincons);
    4816 nlinvars = SCIPgetNVarsLinear(scip, lincons);
    4817
    4818 linrhs = SCIPgetRhsLinear(scip, lincons);
    4819 if ( SCIPisInfinity(scip, linrhs) )
    4820 {
    4821 if ( ! SCIPisInfinity(scip, SCIPgetLhsLinear(scip, lincons)) )
    4822 {
    4823 linrhs = -SCIPgetLhsLinear(scip, lincons);
    4824 signfactor = -1.0;
    4825 }
    4826 else
    4827 continue;
    4828 }
    4829 ypart = -linrhs;
    4830 cutval = binval * ypart;
    4831
    4832 for (j = 0; j < nlinvars; ++j)
    4833 {
    4834 SCIP_Real linval;
    4835 SCIP_Real lb;
    4836 SCIP_Real ub;
    4837 SCIP_Real din = 0.0;
    4838 SCIP_Real dout = 0.0;
    4839 SCIP_Real xpart;
    4840 SCIP_Real xval;
    4841
    4842 if ( linvars[j] == slackvar )
    4843 continue;
    4844
    4845 if ( conshdlrdata->sepapersplocal )
    4846 {
    4847 lb = SCIPvarGetLbLocal(linvars[j]);
    4848 ub = SCIPvarGetUbLocal(linvars[j]);
    4849
    4850 if ( lb > SCIPvarGetLbGlobal(linvars[j]) )
    4851 islocal = TRUE;
    4852 if ( ub < SCIPvarGetUbGlobal(linvars[j]) )
    4853 islocal = TRUE;
    4854 }
    4855 else
    4856 {
    4857 lb = SCIPvarGetLbGlobal(linvars[j]);
    4858 ub = SCIPvarGetUbGlobal(linvars[j]);
    4859 }
    4860
    4861 /* skip cases with unbounded variables */
    4862 if ( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
    4863 {
    4864 finitebound = FALSE;
    4865 break;
    4866 }
    4867
    4868 /* compute rest parts for i in the set (din) or not in the set (dout) */
    4869 linval = signfactor * linvals[j];
    4870 if ( SCIPisNegative(scip, linval) )
    4871 {
    4872 din += linval * ub;
    4873 dout += linval * lb;
    4874 }
    4875 else if ( SCIPisPositive(scip, linval) )
    4876 {
    4877 din += linval * lb;
    4878 dout += linval * ub;
    4879 }
    4880
    4881 xval = SCIPgetSolVal(scip, sol, linvars[j]);
    4882 xpart = linval * xval;
    4883
    4884 /* if din > dout, we want to include i in the set */
    4885 if ( SCIPisGT(scip, binval * din, binval * dout + xpart) )
    4886 {
    4887 ypart += din;
    4888 cutval += binval * din;
    4889 }
    4890 else
    4891 {
    4892 /* otherwise i is not in the set */
    4893 ypart += dout;
    4894
    4895 cutrhs += dout;
    4896 cutval += binval * dout + xpart;
    4897
    4898 cutvars[cnt] = linvars[j];
    4899 cutvals[cnt++] = linval;
    4900 }
    4901 }
    4902
    4903 if ( ! finitebound )
    4904 continue;
    4905
    4906 if ( SCIPisEfficacious(scip, cutval - cutrhs) )
    4907 {
    4908 SCIP_ROW* row;
    4909 SCIP_Bool infeasible;
    4910 char name[50];
    4911
    4912 /* add y-variable */
    4913 cutvars[cnt] = binvar;
    4914 cutvals[cnt] = ypart;
    4915 ++cnt;
    4916
    4917 SCIPdebugMsg(scip, "Found cut of lhs value %f > %f.\n", cutval, cutrhs);
    4918 (void) SCIPsnprintf(name, 50, "persp%d", conshdlrdata->nperspcutsgen + *nGen);
    4919 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), cutrhs, islocal, FALSE, conshdlrdata->removable) );
    4920 SCIP_CALL( SCIPaddVarsToRow(scip, row, cnt, cutvars, cutvals) );
    4921#ifdef SCIP_OUTPUT
    4922 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
    4923#endif
    4924 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
    4925 assert( ! infeasible );
    4926 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    4927 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
    4928 ++(*nGen);
    4929 }
    4930 }
    4931 if ( *nGen >= maxsepacuts )
    4932 break;
    4933 }
    4934
    4935 SCIPfreeBufferArray(scip, &cutvals);
    4936 SCIPfreeBufferArray(scip, &cutvars);
    4937
    4938 return SCIP_OKAY;
    4939}
    4940
    4941
    4942/** separation method
    4943 *
    4944 * We first check whether coupling inequalities can be separated (if required). If not enough of
    4945 * these could be generated, we check whether IIS inequalities can be separated.
    4946 */
    4947static
    4949 SCIP* scip, /**< SCIP pointer */
    4950 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4951 int nconss, /**< number of constraints */
    4952 int nusefulconss, /**< number of useful constraints */
    4953 SCIP_CONS** conss, /**< indicator constraints */
    4954 SCIP_SOL* sol, /**< solution to be separated */
    4955 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
    4956 SCIP_RESULT* result /**< result */
    4957 )
    4958{
    4959 SCIP_CONSHDLRDATA* conshdlrdata;
    4960 int maxsepacuts;
    4961 int ncuts;
    4962
    4963 assert( scip != NULL );
    4964 assert( conshdlr != NULL );
    4965 assert( conss != NULL );
    4966 assert( result != NULL );
    4967
    4968 *result = SCIP_DIDNOTRUN;
    4969
    4970 if ( nconss == 0 )
    4971 return SCIP_OKAY;
    4972
    4973 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4974 assert( conshdlrdata != NULL );
    4975 ncuts = 0;
    4976
    4977 /* get the maximal number of cuts allowed in a separation round */
    4978 if ( SCIPgetDepth(scip) == 0 )
    4979 maxsepacuts = conshdlrdata->maxsepacutsroot;
    4980 else
    4981 maxsepacuts = conshdlrdata->maxsepacuts;
    4982
    4983 /* first separate coupling inequalities (if required) */
    4984 if ( conshdlrdata->sepacouplingcuts )
    4985 {
    4986 int c;
    4987
    4988 *result = SCIP_DIDNOTFIND;
    4989
    4990 /* check each constraint */
    4991 for (c = 0; c < nusefulconss && ncuts < maxsepacuts; ++c)
    4992 {
    4993 SCIP_CONSDATA* consdata;
    4994 SCIP_Bool islocal;
    4995 SCIP_Real ub;
    4996
    4997 assert( conss != NULL );
    4998 assert( conss[c] != NULL );
    4999 consdata = SCIPconsGetData(conss[c]);
    5000 assert( consdata != NULL );
    5001 assert( consdata->slackvar != NULL );
    5002 assert( consdata->binvar != NULL );
    5003
    5004 /* get upper bound for slack variable in linear constraint */
    5005 islocal = FALSE;
    5006 if ( conshdlrdata->sepacouplinglocal )
    5007 {
    5008 ub = SCIPvarGetUbLocal(consdata->slackvar);
    5009 if ( ub < SCIPvarGetUbGlobal(consdata->slackvar) )
    5010 islocal = TRUE;
    5011 }
    5012 else
    5013 ub = SCIPvarGetUbGlobal(consdata->slackvar);
    5014 assert( ! SCIPisFeasNegative(scip, ub) );
    5015
    5016 /* only use coefficients that are not too large */
    5017 if ( ub <= conshdlrdata->sepacouplingvalue )
    5018 {
    5019 SCIP_Real activity;
    5020
    5021 activity = SCIPgetSolVal(scip, sol, consdata->slackvar) + ub * SCIPgetSolVal(scip, sol, consdata->binvar) - ub;
    5022 if ( SCIPisEfficacious(scip, activity) )
    5023 {
    5024 SCIP_ROW* row;
    5025 SCIP_Bool infeasible;
    5026#ifndef NDEBUG
    5027 char name[50];
    5028
    5029 (void) SCIPsnprintf(name, 50, "couple%d", c);
    5030 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
    5031#else
    5032 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], "", -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
    5033#endif
    5035
    5036 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
    5037 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
    5039
    5040 SCIPdebugMsg(scip, "Separated coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
    5041#ifdef SCIP_OUTPUT
    5042 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
    5043#endif
    5044 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
    5045 assert( ! infeasible );
    5046 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    5047
    5048 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
    5049 *result = SCIP_SEPARATED;
    5050
    5051 ++ncuts;
    5052 }
    5053 }
    5054 }
    5055 SCIPdebugMsg(scip, "Number of separated coupling inequalities: %d.\n", ncuts);
    5056 }
    5057
    5058 /* separate cuts from the alternative lp (if required) */
    5059 if ( conshdlrdata->sepaalternativelp && ncuts < SEPAALTTHRESHOLD )
    5060 {
    5061 SCIP_Bool cutoff;
    5062 int noldcuts;
    5063
    5064 SCIPdebugMsg(scip, "Separating inequalities for indicator constraints.\n");
    5065
    5066 noldcuts = ncuts;
    5067 if ( *result == SCIP_DIDNOTRUN )
    5068 *result = SCIP_DIDNOTFIND;
    5069
    5070 /* start separation */
    5071 SCIP_CALL( separateIISRounding(scip, conshdlr, sol, enfosepatype, nconss, conss, maxsepacuts, &cutoff, &ncuts) );
    5072 SCIPdebugMsg(scip, "Separated %d cuts from indicator constraints.\n", ncuts - noldcuts);
    5073
    5074 if ( cutoff )
    5075 *result = SCIP_CUTOFF;
    5076 else if ( ncuts > noldcuts )
    5077 {
    5078 conshdlrdata->niiscutsgen += ncuts;
    5079
    5080 /* possibly overwrite result from separation above */
    5081 if ( conshdlrdata->genlogicor )
    5082 *result = SCIP_CONSADDED;
    5083 else
    5084 *result = SCIP_SEPARATED;
    5085 }
    5086 }
    5087
    5088 /* separate cuts based on perspective formulation */
    5089 if ( conshdlrdata->sepaperspective && ncuts < SEPAALTTHRESHOLD )
    5090 {
    5091 int noldcuts;
    5092
    5093 SCIPdebugMsg(scip, "Separating inequalities based on perspective formulation.\n");
    5094
    5095 noldcuts = ncuts;
    5096 if ( *result == SCIP_DIDNOTRUN )
    5097 *result = SCIP_DIDNOTFIND;
    5098
    5099 /* start separation */
    5100 SCIP_CALL( separatePerspective(scip, conshdlr, sol, nconss, conss, maxsepacuts, &ncuts) );
    5101 SCIPdebugMsg(scip, "Separated %d cuts from perspective formulation.\n", ncuts - noldcuts);
    5102
    5103 if ( ncuts > noldcuts )
    5104 {
    5105 conshdlrdata->nperspcutsgen += ncuts;
    5106
    5107 /* possibly overwrite result from separation above */
    5108 *result = SCIP_SEPARATED;
    5109 }
    5110 }
    5111
    5112 return SCIP_OKAY;
    5113}
    5114
    5115
    5116/** initializes the constraint handler data */
    5117static
    5119 SCIP* scip, /**< SCIP pointer */
    5120 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
    5121 )
    5122{
    5123 assert( conshdlrdata != NULL );
    5124
    5125 conshdlrdata->linconsevents = FALSE;
    5126 conshdlrdata->linconsboundschanged = TRUE;
    5127 conshdlrdata->boundhaschanged = TRUE;
    5128 conshdlrdata->removable = TRUE;
    5129 conshdlrdata->scaled = FALSE;
    5130 conshdlrdata->altlp = NULL;
    5131 conshdlrdata->nrows = 0;
    5132 conshdlrdata->varhash = NULL;
    5133 conshdlrdata->slackhash = NULL;
    5134 conshdlrdata->lbhash = NULL;
    5135 conshdlrdata->ubhash = NULL;
    5136 conshdlrdata->nlbbounds = 0;
    5137 conshdlrdata->nubbounds = 0;
    5138 conshdlrdata->nslackvars = 0;
    5139 conshdlrdata->objcutindex = -1;
    5140 conshdlrdata->objupperbound = SCIPinfinity(scip);
    5141 conshdlrdata->objaltlpbound = SCIPinfinity(scip);
    5142 conshdlrdata->roundingminthres = 0.1;
    5143 conshdlrdata->roundingmaxthres = 0.6;
    5144 conshdlrdata->maxroundingrounds = MAXROUNDINGROUNDS;
    5145 conshdlrdata->roundingoffset = 0.1;
    5146 conshdlrdata->addedcouplingcons = FALSE;
    5147 conshdlrdata->ninitconss = 0;
    5148 conshdlrdata->nbinvarszero = 0;
    5149 conshdlrdata->performedrestart = FALSE;
    5150 conshdlrdata->objindicatoronly = FALSE;
    5151 conshdlrdata->objothervarsonly = FALSE;
    5152 conshdlrdata->minabsobj = 0.0;
    5153 conshdlrdata->normtype = 'e';
    5154 conshdlrdata->niiscutsgen = 0;
    5155 conshdlrdata->nperspcutsgen = 0;
    5156}
    5157
    5158
    5159/* ---------------------------- upgrading methods -----------------------------------*/
    5160
    5161/** tries to upgrade a linear constraint into an indicator constraint
    5162 *
    5163 * For some linear constraint of the form \f$a^T x + \alpha\, y \geq \beta\f$ with \f$y \in \{0,1\}\f$, we can upgrade
    5164 * it to an indicator constraint if for the residual value \f$a^T x \geq \gamma\f$, we have \f$\alpha + \gamma \geq
    5165 * \beta\f$: in this case, the constraint is always satisfied if \f$y = 1\f$.
    5166 *
    5167 * Similarly, for a linear constraint in the form \f$a^T x + \alpha\, y \leq \beta\f$ with \f$y \in \{0,1\}\f$, we can
    5168 * upgrade it to an indicator constraint if for the residual value \f$a^T x \leq \gamma\f$, we have \f$\alpha + \gamma
    5169 * \leq \beta\f$.
    5170 */
    5171static
    5172SCIP_DECL_LINCONSUPGD(linconsUpgdIndicator)
    5173{ /*lint --e{715}*/
    5174 SCIP_CONSHDLRDATA* conshdlrdata;
    5175 SCIP_CONSHDLR* conshdlr;
    5176 SCIP_Real minactivity = 0.0;
    5177 SCIP_Real maxactivity = 0.0;
    5178 SCIP_Real maxabsval = -1.0;
    5179 SCIP_Real secabsval = -1.0;
    5180 int maxabsvalidx = -1;
    5181 int j;
    5182
    5183 assert( scip != NULL );
    5184 assert( upgdcons != NULL );
    5185 assert( ! SCIPconsIsModifiable(cons) );
    5186
    5188
    5189 /* do not upgrade if there are at most 2 variables (2 variables should be upgraded to a varbound constraint) */
    5190 if ( nvars <= 2 )
    5191 return SCIP_OKAY;
    5192
    5193 /* cannot currently ranged constraints, since we can only return one constraint (and we would need one for each side each) */
    5194 if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
    5195 return SCIP_OKAY;
    5196
    5197 /* check whether upgrading is turned on */
    5198 conshdlr = SCIPfindConshdlr(scip, "indicator");
    5199 assert( conshdlr != NULL );
    5200 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5201 assert( conshdlrdata != NULL );
    5202
    5203 if ( ! conshdlrdata->upgradelinear )
    5204 return SCIP_OKAY;
    5205
    5206 /* calculate activities */
    5207 for (j = 0; j < nvars; ++j)
    5208 {
    5209 SCIP_VAR* var;
    5210 SCIP_Real val;
    5211 SCIP_Real lb;
    5212 SCIP_Real ub;
    5213
    5214 val = vals[j];
    5215 assert( ! SCIPisZero(scip, val) );
    5216
    5217 var = vars[j];
    5218 assert( var != NULL );
    5219
    5220 /* store maximal (and second to largest) value of coefficients */
    5221 if ( SCIPisGE(scip, REALABS(val), maxabsval) )
    5222 {
    5223 secabsval = maxabsval;
    5224 maxabsval = REALABS(val);
    5225 maxabsvalidx = j;
    5226 }
    5227
    5228 if ( ! SCIPvarIsBinary(var) )
    5229 {
    5230 if ( val > 0.0 )
    5231 {
    5232 lb = SCIPvarGetLbGlobal(var);
    5233 ub = SCIPvarGetUbGlobal(var);
    5234 }
    5235 else
    5236 {
    5237 ub = SCIPvarGetLbGlobal(var);
    5238 lb = SCIPvarGetUbGlobal(var);
    5239 }
    5240
    5241 /* compute minimal activity */
    5242 if ( SCIPisInfinity(scip, -lb) )
    5243 minactivity = -SCIPinfinity(scip);
    5244 else
    5245 {
    5246 if ( ! SCIPisInfinity(scip, -minactivity) )
    5247 minactivity += val * lb;
    5248 }
    5249
    5250 /* compute maximal activity */
    5251 if ( SCIPisInfinity(scip, ub) )
    5252 maxactivity = SCIPinfinity(scip);
    5253 else
    5254 {
    5255 if ( ! SCIPisInfinity(scip, maxactivity) )
    5256 maxactivity += val * ub;
    5257 }
    5258 }
    5259 }
    5260 assert( maxabsval >= 0.0 );
    5261 assert( 0 <= maxabsvalidx && maxabsvalidx < nvars );
    5262
    5263 /* exit if largest coefficient does not belong to binary variable */
    5264 if ( ! SCIPvarIsBinary(vars[maxabsvalidx]) )
    5265 return SCIP_OKAY;
    5266
    5267 /* exit if the second largest coefficient is as large as largest */
    5268 if ( SCIPisEQ(scip, secabsval, maxabsval) )
    5269 return SCIP_OKAY;
    5270
    5271 /* cannot upgrade if all activities are infinity */
    5272 if ( SCIPisInfinity(scip, -minactivity) && SCIPisInfinity(scip, maxactivity) )
    5273 return SCIP_OKAY;
    5274
    5275 /* check each variable as indicator variable */
    5276 for (j = 0; j < nvars; ++j)
    5277 {
    5278 SCIP_VAR** indconsvars;
    5279 SCIP_Real* indconsvals;
    5280 SCIP_Bool upgdlhs = FALSE;
    5281 SCIP_Bool upgdrhs = FALSE;
    5282 SCIP_Bool indneglhs = FALSE;
    5283 SCIP_Bool indnegrhs = FALSE;
    5284 SCIP_VAR* indvar;
    5285 SCIP_Real indval;
    5286 int l;
    5287
    5288 indvar = vars[j];
    5289 indval = vals[j];
    5290 assert( ! SCIPisZero(scip, indval) );
    5291
    5292 if ( ! SCIPvarIsBinary(indvar) )
    5293 continue;
    5294
    5295 /* check for upgrading of lhs */
    5296 if ( ! SCIPisInfinity(scip, -minactivity) && ! SCIPisInfinity(scip, -lhs) )
    5297 {
    5298 /* upgrading is possible with binary variable */
    5299 if ( SCIPisGE(scip, minactivity, lhs) )
    5300 upgdlhs = TRUE;
    5301
    5302 /* upgrading is possible with negated binary variable */
    5303 if ( SCIPisGE(scip, minactivity + indval, lhs) )
    5304 {
    5305 upgdlhs = TRUE;
    5306 indneglhs = TRUE;
    5307 }
    5308 }
    5309
    5310 /* check for upgrading of rhs */
    5311 if ( ! SCIPisInfinity(scip, maxactivity) && ! SCIPisInfinity(scip, rhs) )
    5312 {
    5313 /* upgrading is possible with binary variable */
    5314 if ( SCIPisLE(scip, maxactivity, rhs) )
    5315 upgdrhs = TRUE;
    5316
    5317 /* upgrading is possible with negated binary variable */
    5318 if ( SCIPisLE(scip, maxactivity + indval, rhs) )
    5319 {
    5320 upgdrhs = TRUE;
    5321 indnegrhs = TRUE;
    5322 }
    5323 }
    5324
    5325 /* upgrade constraint */
    5326 if ( upgdlhs || upgdrhs )
    5327 {
    5328 SCIP_VAR* indvar2;
    5329 SCIP_Real bnd;
    5330 int cnt = 0;
    5331
    5332 assert( ! upgdlhs || ! upgdrhs ); /* cannot treat ranged rows */
    5333 SCIPdebugMsg(scip, "upgrading constraint <%s> to an indicator constraint.\n", SCIPconsGetName(cons));
    5334
    5335 SCIP_CALL( SCIPallocBufferArray(scip, &indconsvars, nvars - 1) );
    5336 SCIP_CALL( SCIPallocBufferArray(scip, &indconsvals, nvars - 1) );
    5337
    5338 /* create constraint */
    5339 for (l = 0; l < nvars; ++l)
    5340 {
    5341 if ( vars[l] == indvar )
    5342 continue;
    5343 indconsvars[cnt] = vars[l];
    5344 if ( upgdlhs )
    5345 indconsvals[cnt] = -vals[l];
    5346 else
    5347 indconsvals[cnt] = vals[l];
    5348 ++cnt;
    5349 }
    5350
    5351 if ( indneglhs || indnegrhs )
    5352 {
    5353 SCIP_CALL( SCIPgetNegatedVar(scip, indvar, &indvar2) );
    5354 }
    5355 else
    5356 indvar2 = indvar;
    5357
    5358 if ( upgdlhs )
    5359 {
    5360 bnd = -lhs;
    5361 if ( ! indneglhs )
    5362 bnd -= indval;
    5363 SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
    5366 }
    5367 else
    5368 {
    5369 bnd = rhs;
    5370 if ( ! indnegrhs )
    5371 bnd -= indval;
    5372 SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
    5375 }
    5376
    5377#ifdef SCIP_DEBUG
    5378 SCIPinfoMessage(scip, NULL, "upgrade: \n");
    5379 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
    5380 SCIPinfoMessage(scip, NULL, "\n");
    5381 SCIP_CALL( SCIPprintCons(scip, *upgdcons, NULL) );
    5382 SCIPinfoMessage(scip, NULL, "\n");
    5384 SCIPinfoMessage(scip, NULL, " (minact: %f, maxact: %f)\n", minactivity, maxactivity);
    5385#endif
    5386
    5387 SCIPfreeBufferArray(scip, &indconsvars);
    5388 SCIPfreeBufferArray(scip, &indconsvals);
    5389
    5390 return SCIP_OKAY;
    5391 }
    5392 }
    5393
    5394 return SCIP_OKAY;
    5395}
    5396
    5397
    5398/* ---------------------------- constraint handler callback methods ----------------------*/
    5399
    5400/** copy method for constraint handler plugins (called when SCIP copies plugins) */
    5401static
    5402SCIP_DECL_CONSHDLRCOPY(conshdlrCopyIndicator)
    5403{ /*lint --e{715}*/
    5404 assert( scip != NULL );
    5405 assert( conshdlr != NULL );
    5406 assert( valid != NULL );
    5407
    5409
    5410 /* call inclusion method of constraint handler */
    5412
    5413 *valid = TRUE;
    5414
    5415 return SCIP_OKAY;
    5416}
    5417
    5418
    5419/** initialization method of constraint handler (called after problem was transformed) */
    5420static
    5421SCIP_DECL_CONSINIT(consInitIndicator)
    5422{ /*lint --e{715}*/
    5423 SCIP_CONSHDLRDATA* conshdlrdata;
    5424
    5425 assert( scip != NULL );
    5426 assert( conshdlr != NULL );
    5427
    5429
    5430 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5431 assert( conshdlrdata != NULL );
    5432
    5433 initConshdlrData(scip, conshdlrdata);
    5434
    5435 /* find trysol heuristic */
    5436 if ( conshdlrdata->trysolutions && conshdlrdata->heurtrysol == NULL )
    5437 {
    5438 conshdlrdata->heurtrysol = SCIPfindHeur(scip, "trysol");
    5439 }
    5440
    5441 return SCIP_OKAY;
    5442}
    5443
    5444
    5445/** deinitialization method of constraint handler (called before transformed problem is freed) */
    5446static
    5447SCIP_DECL_CONSEXIT(consExitIndicator)
    5448{ /*lint --e{715}*/
    5449 SCIP_CONSHDLRDATA* conshdlrdata;
    5450 SCIP_CONSDATA* consdata;
    5451 int i;
    5452 int j;
    5453
    5454 assert( scip != NULL );
    5455 assert( conshdlr != NULL );
    5456
    5458
    5459 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5460
    5461 if ( conshdlrdata->binvarhash != NULL )
    5462 SCIPhashmapFree(&conshdlrdata->binvarhash);
    5463
    5464 if ( conshdlrdata->binslackvarhash != NULL )
    5465 SCIPhashmapFree(&conshdlrdata->binslackvarhash);
    5466
    5467 /* drop bound change events on variables of linear constraints */
    5468 for (i = 0; i < nconss; i++)
    5469 {
    5470 consdata = SCIPconsGetData(conss[i]);
    5471 assert( consdata != NULL );
    5472
    5473 if ( consdata->varswithevents != NULL )
    5474 {
    5475 assert( consdata->eventtypes != NULL );
    5476 assert( consdata->lincons != NULL );
    5477
    5478 for (j = 0; j < consdata->nevents; ++j)
    5479 {
    5480 SCIP_CALL( SCIPdropVarEvent(scip, consdata->varswithevents[j], consdata->eventtypes[j], conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, -1) );
    5481 }
    5482 SCIPfreeBlockMemoryArray(scip, &consdata->varswithevents, consdata->nevents);
    5483 SCIPfreeBlockMemoryArray(scip, &consdata->eventtypes, consdata->nevents);
    5484
    5485 consdata->nevents = 0;
    5486 assert( consdata->varswithevents == NULL );
    5487 assert( consdata->eventtypes == NULL );
    5488 }
    5489 }
    5490
    5491 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
    5492 conshdlrdata->maxaddlincons = 0;
    5493 conshdlrdata->naddlincons = 0;
    5494 conshdlrdata->nrows = 0;
    5495
    5496 return SCIP_OKAY;
    5497}
    5498
    5499
    5500/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
    5501static
    5502SCIP_DECL_CONSFREE(consFreeIndicator)
    5503{
    5504 SCIP_CONSHDLRDATA* conshdlrdata;
    5505
    5506 assert( scip != NULL );
    5507 assert( conshdlr != NULL );
    5508
    5510
    5511 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5512 assert( conshdlrdata != NULL );
    5513 assert( conshdlrdata->altlp == NULL );
    5514 assert( conshdlrdata->varhash == NULL );
    5515 assert( conshdlrdata->lbhash == NULL );
    5516 assert( conshdlrdata->ubhash == NULL );
    5517 assert( conshdlrdata->slackhash == NULL );
    5518
    5519 if ( conshdlrdata->maxaddlincons > 0 )
    5520 {
    5521 /* if problem was not yet transformed the array may need to be freed, because we did not call the EXIT callback */
    5522 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
    5523 }
    5524 assert( conshdlrdata->addlincons == NULL );
    5525 conshdlrdata->naddlincons = 0;
    5526 conshdlrdata->maxaddlincons = 0;
    5527
    5528 SCIPfreeBlockMemory(scip, &conshdlrdata);
    5529
    5530 return SCIP_OKAY;
    5531}
    5532
    5533
    5534/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
    5535static
    5536SCIP_DECL_CONSINITSOL(consInitsolIndicator)
    5537{
    5538 SCIP_CONSHDLRDATA* conshdlrdata;
    5539 int c;
    5540
    5541 assert( scip != NULL );
    5542 assert( conshdlr != NULL );
    5543
    5545
    5548 return SCIP_OKAY;
    5549
    5550 SCIPdebugMsg(scip, "Initsol for indicator constraints.\n");
    5551
    5552 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5553 assert( conshdlrdata != NULL );
    5554 assert( conshdlrdata->slackhash == NULL );
    5555
    5556 conshdlrdata->boundhaschanged = TRUE; /* make sure that we propagate at the beginning */
    5557
    5558 SCIP_CALL( SCIPgetCharParam(scip, "separating/efficacynorm", &conshdlrdata->normtype) );
    5559
    5560 if ( conshdlrdata->sepaalternativelp )
    5561 {
    5562 /* generate hash for storing all slack variables (size is just a guess) */
    5563 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->slackhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
    5564 assert( conshdlrdata->slackhash != NULL );
    5565
    5566 /* first initialize slack hash */
    5567 for (c = 0; c < nconss; ++c)
    5568 {
    5569 SCIP_CONSDATA* consdata;
    5570
    5571 assert( conss != NULL );
    5572 assert( conss[c] != NULL );
    5573 assert( SCIPconsIsTransformed(conss[c]) );
    5574
    5575 consdata = SCIPconsGetData(conss[c]);
    5576 assert( consdata != NULL );
    5577
    5578 assert( consdata->slackvar != NULL );
    5579
    5580 /* insert slack variable into hash */
    5581 SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->slackhash, consdata->slackvar, INT_MAX) );
    5582 assert( SCIPhashmapExists(conshdlrdata->slackhash, consdata->slackvar) );
    5583 ++conshdlrdata->nslackvars;
    5584 }
    5585
    5586 if ( conshdlrdata->genlogicor )
    5587 {
    5588 SCIP_CONSHDLR* logicorconshdlr;
    5589 int logicorsepafreq;
    5590 int sepafreq;
    5591
    5592 /* If we generate logicor constraints, but the separation frequency is not 1, output warning */
    5593 logicorconshdlr = SCIPfindConshdlr(scip, "logicor");
    5594 if ( logicorconshdlr == NULL )
    5595 {
    5596 SCIPerrorMessage("Logicor constraint handler not included, cannot generate constraints.\n");
    5597 return SCIP_ERROR;
    5598 }
    5599 logicorsepafreq = SCIPconshdlrGetSepaFreq(logicorconshdlr);
    5600 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
    5601 if ( (sepafreq != -1 || conshdlrdata->enforcecuts) && logicorsepafreq != 1 )
    5602 {
    5603 SCIPwarningMessage(scip, "For better performance set parameter 'constraints/logicor/sepafreq' to 1 if 'constraints/included/genlogicor' is true.\n");
    5604 }
    5605 }
    5606 }
    5607
    5608 /* check each constraint */
    5609 conshdlrdata->objothervarsonly = TRUE;
    5610 for (c = 0; c < nconss; ++c)
    5611 {
    5612 SCIP_CONSDATA* consdata;
    5613
    5614 assert( conss != NULL );
    5615 assert( conss[c] != NULL );
    5616 assert( SCIPconsIsTransformed(conss[c]) );
    5617
    5618 consdata = SCIPconsGetData(conss[c]);
    5619 assert( consdata != NULL );
    5620 assert( consdata->binvar != NULL );
    5621 assert( consdata->slackvar != NULL );
    5622
    5623 /* Presolving might replace a slack variable by an active variable. Thus, the objective of a slack variables might
    5624 * be nonzero. However, we do not need to check slack variables here. */
    5625 if ( ! SCIPisZero(scip, varGetObjDelta(consdata->binvar)) )
    5626 conshdlrdata->objothervarsonly = FALSE;
    5627
    5628 /* deactivate */
    5629 if ( ! consdata->linconsactive )
    5630 {
    5631 SCIP_CALL( SCIPdisableCons(scip, consdata->lincons) );
    5632 }
    5633 else
    5634 {
    5635 /* add constraint to alternative LP if not already done */
    5636 if ( conshdlrdata->sepaalternativelp && consdata->colindex < 0 )
    5637 {
    5638 SCIP_CALL( addAltLPConstraint(scip, conshdlr, consdata->lincons, consdata->slackvar, 1.0, &consdata->colindex) );
    5639 SCIPdebugMsg(scip, "Added column for <%s> to alternative LP with column index %d.\n", SCIPconsGetName(conss[c]),consdata->colindex);
    5640#ifdef SCIP_OUTPUT
    5641 SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
    5642 SCIPinfoMessage(scip, NULL, ";\n");
    5643#endif
    5644 }
    5645 }
    5646
    5647 /* add nlrow representation to NLP, if NLP had been constructed
    5648 *
    5649 * Note, that we did not tell SCIP in exitpre that we have something to add to the NLP, thus
    5650 * indicators are only available in the NLP for MINLPs, but not for MIPs with indicators.
    5651 */
    5652 if ( SCIPisNLPConstructed(scip) && SCIPconsIsChecked(conss[c]) )
    5653 {
    5654 /* create nonlinear row binary variable * slack variable = 0 */
    5655 SCIP_NLROW* nlrow;
    5656 SCIP_EXPR* quadexpr;
    5657 SCIP_EXPR* varexprs[2];
    5658
    5659 SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[0], consdata->binvar, NULL, NULL) );
    5660 SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[1], consdata->slackvar, NULL, NULL) );
    5661 SCIP_CALL( SCIPcreateExprProduct(scip, &quadexpr, 2, varexprs, 1.0, NULL, NULL) );
    5662
    5663 SCIP_CALL( SCIPcreateNlRow(scip, &nlrow, SCIPconsGetName(conss[c]), 0.0, 0, NULL, NULL, quadexpr, 0.0, 0.0, SCIP_EXPRCURV_UNKNOWN) );
    5664
    5665 SCIP_CALL( SCIPreleaseExpr(scip, &quadexpr) );
    5666 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[1]) );
    5667 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[0]) );
    5668
    5669 /* add row to NLP and forget about it */
    5670 SCIP_CALL( SCIPaddNlRow(scip, nlrow) );
    5671 SCIP_CALL( SCIPreleaseNlRow(scip, &nlrow) );
    5672 }
    5673 }
    5674
    5675 SCIPdebugMsg(scip, "Initialized %d indicator constraints.\n", nconss);
    5676
    5677 /* check additional constraints */
    5678 if ( conshdlrdata->sepaalternativelp )
    5679 {
    5680 SCIP_CONS* cons;
    5681 int colindex;
    5682 int cnt = 0;
    5683
    5684 /* add stored linear constraints if they exist */
    5685 if ( conshdlrdata->naddlincons > 0 )
    5686 {
    5687 for (c = 0; c < conshdlrdata->naddlincons; ++c)
    5688 {
    5689 cons = conshdlrdata->addlincons[c];
    5690
    5691 /* get transformed constraint - since it is needed only here, we do not store the information */
    5692 if ( ! SCIPconsIsTransformed(cons) )
    5693 {
    5694 SCIP_CALL( SCIPgetTransformedCons(scip, conshdlrdata->addlincons[c], &cons) );
    5695
    5696 /* @todo check when exactly the transformed constraint does not exist - SCIPisActive() does not suffice */
    5697 if ( cons == NULL )
    5698 continue;
    5699 }
    5700 SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
    5701 ++cnt;
    5702
    5703#ifdef SCIP_OUTPUT
    5704 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
    5705 SCIPinfoMessage(scip, NULL, ";\n");
    5706#endif
    5707 }
    5708 SCIPdebugMsg(scip, "Added %d additional columns to alternative LP.\n", cnt);
    5709 }
    5710 else
    5711 {
    5712 /* if no stored linear constraints are available, possibly collect other linear constraints; we only use linear
    5713 * constraints, since most other constraints involve integral variables, and in this context we will likely
    5714 * benefit much more from continuous variables. */
    5715 if ( conshdlrdata->useotherconss )
    5716 {
    5717 const char* conshdlrname;
    5718 SCIP_CONS** allconss;
    5719 int nallconss;
    5720
    5721 nallconss = SCIPgetNConss(scip);
    5722 allconss = SCIPgetConss(scip);
    5723
    5724 /* loop through all constraints */
    5725 for (c = 0; c < nallconss; ++c)
    5726 {
    5727 /* get constraint */
    5728 cons = allconss[c];
    5729 assert( cons != NULL );
    5730 assert( SCIPconsIsTransformed(cons) );
    5731
    5732 /* get constraint handler name */
    5733 conshdlrname = SCIPconshdlrGetName(SCIPconsGetHdlr(cons));
    5734
    5735 /* check type of constraint (only take modifiable linear constraints) */
    5736 if ( strcmp(conshdlrname, "linear") == 0 && ! SCIPconsIsModifiable(cons) )
    5737 {
    5738 /* avoid adding linear constraints that correspond to indicator constraints */
    5739 if ( strncmp(SCIPconsGetName(cons), "indlin", 6) != 0 )
    5740 {
    5741 SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
    5742 SCIPdebugMsg(scip, "Added column for linear constraint <%s> to alternative LP with column index %d.\n", SCIPconsGetName(cons), colindex);
    5743 ++cnt;
    5744 }
    5745 }
    5746 }
    5747 SCIPdebugMsg(scip, "Added %d additional columns from linear constraints to alternative LP.\n", cnt);
    5748 }
    5749 }
    5750 }
    5751
    5752 /* initialize event handler if restart should be forced */
    5753 if ( conshdlrdata->forcerestart )
    5754 {
    5755 SCIP_Bool* covered;
    5756 SCIP_VAR** vars;
    5757 int nvars;
    5758 int j;
    5759
    5760 assert( conshdlrdata->eventhdlrrestart != NULL );
    5761
    5762 /* store number of initial constraints */
    5763 conshdlrdata->ninitconss = SCIPconshdlrGetNActiveConss(conshdlr);
    5764
    5765 /* reset number of fixed binary variables */
    5766 conshdlrdata->nbinvarszero = 0;
    5767
    5768 /* loop through variables */
    5769 nvars = SCIPgetNVars(scip);
    5770 vars = SCIPgetVars(scip);
    5771
    5772 conshdlrdata->objindicatoronly = FALSE;
    5773 conshdlrdata->minabsobj = SCIP_REAL_MAX;
    5774
    5775 /* unmark all variables */
    5776 SCIP_CALL( SCIPallocBufferArray(scip, &covered, nvars) );
    5777 for (j = 0; j < nvars; ++j)
    5778 covered[j] = FALSE;
    5779
    5780 /* mark indicator variables */
    5781 for (c = 0; c < nconss; ++c)
    5782 {
    5783 SCIP_CONSDATA* consdata;
    5784 int probindex;
    5785
    5786 assert( conss != NULL );
    5787 assert( conss[c] != NULL );
    5788
    5789 /* avoid non-active indicator constraints */
    5790 if ( ! SCIPconsIsActive(conss[c]) )
    5791 continue;
    5792
    5793 consdata = SCIPconsGetData(conss[c]);
    5794 assert( consdata != NULL );
    5795 assert( consdata->binvar != NULL );
    5796
    5797 if ( SCIPvarIsNegated(consdata->binvar) )
    5798 {
    5799 assert( SCIPvarGetNegatedVar(consdata->binvar) != NULL );
    5800 probindex = SCIPvarGetProbindex(SCIPvarGetNegatedVar(consdata->binvar));
    5801 }
    5802 else
    5803 probindex = SCIPvarGetProbindex(consdata->binvar);
    5804
    5805 /* if presolving detected infeasibility it might be that the binary variables are not active */
    5806 if ( probindex < 0 )
    5807 continue;
    5808
    5809 assert( 0 <= probindex && probindex < nvars );
    5810 covered[probindex] = TRUE;
    5811 }
    5812
    5813 /* check all variables */
    5814 for (j = 0; j < nvars; ++j)
    5815 {
    5816 SCIP_Real obj;
    5817
    5818 obj = SCIPvarGetObj(vars[j]);
    5819 if ( ! SCIPisZero(scip, obj) )
    5820 {
    5821 if ( ! covered[j] )
    5822 break;
    5823 if ( ! SCIPisIntegral(scip, obj) )
    5824 break;
    5825 if ( REALABS(obj) < conshdlrdata->minabsobj )
    5826 conshdlrdata->minabsobj = REALABS(obj);
    5827 }
    5828 }
    5829
    5830 /* if all variables have integral objective and only indicator variables have nonzero objective */
    5831 if ( j >= nvars )
    5832 {
    5833 /* if there are variables with nonzero objective */
    5834 if ( conshdlrdata->minabsobj < SCIP_REAL_MAX )
    5835 {
    5836 assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
    5837 assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0) );
    5838
    5839 conshdlrdata->objindicatoronly = TRUE;
    5840
    5841 assert( conshdlrdata->eventhdlrrestart != NULL );
    5842 SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
    5843 }
    5844 }
    5845
    5846 SCIPfreeBufferArray(scip, &covered);
    5847 }
    5848
    5849 return SCIP_OKAY;
    5850}
    5851
    5852
    5853/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
    5854static
    5855SCIP_DECL_CONSEXITSOL(consExitsolIndicator)
    5856{ /*lint --e{715}*/
    5857 SCIP_CONSHDLRDATA* conshdlrdata;
    5858 int c;
    5859
    5860 assert( scip != NULL );
    5861 assert( conshdlr != NULL );
    5862
    5864
    5865 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5866 assert( conshdlrdata != NULL );
    5867
    5868 if ( conshdlrdata->sepaalternativelp )
    5869 {
    5870 if ( conshdlrdata->slackhash != NULL )
    5871 {
    5872#ifdef SCIP_DEBUG
    5873 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator slack hash:\n");
    5874 SCIPhashmapPrintStatistics(conshdlrdata->slackhash, SCIPgetMessagehdlr(scip));
    5875#endif
    5876 SCIPhashmapFree(&conshdlrdata->slackhash);
    5877 }
    5878
    5879 if ( conshdlrdata->altlp != NULL )
    5880 {
    5881 assert( conshdlrdata->varhash != NULL );
    5882 assert( conshdlrdata->lbhash != NULL );
    5883 assert( conshdlrdata->ubhash != NULL );
    5884
    5885#ifdef SCIP_DEBUG
    5886 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator var hash:\n");
    5887 SCIPhashmapPrintStatistics(conshdlrdata->varhash, SCIPgetMessagehdlr(scip));
    5888 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator lower bound hash:\n");
    5889 SCIPhashmapPrintStatistics(conshdlrdata->lbhash, SCIPgetMessagehdlr(scip));
    5890 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator upper bound hash:\n");
    5891 SCIPhashmapPrintStatistics(conshdlrdata->ubhash, SCIPgetMessagehdlr(scip));
    5892#endif
    5893
    5894 SCIPhashmapFree(&conshdlrdata->varhash);
    5895 SCIPhashmapFree(&conshdlrdata->lbhash);
    5896 SCIPhashmapFree(&conshdlrdata->ubhash);
    5897
    5898 SCIP_CALL( SCIPlpiFree(&conshdlrdata->altlp) );
    5899
    5900 /* save the information that the columns have been deleted */
    5901 for (c = 0; c < nconss; ++c)
    5902 {
    5903 SCIP_CONSDATA* consdata;
    5904
    5905 assert( conss != NULL );
    5906 assert( conss[c] != NULL );
    5907
    5908 consdata = SCIPconsGetData(conss[c]);
    5909 assert( consdata != NULL );
    5910 consdata->colindex = -1;
    5911 }
    5912 }
    5913 }
    5914 else
    5915 {
    5916 assert( conshdlrdata->slackhash == NULL );
    5917 assert( conshdlrdata->varhash == NULL );
    5918 assert( conshdlrdata->lbhash == NULL );
    5919 assert( conshdlrdata->ubhash == NULL );
    5920 }
    5921
    5922 return SCIP_OKAY;
    5923}
    5924
    5925
    5926/** frees specific constraint data */
    5927static
    5928SCIP_DECL_CONSDELETE(consDeleteIndicator)
    5929{
    5930 assert( scip != NULL );
    5931 assert( conshdlr != NULL );
    5932 assert( cons != NULL );
    5933 assert( consdata != NULL );
    5934
    5936
    5937#ifdef SCIP_MORE_DEBUG
    5938 SCIPdebugMsg(scip, "Deleting indicator constraint <%s>.\n", SCIPconsGetName(cons) );
    5939#endif
    5940
    5941 /* Make sure that the hash for binary variables is freed. If we read a problem and then another problem without
    5942 * solving (transforming) between, then no callback of constraint handlers are called. Thus, we cannot easily free the
    5943 * hash map there. */
    5944 if ( SCIPconshdlrGetNConss(conshdlr) == 0 )
    5945 {
    5946 SCIP_CONSHDLRDATA* conshdlrdata;
    5947
    5948 /* get constraint handler data */
    5949 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5950 assert( conshdlrdata != NULL );
    5951
    5952 if ( conshdlrdata->binslackvarhash != NULL )
    5953 SCIPhashmapFree(&conshdlrdata->binslackvarhash);
    5954 }
    5955
    5956 /* drop events on transformed variables */
    5957 if ( SCIPconsIsTransformed(cons) )
    5958 {
    5959 SCIP_CONSHDLRDATA* conshdlrdata;
    5960
    5961 /* get constraint handler data */
    5962 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5963 assert( conshdlrdata != NULL );
    5964
    5965 if ( conshdlrdata->sepaalternativelp )
    5966 {
    5967 SCIP_CALL( deleteAltLPConstraint(scip, conshdlr, cons) );
    5968 }
    5969
    5970 assert( (*consdata)->slackvar != NULL );
    5971 assert( (*consdata)->binvar != NULL );
    5972
    5973 /* free events only in correct stages */
    5975 {
    5976 if ( (*consdata)->linconsactive )
    5977 {
    5978 assert( conshdlrdata->eventhdlrbound != NULL );
    5979 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
    5980 (SCIP_EVENTDATA*) cons, -1) );
    5981 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
    5982 (SCIP_EVENTDATA*) cons, -1) );
    5983 }
    5984 if ( conshdlrdata->forcerestart )
    5985 {
    5986 assert( conshdlrdata->eventhdlrrestart != NULL );
    5987 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
    5988 (SCIP_EVENTDATA*) conshdlrdata, -1) );
    5989 }
    5990
    5991 /* drop bound change events on variables of linear constraints */
    5992 if ( conshdlrdata->linconsevents && (*consdata)->linconsactive && (*consdata)->varswithevents != NULL )
    5993 {
    5994 int j;
    5995 assert( cons != NULL );
    5996 assert( (*consdata)->eventtypes != NULL );
    5997 assert( (*consdata)->lincons != NULL );
    5998
    5999 for (j = 0; j < (*consdata)->nevents; ++j)
    6000 {
    6001 assert( !SCIPvarIsDeleted((*consdata)->varswithevents[j]) );
    6002 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->varswithevents[j], (*consdata)->eventtypes[j], conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, -1) );
    6003 }
    6004 SCIPfreeBlockMemoryArray(scip, &(*consdata)->varswithevents, (*consdata)->nevents);
    6005 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventtypes, (*consdata)->nevents);
    6006
    6007 (*consdata)->nevents = 0;
    6008 assert( (*consdata)->varswithevents == NULL );
    6009 assert( (*consdata)->eventtypes == NULL );
    6010 }
    6011 }
    6012 }
    6013
    6014 /* Can there be cases where lincons is NULL, e.g., if presolve found the problem infeasible? */
    6015 assert( (*consdata)->lincons != NULL );
    6016
    6017 /* mark linear constraint to be upgrade-able */
    6018 if ( SCIPconsIsActive((*consdata)->lincons) )
    6019 {
    6020 SCIPconsAddUpgradeLocks((*consdata)->lincons, -1);
    6021 assert( SCIPconsGetNUpgradeLocks((*consdata)->lincons) == 0 );
    6022 }
    6023
    6024 /* release binary variable, slack variable, and linear constraint */
    6025 if( (*consdata)->binvar != NULL )
    6026 {
    6027 SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->binvar) );
    6028 }
    6029 SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->slackvar) );
    6030 SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->lincons) );
    6031
    6032 SCIPfreeBlockMemory(scip, consdata);
    6033
    6034 return SCIP_OKAY;
    6035}
    6036
    6037
    6038/** transforms constraint data into data belonging to the transformed problem */
    6039static
    6040SCIP_DECL_CONSTRANS(consTransIndicator)
    6041{
    6042 SCIP_CONSDATA* consdata;
    6043 SCIP_CONSHDLRDATA* conshdlrdata;
    6044 SCIP_CONSDATA* sourcedata;
    6045 char s[SCIP_MAXSTRLEN];
    6046
    6047 assert( scip != NULL );
    6048 assert( conshdlr != NULL );
    6049 assert( sourcecons != NULL );
    6050 assert( targetcons != NULL );
    6051
    6053
    6054 /* get constraint handler data */
    6055 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6056 assert( conshdlrdata != NULL );
    6057 assert( conshdlrdata->eventhdlrbound != NULL );
    6058
    6059#ifdef SCIP_MORE_DEBUG
    6060 SCIPdebugMsg(scip, "Transforming indicator constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
    6061#endif
    6062
    6063 /* get data of original constraint */
    6064 sourcedata = SCIPconsGetData(sourcecons);
    6065 assert( sourcedata != NULL );
    6066 assert( sourcedata->binvar != NULL );
    6067
    6068 /* check for slackvar */
    6069 if ( sourcedata->slackvar == NULL )
    6070 {
    6071 SCIPerrorMessage("The indicator constraint <%s> needs a slack variable.\n", SCIPconsGetName(sourcecons));
    6072 return SCIP_INVALIDDATA;
    6073 }
    6074
    6075 /* check for linear constraint */
    6076 if ( sourcedata->lincons == NULL )
    6077 {
    6078 SCIPerrorMessage("The indicator constraint <%s> needs a linear constraint.\n", SCIPconsGetName(sourcecons));
    6079 return SCIP_INVALIDDATA;
    6080 }
    6081 assert( sourcedata->lincons != NULL );
    6082 assert( sourcedata->slackvar != NULL );
    6083
    6084 /* create constraint data */
    6085 consdata = NULL;
    6086 /* Note that the constraint has activeone = TRUE, since the binary variable has been negated already if needed. */
    6087 SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, SCIPconsGetName(sourcecons), &consdata, conshdlrdata->eventhdlrrestart,
    6088 sourcedata->binvar, TRUE, sourcedata->lessthanineq, sourcedata->slackvar, sourcedata->lincons, sourcedata->linconsactive) );
    6089 consdata->activeone = sourcedata->activeone;
    6090 assert( consdata != NULL );
    6091
    6092 /* capture binary variable, slack variable, and linear constraint */
    6093 SCIP_CALL( SCIPcaptureVar(scip, consdata->binvar) );
    6094 SCIP_CALL( SCIPcaptureVar(scip, consdata->slackvar) );
    6095 SCIP_CALL( SCIPcaptureCons(scip, consdata->lincons) );
    6096
    6097 /* create transformed constraint with the same flags */
    6098 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
    6099 SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
    6100 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
    6101 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
    6102 SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
    6103 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
    6104 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
    6105
    6106 /* catch local bound change events on binary variable */
    6107 if ( sourcedata->linconsactive )
    6108 {
    6109 assert( SCIPisTransformed(scip) );
    6110 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *targetcons, NULL) );
    6111 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *targetcons, NULL) );
    6112 }
    6113
    6114 /* make sure that binary variable hash exists */
    6115 if ( conshdlrdata->sepaalternativelp )
    6116 {
    6117 if ( conshdlrdata->binvarhash == NULL )
    6118 {
    6119 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
    6120 }
    6121
    6122 /* check whether binary variable is present: note that a binary variable might appear several times, but this seldomly happens. */
    6123 assert( conshdlrdata->binvarhash != NULL );
    6124 if ( ! SCIPhashmapExists(conshdlrdata->binvarhash, (void*) consdata->binvar) )
    6125 {
    6126 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binvarhash, (void*) consdata->binvar, (void*) (*targetcons)) );
    6127 }
    6128 }
    6129
    6130 return SCIP_OKAY;
    6131}
    6132
    6133
    6134/** presolving initialization method of constraint handler (called when presolving is about to begin) */
    6135static
    6136SCIP_DECL_CONSINITPRE(consInitpreIndicator)
    6137{ /*lint --e{715}*/
    6138 SCIP_CONSHDLRDATA* conshdlrdata;
    6139 int c;
    6140
    6141 assert( scip != NULL );
    6142 assert( conshdlr != NULL );
    6143
    6145
    6147 return SCIP_OKAY;
    6148
    6149 SCIPdebugMsg(scip, "Initpre method for indicator constraints.\n");
    6150
    6151 /* check each constraint and get transformed linear constraint */
    6152 for (c = 0; c < nconss; ++c)
    6153 {
    6154 SCIP_CONSDATA* consdata;
    6155
    6156 assert( conss != NULL );
    6157 assert( conss[c] != NULL );
    6158 assert( SCIPconsIsTransformed(conss[c]) );
    6159
    6160 consdata = SCIPconsGetData(conss[c]);
    6161 assert( consdata != NULL );
    6162
    6163 /* if not happened already, get transformed linear constraint */
    6164 assert( consdata->lincons != NULL );
    6165
    6166 SCIP_STRINGEQ( SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear", SCIP_INVALIDCALL );
    6167
    6168 /* in a restart the linear constraint might already be transformed */
    6169 if ( ! SCIPconsIsTransformed(consdata->lincons) )
    6170 {
    6171 SCIP_CONS* translincons;
    6172
    6173 SCIP_CALL( SCIPgetTransformedCons(scip, consdata->lincons, &translincons) );
    6174 assert( translincons != NULL );
    6175
    6176 SCIP_CALL( SCIPreleaseCons(scip, &consdata->lincons) );
    6177 SCIP_CALL( SCIPcaptureCons(scip, translincons) );
    6178 consdata->lincons = translincons;
    6179 }
    6180 }
    6181
    6182 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6183 assert( conshdlrdata != NULL );
    6184
    6185 /* reset flag, in case presolve was called for some problem before */
    6186 conshdlrdata->addedcouplingcons = FALSE;
    6187
    6188 return SCIP_OKAY;
    6189}
    6190
    6191
    6192/** presolving method of constraint handler
    6193 *
    6194 * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
    6195 * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
    6196 * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not
    6197 * inserted. Depending on the parameter @a addcouplingcons we add a variable upper bound or a row
    6198 * (in consInitlpIndicator()).
    6199 *
    6200 * @warning We can never delete linear constraints, because we need them to get the right values
    6201 * for the slack variables!
    6202 */
    6203static
    6204SCIP_DECL_CONSPRESOL(consPresolIndicator)
    6205{ /*lint --e{715}*/
    6206 SCIP_CONSHDLRDATA* conshdlrdata;
    6207 SCIP_Bool noReductions;
    6208 SCIPdebug( int oldnfixedvars = *nfixedvars; )
    6209 SCIPdebug( int oldndelconss = *ndelconss; )
    6210 int c;
    6211
    6212 assert( scip != NULL );
    6213 assert( conshdlr != NULL );
    6214 assert( result != NULL );
    6215
    6217
    6218 *result = SCIP_DIDNOTRUN;
    6219
    6220 /* get constraint handler data */
    6221 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6222 assert( conshdlrdata != NULL );
    6223
    6224 SCIPdebugMsg(scip, "Presolving indicator constraints.\n");
    6225
    6226 /* only run if success is possible */
    6227 if ( nrounds == 0 || nnewfixedvars > 0 || nnewchgbds > 0 || nnewaggrvars > 0 )
    6228 {
    6229 *result = SCIP_DIDNOTFIND;
    6230
    6231 /* check each constraint */
    6232 for (c = 0; c < nconss; ++c)
    6233 {
    6234 SCIP_CONSDATA* consdata;
    6235 SCIP_CONS* cons;
    6236 SCIP_Bool success;
    6237 SCIP_Bool cutoff;
    6238
    6239 assert( conss != NULL );
    6240 assert( conss[c] != NULL );
    6241 cons = conss[c];
    6242 consdata = SCIPconsGetData(cons);
    6243 assert( consdata != NULL );
    6244 assert( consdata->binvar != NULL );
    6245 assert( ! SCIPconsIsModifiable(cons) );
    6246
    6247#ifdef SCIP_MORE_DEBUG
    6248 SCIPdebugMsg(scip, "Presolving indicator constraint <%s>.\n", SCIPconsGetName(cons) );
    6249#endif
    6250
    6251 /* do nothing if the linear constraint is not active */
    6252 if ( ! consdata->linconsactive )
    6253 continue;
    6254
    6255 assert( consdata->lincons != NULL );
    6256 assert( consdata->slackvar != NULL );
    6257 assert( SCIPconsIsTransformed(consdata->lincons) );
    6258
    6259 SCIP_STRINGEQ( SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear", SCIP_INVALIDCALL );
    6260
    6261 /* add implications if not yet done */
    6262 if ( ! consdata->implicationadded )
    6263 {
    6264 int nbnds = 0;
    6265 SCIP_CALL( SCIPaddVarImplication(scip, consdata->binvar, TRUE, consdata->slackvar, SCIP_BOUNDTYPE_UPPER, 0.0,
    6266 &cutoff, &nbnds) );
    6267 *nchgbds += nbnds;
    6268
    6269 /* cutoff/infeasible might be true if preprocessing was truncated */
    6270 /* note: nbdchgs == 0 is not necessarily true, because preprocessing might be truncated. */
    6271 consdata->implicationadded = TRUE;
    6272 if ( cutoff )
    6273 {
    6274 *result = SCIP_CUTOFF;
    6275 return SCIP_OKAY;
    6276 }
    6277 }
    6278
    6279 /* determine integrality of slack variable if not yet done */
    6280 if ( !consdata->slacktypechecked )
    6281 {
    6282 consdata->slacktypechecked = TRUE;
    6283 if ( !SCIPvarIsImpliedIntegral(consdata->slackvar) )
    6284 {
    6285 SCIP_Real* vals;
    6286 SCIP_VAR** vars;
    6287 SCIP_VAR* slackvar;
    6288 SCIP_Bool foundslackvar = FALSE;
    6289 int nvars;
    6290 int j;
    6291
    6292 assert( consdata->lincons != NULL );
    6293 vars = SCIPgetVarsLinear(scip, consdata->lincons);
    6294 vals = SCIPgetValsLinear(scip, consdata->lincons);
    6295 nvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    6296 slackvar = consdata->slackvar;
    6297 assert( slackvar != NULL );
    6298
    6299 for (j = 0; j < nvars; ++j)
    6300 {
    6301 if ( vars[j] == slackvar )
    6302 foundslackvar = TRUE;
    6303 else
    6304 {
    6305 if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, vals[j]))
    6306 break;
    6307 }
    6308 }
    6309 /* something is strange if the slack variable does not appear in the linear constraint (possibly because it is an artificial constraint) */
    6310 if ( j == nvars && foundslackvar )
    6311 {
    6312 SCIP_Real lb;
    6313 SCIP_Real ub;
    6314
    6315 lb = SCIPvarGetLbGlobal(consdata->slackvar);
    6316 ub = SCIPvarGetUbGlobal(consdata->slackvar);
    6317 if ( (SCIPisInfinity(scip, -lb) || SCIPisIntegral(scip, lb)) && (SCIPisInfinity(scip, ub) || SCIPisIntegral(scip, ub)) )
    6318 {
    6319 SCIP_Bool infeasible;
    6320
    6321 SCIP_CALL( SCIPchgVarImplType(scip, consdata->slackvar, SCIP_IMPLINTTYPE_WEAK, &infeasible) );
    6322 /* don't assert feasibility here because the presolver should detect infeasibility */
    6323 }
    6324 else
    6325 {
    6326 /* it can happen that the bounds of the slack variable have been changed to be non-integral in
    6327 * previous presolving steps. We then might get a problem with tightening the bounds. In this case,
    6328 * we just leave the slack variable to be continuous */
    6329 SCIPdebugMsg(scip, "Cannot declare slack variable (<%s>) weakly implied integral, since global bound is non-integral: (%g, %g).\n",
    6330 SCIPvarGetName(consdata->slackvar), SCIPvarGetLbGlobal(consdata->slackvar), SCIPvarGetUbGlobal(consdata->slackvar));
    6331 }
    6332 }
    6333 }
    6334 }
    6335
    6336 /* perform one presolving round */
    6337 SCIP_CALL( presolRoundIndicator(scip, conshdlrdata, cons, consdata,
    6338 conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip), &cutoff, &success, ndelconss, nfixedvars) );
    6339
    6340 if ( cutoff )
    6341 {
    6342 *result = SCIP_CUTOFF;
    6343 return SCIP_OKAY;
    6344 }
    6345 if ( success )
    6346 *result = SCIP_SUCCESS;
    6347 }
    6348 }
    6349
    6350 /* determine whether other methods have found reductions */
    6351 noReductions = nnewfixedvars == 0 && nnewaggrvars == 0 && nnewchgvartypes == 0 && nnewchgbds == 0
    6352 && nnewdelconss == 0 && nnewchgcoefs == 0 && nnewchgsides == 0;
    6353
    6354 /* add variable upper bounds after bounds are likely to be strengthened */
    6355 if ( noReductions && *result != SCIP_SUCCESS && conshdlrdata->addcouplingcons && ! conshdlrdata->addedcouplingcons )
    6356 {
    6357 int ngen;
    6358
    6359 /* create variable upper bounds, possibly removing indicator constraints */
    6360 SCIP_CALL( createVarUbs(scip, conshdlrdata, conss, nconss, &ngen) );
    6361
    6362 if ( ngen > 0 )
    6363 {
    6364 *result = SCIP_SUCCESS;
    6365 *nupgdconss += ngen;
    6366 if ( conshdlrdata->removeindicators )
    6367 *ndelconss += ngen;
    6368 }
    6369 conshdlrdata->addedcouplingcons = TRUE;
    6370 }
    6371
    6372 SCIPdebug( SCIPdebugMsg(scip, "Presolved %d constraints (fixed %d variables, removed 0 variables, and deleted %d constraints).\n",
    6373 nconss, *nfixedvars - oldnfixedvars, *ndelconss - oldndelconss); )
    6374
    6375 return SCIP_OKAY; /*lint !e438*/
    6376}
    6377
    6378
    6379/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved)
    6380 *
    6381 * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
    6382 * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
    6383 * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not inserted.
    6384 */
    6385static
    6386SCIP_DECL_CONSINITLP(consInitlpIndicator)
    6387{
    6388 int c;
    6389 SCIP_CONSHDLRDATA* conshdlrdata;
    6390
    6391 assert( scip != NULL );
    6392 assert( conshdlr != NULL );
    6393
    6395
    6396 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6397 assert( conshdlrdata != NULL );
    6398
    6399 *infeasible = FALSE;
    6400
    6401 /* check whether coupling constraints should be added */
    6402 if ( ! conshdlrdata->addcoupling )
    6403 return SCIP_OKAY;
    6404
    6405 /* check whether coupling constraints have been added already */
    6406 if ( conshdlrdata->addcouplingcons && conshdlrdata->addedcouplingcons )
    6407 return SCIP_OKAY;
    6408
    6409 SCIPdebugMsg(scip, "Handle initial rows for %d indicator constraints.\n", nconss);
    6410
    6411 /* check each constraint */
    6412 for (c = 0; c < nconss && !(*infeasible); ++c)
    6413 {
    6414 SCIP_CONSDATA* consdata;
    6415 SCIP_Real ub;
    6416
    6417 assert( conss != NULL );
    6418 assert( conss[c] != NULL );
    6419 consdata = SCIPconsGetData(conss[c]);
    6420 assert( consdata != NULL );
    6421
    6422 /* do not add inequalities if there are no linear constraints (no slack variable available) */
    6423 if ( ! consdata->linconsactive )
    6424 continue;
    6425
    6426 /* get upper bound for slack variable in linear constraint */
    6427 ub = SCIPvarGetUbGlobal(consdata->slackvar);
    6428 assert( ! SCIPisNegative(scip, ub) );
    6429
    6430 /* insert corresponding row if helpful and coefficient is not too large */
    6431 if ( ub <= conshdlrdata->maxcouplingvalue )
    6432 {
    6433 char name[50];
    6434
    6435#ifndef NDEBUG
    6436 (void) SCIPsnprintf(name, 50, "couple%d", c);
    6437#else
    6438 name[0] = '\0';
    6439#endif
    6440
    6441 /* add variable upper bound if required */
    6442 if ( conshdlrdata->addcouplingcons )
    6443 {
    6444 SCIP_CONS* cons;
    6445
    6446 assert( ! conshdlrdata->addedcouplingcons );
    6447
    6448 SCIPdebugMsg(scip, "Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
    6449
    6450 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
    6452
    6453 SCIP_CALL( SCIPaddCons(scip, cons) );
    6454 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    6455 }
    6456 else
    6457 {
    6458 SCIP_ROW* row;
    6459
    6460 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, FALSE, FALSE, FALSE) );
    6462
    6463 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
    6464 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
    6466
    6467 SCIPdebugMsg(scip, "Insert coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
    6468#ifdef SCIP_OUTPUT
    6469 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
    6470#endif
    6471 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
    6472 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    6473 }
    6474 }
    6475 }
    6476
    6477 return SCIP_OKAY;
    6478}
    6479
    6480
    6481/** separation method of constraint handler for LP solutions */
    6482static
    6483SCIP_DECL_CONSSEPALP(consSepalpIndicator)
    6484{ /*lint --e{715}*/
    6485 assert( scip != NULL );
    6486 assert( conshdlr != NULL );
    6487 assert( conss != NULL );
    6488 assert( result != NULL );
    6489
    6491
    6492 /* perform separation */
    6493 SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, NULL, SCIP_TYPE_SEPALP, result) );
    6494
    6495 return SCIP_OKAY;
    6496}
    6497
    6498
    6499/** separation method of constraint handler for arbitrary primal solutions */
    6500static
    6501SCIP_DECL_CONSSEPASOL(consSepasolIndicator)
    6502{ /*lint --e{715}*/
    6503 assert( scip != NULL );
    6504 assert( conshdlr != NULL );
    6505 assert( conss != NULL );
    6506 assert( result != NULL );
    6507
    6509
    6510 /* perform separation */
    6511 SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, sol, SCIP_TYPE_SEPASOL, result) );
    6512
    6513 return SCIP_OKAY;
    6514}
    6515
    6516
    6517/** constraint enforcing method of constraint handler for LP solutions */
    6518static
    6519SCIP_DECL_CONSENFOLP(consEnfolpIndicator)
    6520{ /*lint --e{715}*/
    6521 SCIP_CONSHDLRDATA* conshdlrdata;
    6522
    6523 assert( scip != NULL );
    6524 assert( conshdlr != NULL );
    6525 assert( conss != NULL );
    6526 assert( result != NULL );
    6527
    6529
    6530 if ( solinfeasible )
    6531 {
    6532 *result = SCIP_FEASIBLE;
    6533 return SCIP_OKAY;
    6534 }
    6535
    6536 /* get constraint handler data */
    6537 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6538 assert( conshdlrdata != NULL );
    6539
    6540 SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, NULL, SCIP_TYPE_ENFOLP, conshdlrdata->genlogicor, result) );
    6541
    6542 return SCIP_OKAY;
    6543}
    6544
    6545
    6546/** constraint enforcing method of constraint handler for relaxation solutions */
    6547static
    6548SCIP_DECL_CONSENFORELAX(consEnforelaxIndicator)
    6549{ /*lint --e{715}*/
    6550 SCIP_CONSHDLRDATA* conshdlrdata;
    6551
    6552 assert( scip != NULL );
    6553 assert( conshdlr != NULL );
    6554 assert( conss != NULL );
    6555 assert( result != NULL );
    6556
    6558
    6559 if ( solinfeasible )
    6560 {
    6561 *result = SCIP_FEASIBLE;
    6562 return SCIP_OKAY;
    6563 }
    6564
    6565 /* get constraint handler data */
    6566 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6567 assert( conshdlrdata != NULL );
    6568
    6569 SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, sol, SCIP_TYPE_ENFORELAX, conshdlrdata->genlogicor, result) );
    6570
    6571 return SCIP_OKAY;
    6572}
    6573
    6574
    6575/** constraint enforcing method of constraint handler for pseudo solutions */
    6576static
    6577SCIP_DECL_CONSENFOPS(consEnfopsIndicator)
    6578{ /*lint --e{715}*/
    6579 assert( scip != NULL );
    6580 assert( conshdlr != NULL );
    6581 assert( conss != NULL );
    6582 assert( result != NULL );
    6583
    6585
    6586 if ( solinfeasible )
    6587 {
    6588 *result = SCIP_FEASIBLE;
    6589 return SCIP_OKAY;
    6590 }
    6591
    6592 if ( objinfeasible )
    6593 {
    6594 *result = SCIP_DIDNOTRUN;
    6595 return SCIP_OKAY;
    6596 }
    6597
    6598 SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, NULL, SCIP_TYPE_ENFOPS, TRUE, result) );
    6599
    6600 return SCIP_OKAY;
    6601}
    6602
    6603
    6604/** feasibility check method of constraint handler for integral solutions */
    6605static
    6606SCIP_DECL_CONSCHECK(consCheckIndicator)
    6607{ /*lint --e{715}*/
    6608 SCIP_SOL* trysol = NULL;
    6609 SCIP_CONSHDLRDATA* conshdlrdata;
    6610 SCIP_Bool someLinconsNotActive;
    6611 SCIP_Bool changedSol;
    6612 int c;
    6613
    6614 assert( scip != NULL );
    6615 assert( conshdlr != NULL );
    6616 assert( conss != NULL );
    6617 assert( result != NULL );
    6618
    6620
    6621 SCIPdebugMsg(scip, "Checking %d indicator constraints <%s>.\n", nconss, SCIPconshdlrGetName(conshdlr) );
    6622
    6623 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6624 assert( conshdlrdata != NULL );
    6625
    6626 /* try to repair solution below, if it makes sense (will send solution to trysol heuristic in any case (see below) */
    6627 if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM && SCIPgetStage(scip) < SCIP_STAGE_SOLVED && conshdlrdata->trysolutions && conshdlrdata->heurtrysol != NULL )
    6628 {
    6629 SCIP_CALL( SCIPcreateSolCopy(scip, &trysol, sol) );
    6630 assert( trysol != NULL );
    6631 }
    6632
    6633 /* check each constraint */
    6634 *result = SCIP_FEASIBLE;
    6635 changedSol = FALSE;
    6636 someLinconsNotActive = FALSE;
    6637 for (c = 0; c < nconss; ++c)
    6638 {
    6639 SCIP_CONSDATA* consdata;
    6640
    6641 assert( conss[c] != NULL );
    6642 consdata = SCIPconsGetData(conss[c]);
    6643 assert( consdata != NULL );
    6644 assert( consdata->binvar != NULL );
    6645
    6646 /* if the linear constraint has not been generated, we do nothing */
    6647 if ( ! consdata->linconsactive )
    6648 {
    6649 someLinconsNotActive = TRUE;
    6650 continue;
    6651 }
    6652
    6653 assert( consdata->slackvar != NULL );
    6654 /* if printreason is true it can happen that non-integral solutions are checked */
    6655 assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
    6656
    6657 /* if constraint is infeasible */
    6658 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) &&
    6659 ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) )
    6660 {
    6661 SCIP_Real absviol = REALABS(SCIPgetSolVal(scip, sol, consdata->slackvar));
    6662 SCIP_Real relviol = SCIPrelDiff(absviol, 0.0);
    6663
    6664 if( sol != NULL )
    6665 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
    6666
    6667 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
    6668 *result = SCIP_INFEASIBLE;
    6669
    6670 if ( printreason )
    6671 {
    6672 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
    6673 SCIPinfoMessage(scip, NULL, ";\nviolation: <%s> = %g and <%s> = %.15g\n",
    6674 SCIPvarGetName(consdata->binvar), SCIPgetSolVal(scip, sol, consdata->binvar),
    6675 SCIPvarGetName(consdata->slackvar), SCIPgetSolVal(scip, sol, consdata->slackvar));
    6676 }
    6677
    6678 /* try to make solution feasible if it makes sense - otherwise exit */
    6679 if ( trysol != NULL )
    6680 {
    6681 SCIP_Bool changed;
    6682 SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
    6683 changedSol = changedSol || changed;
    6684 }
    6685 else
    6686 {
    6687 SCIPdebugMsg(scip, "Indicator constraint %s is not feasible.\n", SCIPconsGetName(conss[c]));
    6688
    6689 if ( ! completely )
    6690 return SCIP_OKAY;
    6691 }
    6692 }
    6693 else
    6694 {
    6695 if ( trysol != NULL )
    6696 {
    6697 SCIP_Bool changed;
    6698 SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
    6699 changedSol = changedSol || changed;
    6700 }
    6701 }
    6702 }
    6703
    6704 /* if some linear constraints are not active, we need to check feasibility via the alternative polyhedron */
    6705 if ( someLinconsNotActive )
    6706 {
    6707 SCIP_LPI* lp;
    6708 SCIP_Bool infeasible;
    6709 SCIP_Bool error;
    6710 SCIP_Bool* S;
    6711
    6712 lp = conshdlrdata->altlp;
    6713 assert( conshdlrdata->sepaalternativelp );
    6714
    6715 /* the check maybe called before we have build the alternative polyhedron -> return SCIP_INFEASIBLE */
    6716 if ( lp != NULL )
    6717 {
    6718#ifndef NDEBUG
    6719 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    6720#endif
    6721
    6722 /* change coefficients of bounds in alternative LP */
    6723 if ( conshdlrdata->updatebounds )
    6724 {
    6725 SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
    6726 }
    6727
    6728 /* scale first row if necessary */
    6729 SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
    6730
    6731 /* set objective function to current solution */
    6732 SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
    6733
    6734 SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
    6735
    6736 /* set up variables fixed to 1 */
    6737 for (c = 0; c < nconss; ++c)
    6738 {
    6739 SCIP_CONSDATA* consdata;
    6740
    6741 assert( conss[c] != NULL );
    6742 consdata = SCIPconsGetData(conss[c]);
    6743 assert( consdata != NULL );
    6744
    6745 /* if printreason is true it can happen that non-integral solutions are checked */
    6746 assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
    6747 if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
    6748 S[c] = TRUE;
    6749 else
    6750 S[c] = FALSE;
    6751 }
    6752
    6753 /* fix the variables in S */
    6754 SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
    6755
    6756 /* check feasibility */
    6758 SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, TRUE, &infeasible, &error) );
    6760
    6761 if ( error )
    6762 return SCIP_LPERROR;
    6763
    6764 if ( ! infeasible )
    6765 *result = SCIP_INFEASIBLE;
    6766
    6767 /* reset bounds */
    6768 SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
    6769
    6770#ifndef NDEBUG
    6771 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    6772#endif
    6773
    6775 }
    6776 else
    6777 *result = SCIP_INFEASIBLE;
    6778 }
    6779 else
    6780 {
    6781 /* tell heur_trysol about solution - it will pass it to SCIP */
    6782 if ( trysol != NULL && changedSol )
    6783 {
    6784 assert( conshdlrdata->heurtrysol != NULL );
    6785 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->heurtrysol, trysol) );
    6786 }
    6787 }
    6788
    6789 if ( trysol != NULL )
    6790 SCIP_CALL( SCIPfreeSol(scip, &trysol) );
    6791
    6792 if ( *result == SCIP_INFEASIBLE )
    6793 {
    6794 SCIPdebugMsg(scip, "Indicator constraints are not feasible.\n");
    6795 return SCIP_OKAY;
    6796 }
    6797
    6798 /* at this point we are feasible */
    6799 SCIPdebugMsg(scip, "Indicator constraints are feasible.\n");
    6800
    6801 return SCIP_OKAY;
    6802}
    6803
    6804
    6805/** domain propagation method of constraint handler */
    6806static
    6807SCIP_DECL_CONSPROP(consPropIndicator)
    6808{ /*lint --e{715}*/
    6809 SCIP_CONSHDLRDATA* conshdlrdata;
    6810 SCIP_Bool dualreductions;
    6811 int ngen = 0;
    6812 int c;
    6813
    6814 assert( scip != NULL );
    6815 assert( conshdlr != NULL );
    6816 assert( conss != NULL );
    6817 assert( result != NULL );
    6818
    6820
    6821 *result = SCIP_DIDNOTRUN;
    6822
    6823 assert( SCIPisTransformed(scip) );
    6824
    6825 SCIPdebugMsg(scip, "Start propagation of constraint handler <%s>.\n", SCIPconshdlrGetName(conshdlr));
    6826
    6827 /* get constraint handler data */
    6828 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6829 assert( conshdlrdata != NULL );
    6830
    6831 /* avoid propagation if no bound has changed */
    6832 if ( ! conshdlrdata->boundhaschanged && ! SCIPinRepropagation(scip) && ! conshdlrdata->linconsboundschanged )
    6833 {
    6834 *result = SCIP_DIDNOTFIND;
    6835 return SCIP_OKAY;
    6836 }
    6837
    6838 /* if first time called, add events on variables of linear constraint */
    6839 if ( !conshdlrdata->linconsevents )
    6840 {
    6841 for (c = 0; c < nconss; ++c)
    6842 {
    6843 SCIP_CONSDATA* consdata;
    6844 SCIP_VAR** vars;
    6845 SCIP_Real* vals;
    6846 int nvars;
    6847 int j;
    6848 assert( conss[c] != NULL );
    6849
    6850 consdata = SCIPconsGetData(conss[c]);
    6851 assert( consdata != NULL );
    6852
    6853 /* if the linear constraint is not present, we continue */
    6854 if ( ! consdata->linconsactive )
    6855 continue;
    6856
    6857 /* do not add events if upper bound of slackvar is already small */
    6858 if ( SCIPvarGetUbLocal(consdata->slackvar) <= conshdlrdata->maxcouplingvalue )
    6859 continue;
    6860
    6861 /* do not add events if it is not a <= inequality; we do not propagate in this case */
    6862 if ( SCIPisInfinity(scip, SCIPgetRhsLinear(scip, consdata->lincons) ) )
    6863 continue;
    6864
    6865 assert( consdata->lincons != NULL );
    6866 vars = SCIPgetVarsLinear(scip, consdata->lincons);
    6867 vals = SCIPgetValsLinear(scip, consdata->lincons);
    6868 nvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    6869 assert( consdata->slackvar != NULL );
    6870 assert( nvars != 0 );
    6871
    6872 /* alloc memory to store events on variables of linear constraint; otherwise we can not drop the events when the cons is deleted */
    6873 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varswithevents, nvars - 1) );
    6874 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventtypes, nvars - 1) );
    6875
    6876 for (j = 0; j < nvars; ++j)
    6877 {
    6878 if ( vars[j] == consdata->slackvar )
    6879 continue;
    6880
    6881 /* catch only bound changes which are important for propagation of max activity to upper bound of slackvar */
    6882 if ( vals[j] > 0.0 )
    6883 {
    6884 SCIP_CALL( SCIPcatchVarEvent(scip, vars[j], SCIP_EVENTTYPE_UBTIGHTENED, conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
    6885 consdata->varswithevents[consdata->nevents] = vars[j];
    6886 consdata->eventtypes[consdata->nevents] = SCIP_EVENTTYPE_UBTIGHTENED;
    6887 consdata->nevents++;
    6888 }
    6889 else
    6890 {
    6891 SCIP_CALL( SCIPcatchVarEvent(scip, vars[j], SCIP_EVENTTYPE_LBTIGHTENED, conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
    6892 consdata->varswithevents[consdata->nevents] = vars[j];
    6893 consdata->eventtypes[consdata->nevents] = SCIP_EVENTTYPE_LBTIGHTENED;
    6894 consdata->nevents++;
    6895 }
    6896 }
    6897 assert( consdata->nevents == nvars - 1 );
    6898 }
    6899 conshdlrdata->linconsevents = TRUE;
    6900 }
    6901
    6902 /* already mark that no bound has changed */
    6903 conshdlrdata->boundhaschanged = FALSE;
    6904 conshdlrdata->linconsboundschanged = FALSE;
    6905
    6906 dualreductions = conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip);
    6907
    6908 /* check each constraint */
    6909 for (c = 0; c < nconss; ++c)
    6910 {
    6911 SCIP_CONS* cons;
    6912 SCIP_CONSDATA* consdata;
    6913 SCIP_Bool cutoff;
    6914 int cnt;
    6915
    6916 *result = SCIP_DIDNOTFIND;
    6917
    6918 assert( conss[c] != NULL );
    6919 cons = conss[c];
    6920 consdata = SCIPconsGetData(cons);
    6921 assert( consdata != NULL );
    6922
    6923#ifdef SCIP_MORE_DEBUG
    6924 SCIPdebugMsg(scip, "Propagating indicator constraint <%s>.\n", SCIPconsGetName(cons) );
    6925#endif
    6926
    6927 SCIP_CALL( propIndicator(scip, cons, consdata, conshdlrdata, dualreductions, conshdlrdata->addopposite, &cutoff, &cnt) );
    6928
    6929 if ( cutoff )
    6930 {
    6931 *result = SCIP_CUTOFF;
    6932 return SCIP_OKAY;
    6933 }
    6934 ngen += cnt;
    6935 }
    6936
    6937 SCIPdebugMsg(scip, "Propagated %d domains in constraint handler <%s>.\n", ngen, SCIPconshdlrGetName(conshdlr));
    6938 if ( ngen > 0 )
    6939 *result = SCIP_REDUCEDDOM;
    6940
    6941 return SCIP_OKAY;
    6942}
    6943
    6944
    6945/** propagation conflict resolving method of constraint handler
    6946 *
    6947 * We check which bound changes were the reason for infeasibility. We use that @a inferinfo is 0 if
    6948 * the binary variable has bounds that fix it to be nonzero (these bounds are the reason). Likewise
    6949 * @a inferinfo is 1 if the slack variable has bounds that fix it to be nonzero.
    6950 */
    6951static
    6952SCIP_DECL_CONSRESPROP(consRespropIndicator)
    6953{ /*lint --e{715}*/
    6954 SCIP_CONSDATA* consdata;
    6955
    6956 assert( scip != NULL );
    6957 assert( cons != NULL );
    6958 assert( infervar != NULL );
    6959 assert( bdchgidx != NULL );
    6960 assert( result != NULL );
    6961
    6963
    6964 *result = SCIP_DIDNOTFIND;
    6965 SCIPdebugMsg(scip, "Propagation resolution method of indicator constraint <%s>.\n", SCIPconsGetName(cons));
    6966
    6967 consdata = SCIPconsGetData(cons);
    6968 assert( consdata != NULL );
    6969 assert( inferinfo == 0 || inferinfo == 1 || inferinfo == 2 || inferinfo == 3 );
    6970 assert( consdata->linconsactive );
    6971
    6972 /* if the binary variable was the reason */
    6973 if ( inferinfo == 0 )
    6974 {
    6975 assert( SCIPgetVarLbAtIndex(scip, consdata->binvar, bdchgidx, FALSE) > 0.5 );
    6976 assert( infervar != consdata->binvar );
    6977
    6978 SCIP_CALL( SCIPaddConflictLb(scip, consdata->binvar, bdchgidx) );
    6979 }
    6980 else if ( inferinfo == 1 )
    6981 {
    6982 /* if the slack variable fixed to a positive value was the reason */
    6983 assert( infervar != consdata->slackvar );
    6984 /* Use a weaker comparison to SCIPgetVarLbAtIndex here (i.e., SCIPisPositive instead of SCIPisFeasPositive),
    6985 * because SCIPgetVarLbAtIndex might differ from the local bound at time bdchgidx by epsilon. */
    6986 assert( SCIPisPositive(scip, SCIPgetVarLbAtIndex(scip, consdata->slackvar, bdchgidx, FALSE)) );
    6987 SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, bdchgidx) );
    6988 }
    6989 else if ( inferinfo == 2 )
    6990 {
    6991 assert( SCIPisFeasZero(scip, SCIPgetVarUbAtIndex(scip, consdata->slackvar, bdchgidx, FALSE)) );
    6992 assert( SCIPconshdlrGetData(conshdlr)->dualreductions && SCIPallowStrongDualReds(scip) && SCIPallowWeakDualReds(scip) );
    6993 SCIP_CALL( SCIPaddConflictUb(scip, consdata->slackvar, bdchgidx) );
    6994 }
    6995 else
    6996 {
    6997 SCIP_VAR** linconsvars;
    6998 SCIP_Real* linconsvals;
    6999 int nlinconsvars;
    7000 int j;
    7001
    7002 assert( inferinfo == 3 );
    7003
    7004 /* mark variables in linear constraint */
    7005 nlinconsvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    7006 linconsvars = SCIPgetVarsLinear(scip, consdata->lincons);
    7007 linconsvals = SCIPgetValsLinear(scip, consdata->lincons);
    7008
    7009 for (j = 0; j < nlinconsvars; ++j)
    7010 {
    7011 if ( linconsvals[j] > 0.0 )
    7012 {
    7013 assert( ! SCIPisInfinity(scip, SCIPgetVarUbAtIndex(scip, linconsvars[j], bdchgidx, FALSE)) );
    7014 SCIP_CALL( SCIPaddConflictUb(scip, linconsvars[j], bdchgidx) );
    7015 }
    7016 else
    7017 {
    7018 assert( ! SCIPisInfinity(scip, -SCIPgetVarLbAtIndex(scip, linconsvars[j], bdchgidx, FALSE)) );
    7019 SCIP_CALL( SCIPaddConflictLb(scip, linconsvars[j], bdchgidx) );
    7020 }
    7021 }
    7022 }
    7023
    7024 *result = SCIP_SUCCESS;
    7025
    7026 return SCIP_OKAY;
    7027}
    7028
    7029
    7030/** variable rounding lock method of constraint handler
    7031 *
    7032 * The up-rounding of the binary and slack variable may violate the constraint. If the linear
    7033 * constraint is not active, we lock all variables in the depending constraint - otherwise they
    7034 * will be fixed by dual presolving methods.
    7035 */
    7036static
    7037SCIP_DECL_CONSLOCK(consLockIndicator)
    7038{
    7039 SCIP_CONSDATA* consdata;
    7040
    7041 assert( scip != NULL );
    7042 assert( conshdlr != NULL );
    7043 assert( cons != NULL );
    7044
    7046
    7047 consdata = SCIPconsGetData(cons);
    7048 assert( consdata != NULL );
    7049 assert( consdata->binvar != NULL );
    7050
    7051#ifdef SCIP_MORE_DEBUG
    7052 SCIPdebugMsg(scip, "%socking constraint <%s>.\n", (nlocksneg < 0) || (nlockspos < 0) ? "Unl" : "L", SCIPconsGetName(cons));
    7053#endif
    7054
    7055 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->binvar, locktype, nlocksneg, nlockspos) );
    7056
    7057 if ( consdata->linconsactive )
    7058 {
    7059 assert( consdata->slackvar != NULL );
    7060
    7061 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->slackvar, locktype, nlocksneg, nlockspos) );
    7062 }
    7063 else
    7064 {
    7065 SCIP_VAR** linvars;
    7066 SCIP_Real* linvals;
    7067 SCIP_Bool haslhs;
    7068 SCIP_Bool hasrhs;
    7069 int nlinvars;
    7070 int j;
    7071
    7072 assert( consdata->lincons != NULL );
    7073 assert( consdata->slackvar == NULL );
    7074
    7075 nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    7076 linvars = SCIPgetVarsLinear(scip, consdata->lincons);
    7077 linvals = SCIPgetValsLinear(scip, consdata->lincons);
    7078 haslhs = ! SCIPisInfinity(scip, REALABS(SCIPgetLhsLinear(scip, consdata->lincons)));
    7079 hasrhs = ! SCIPisInfinity(scip, REALABS(SCIPgetRhsLinear(scip, consdata->lincons)));
    7080
    7081 for (j = 0; j < nlinvars; ++j)
    7082 {
    7083 assert( ! SCIPisZero(scip, linvals[j]) );
    7084 if ( SCIPisPositive(scip, linvals[j]) )
    7085 {
    7086 if ( haslhs )
    7087 {
    7088 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlockspos, nlocksneg) );
    7089 }
    7090 if ( hasrhs )
    7091 {
    7092 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlocksneg, nlockspos) );
    7093 }
    7094 }
    7095 else
    7096 {
    7097 if ( haslhs )
    7098 {
    7099 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlocksneg, nlockspos) );
    7100 }
    7101 if ( hasrhs )
    7102 {
    7103 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlockspos, nlocksneg) );
    7104 }
    7105 }
    7106 }
    7107 }
    7108
    7109 return SCIP_OKAY;
    7110}
    7111
    7112
    7113/** constraint display method of constraint handler */
    7114static
    7115SCIP_DECL_CONSPRINT(consPrintIndicator)
    7116{
    7117 SCIP_CONSDATA* consdata;
    7118 SCIP_VAR* binvar;
    7119 int rhs;
    7120
    7121 assert( scip != NULL );
    7122 assert( conshdlr != NULL );
    7123 assert( cons != NULL );
    7124
    7126
    7127 consdata = SCIPconsGetData(cons);
    7128 assert( consdata != NULL );
    7129 assert( consdata->binvar != NULL );
    7130
    7131 binvar = consdata->binvar;
    7132 rhs = 1;
    7134 {
    7135 rhs = 0;
    7136 binvar = SCIPvarGetNegatedVar(binvar);
    7137 }
    7138 SCIPinfoMessage(scip, file, "<%s> = %d", SCIPvarGetName(binvar), rhs);
    7139
    7140 assert( consdata->slackvar != NULL );
    7141 assert( consdata->lincons != NULL );
    7142 SCIPinfoMessage(scip, file, " -> <%s> = 0", SCIPvarGetName(consdata->slackvar));
    7143 SCIPinfoMessage(scip, file, " (<%s>)", SCIPconsGetName(consdata->lincons));
    7144
    7145 return SCIP_OKAY;
    7146}
    7147
    7148
    7149/** constraint copying method of constraint handler */
    7150static
    7151SCIP_DECL_CONSCOPY(consCopyIndicator)
    7152{ /*lint --e{715}*/
    7153 SCIP_CONSDATA* sourceconsdata;
    7154 SCIP_CONS* targetlincons = NULL;
    7155 SCIP_VAR* targetbinvar = NULL;
    7156 SCIP_VAR* targetslackvar = NULL;
    7157 SCIP_CONS* sourcelincons;
    7158 SCIP_CONSHDLR* conshdlrlinear;
    7159 const char* consname;
    7160
    7161 assert( scip != NULL );
    7162 assert( sourcescip != NULL );
    7163 assert( sourcecons != NULL );
    7164
    7166
    7167 *valid = TRUE;
    7168
    7169 if ( name != NULL )
    7170 consname = name;
    7171 else
    7172 consname = SCIPconsGetName(sourcecons);
    7173
    7174#ifdef SCIP_MORE_DEBUG
    7175 SCIPdebugMsg(scip, "Copying indicator constraint <%s> ...\n", consname);
    7176#endif
    7177
    7178 if ( modifiable )
    7179 {
    7180 SCIPwarningMessage(scip, "cannot create modifiable indicator constraint when trying to copy constraint <%s>,\n", SCIPconsGetName(sourcecons));
    7181 *valid = FALSE;
    7182 return SCIP_OKAY;
    7183 }
    7184
    7185 sourceconsdata = SCIPconsGetData(sourcecons);
    7186 assert( sourceconsdata != NULL );
    7187
    7188 /* get linear constraint */
    7189 sourcelincons = sourceconsdata->lincons;
    7190
    7191 /* if the constraint has been deleted -> create empty constraint (multi-aggregation might still contain slack variable, so indicator is valid) */
    7192 if ( SCIPconsIsDeleted(sourcelincons) )
    7193 {
    7194 SCIPdebugMsg(scip, "Linear constraint <%s> deleted! Create empty linear constraint.\n", SCIPconsGetName(sourceconsdata->lincons));
    7195
    7196 SCIP_CALL( SCIPcreateConsLinear(scip, &targetlincons, "dummy", 0, NULL, NULL, 0.0, SCIPinfinity(scip),
    7198 SCIP_CALL( SCIPaddCons(scip, targetlincons) );
    7199 }
    7200 else
    7201 {
    7202 /* get copied version of linear constraint */
    7203 assert( sourcelincons != NULL );
    7204 conshdlrlinear = SCIPfindConshdlr(sourcescip, "linear");
    7205 assert( conshdlrlinear != NULL );
    7206
    7207 /* if copying scip after transforming the original instance before presolving, we need to correct the linear
    7208 * constraint pointer */
    7209 if ( SCIPconsIsTransformed(sourcecons) && ! SCIPconsIsTransformed(sourcelincons) )
    7210 {
    7211 SCIP_CONS* translincons;
    7212
    7213 /* adjust the linear constraint in the original constraint (no need to release translincons) */
    7214 SCIP_CALL( SCIPgetTransformedCons(sourcescip, sourcelincons, &translincons) );
    7215 assert( translincons != NULL );
    7216 SCIP_CALL( SCIPreleaseCons(sourcescip, &sourceconsdata->lincons) );
    7217 SCIP_CALL( SCIPcaptureCons(sourcescip, translincons) );
    7218 sourceconsdata->lincons = translincons;
    7219 sourcelincons = translincons;
    7220 }
    7221
    7222 SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, sourcelincons, &targetlincons, conshdlrlinear, varmap, consmap, SCIPconsGetName(sourcelincons),
    7223 SCIPconsIsInitial(sourcelincons), SCIPconsIsSeparated(sourcelincons), SCIPconsIsEnforced(sourcelincons), SCIPconsIsChecked(sourcelincons),
    7224 SCIPconsIsPropagated(sourcelincons), SCIPconsIsLocal(sourcelincons), SCIPconsIsModifiable(sourcelincons), SCIPconsIsDynamic(sourcelincons),
    7225 SCIPconsIsRemovable(sourcelincons), SCIPconsIsStickingAtNode(sourcelincons), global, valid) );
    7226 }
    7227
    7228 /* find copied variable corresponding to binvar */
    7229 if ( *valid )
    7230 {
    7231 SCIP_VAR* sourcebinvar;
    7232
    7233 sourcebinvar = sourceconsdata->binvar;
    7234 assert( sourcebinvar != NULL );
    7235
    7236 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcebinvar, &targetbinvar, varmap, consmap, global, valid) );
    7237 }
    7238
    7239 /* find copied variable corresponding to slackvar */
    7240 if ( *valid )
    7241 {
    7242 SCIP_VAR* sourceslackvar;
    7243
    7244 sourceslackvar = sourceconsdata->slackvar;
    7245 assert( sourceslackvar != NULL );
    7246
    7247 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourceslackvar, &targetslackvar, varmap, consmap, global, valid) );
    7248 }
    7249
    7250 /* create indicator constraint */
    7251 if ( *valid )
    7252 {
    7253 assert( targetlincons != NULL );
    7254 assert( targetbinvar != NULL );
    7255 assert( targetslackvar != NULL );
    7256
    7257 /* creates indicator constraint (and captures the linear constraint) */
    7258 /* Note that the copied constraint has activeone = TRUE, since the target binary variable already was negated if needed. */
    7259 SCIP_CALL( SCIPcreateConsIndicatorGenericLinCons(scip, cons, consname, targetbinvar, targetlincons, targetslackvar, TRUE,
    7260 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
    7261 }
    7262 else
    7263 {
    7264 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "could not copy linear constraint <%s>\n", SCIPconsGetName(sourcelincons));
    7265 }
    7266
    7267 /* release copied linear constraint */
    7268 if ( targetlincons != NULL )
    7269 {
    7270 SCIP_CALL( SCIPreleaseCons(scip, &targetlincons) );
    7271 }
    7272
    7273 return SCIP_OKAY;
    7274}
    7275
    7276
    7277/** constraint parsing method of constraint handler */
    7278static
    7279SCIP_DECL_CONSPARSE(consParseIndicator)
    7280{ /*lint --e{715}*/
    7281 char binvarname[1024];
    7282 char slackvarname[1024];
    7283 char linconsname[1024];
    7284 SCIP_VAR* binvar;
    7285 SCIP_VAR* slackvar;
    7286 SCIP_CONS* lincons;
    7287 int zeroone;
    7288 int nargs;
    7289
    7290 *success = TRUE;
    7291
    7292 /* read indicator constraint */
    7293 /* coverity[secure_coding] */
    7294 nargs = sscanf(str, " <%1023[^>]> = %d -> <%1023[^>]> = 0 (<%1023[^>]>)", binvarname, &zeroone, slackvarname, linconsname);
    7295
    7296 /* downward compatible: accept missing linear constraint at end */
    7297 if ( nargs != 3 && nargs != 4 )
    7298 {
    7299 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0 (<lincons>).\n%s\n", str);
    7300 *success = FALSE;
    7301 return SCIP_OKAY;
    7302 }
    7303
    7304 if ( zeroone != 0 && zeroone != 1 )
    7305 {
    7306 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0.\n%s\n", str);
    7307 *success = FALSE;
    7308 return SCIP_OKAY;
    7309 }
    7310
    7311 /* get binary variable */
    7312 binvar = SCIPfindVar(scip, binvarname);
    7313 if ( binvar == NULL )
    7314 {
    7315 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", binvarname);
    7316 *success = FALSE;
    7317 return SCIP_OKAY;
    7318 }
    7319 /* check whether we need the complemented variable */
    7320 if ( zeroone == 0 )
    7321 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
    7322
    7323 /* get slack variable */
    7324 slackvar = SCIPfindVar(scip, slackvarname);
    7325 if ( slackvar == NULL )
    7326 {
    7327 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", slackvarname);
    7328 *success = FALSE;
    7329 return SCIP_OKAY;
    7330 }
    7331
    7332 /* determine linear constraint */
    7333 if ( nargs == 4 )
    7334 {
    7335 lincons = SCIPfindCons(scip, linconsname);
    7336 if ( lincons == NULL )
    7337 {
    7338 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown constraint <%s>\n", linconsname);
    7339 *success = FALSE;
    7340 return SCIP_OKAY;
    7341 }
    7342 if ( strncmp(SCIPconshdlrGetName(SCIPconsGetHdlr(lincons)), "linear", 6) != 0 )
    7343 {
    7344 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "constraint <%s> is not linear\n", linconsname);
    7345 *success = FALSE;
    7346 return SCIP_OKAY;
    7347 }
    7348 }
    7349 else
    7350 {
    7351 const char* posstr;
    7352
    7353 /* for backward compability try to determine name of linear constraint from variables names */
    7354 assert( nargs == 3 );
    7355
    7356 /* find matching linear constraint */
    7357 posstr = strstr(slackvarname, "indslack");
    7358 if ( posstr == NULL )
    7359 {
    7360 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "strange slack variable name: <%s>\n", slackvarname);
    7361 *success = FALSE;
    7362 return SCIP_OKAY;
    7363 }
    7364
    7365 /* overwrite binvarname: set up name for linear constraint */
    7366 (void) SCIPsnprintf(binvarname, 1023, "indlin%s", posstr+8);
    7367
    7368 lincons = SCIPfindCons(scip, binvarname);
    7369 if ( lincons == NULL )
    7370 {
    7371 /* if not found - check without indlin */
    7372 (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+9);
    7373 lincons = SCIPfindCons(scip, binvarname);
    7374
    7375 if ( lincons == NULL )
    7376 {
    7377 /* if not found - check without indrhs or indlhs */
    7378 (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+16);
    7379 lincons = SCIPfindCons(scip, binvarname);
    7380
    7381 if( lincons == NULL )
    7382 {
    7383 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: unknown linear constraint <indlin%s>, <%s> or <%s>.\n",
    7384 name, posstr+8, posstr+9, posstr+16);
    7385 *success = FALSE;
    7386 return SCIP_OKAY;
    7387 }
    7388 }
    7389 }
    7390 }
    7391 assert( lincons != NULL );
    7392
    7393 /* check correct linear constraint */
    7394 if ( ! SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, lincons)) && ! SCIPisInfinity(scip, SCIPgetRhsLinear(scip, lincons)) )
    7395 {
    7396 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: linear constraint is ranged or equation.\n", name);
    7397 *success = FALSE;
    7398 return SCIP_OKAY;
    7399 }
    7400
    7401 /* create indicator constraint */
    7402 SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
    7403 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
    7404
    7405 return SCIP_OKAY;
    7406}
    7407
    7408
    7409/** constraint enabling notification method of constraint handler */
    7410static
    7411SCIP_DECL_CONSENABLE(consEnableIndicator)
    7412{
    7413 SCIP_CONSHDLRDATA* conshdlrdata;
    7414 SCIP_CONSDATA* consdata;
    7415
    7416 assert( scip != NULL );
    7417 assert( conshdlr != NULL );
    7418 assert( cons != NULL );
    7419
    7421
    7422#ifdef SCIP_MORE_DEBUG
    7423 SCIPdebugMsg(scip, "Enabling constraint <%s>.\n", SCIPconsGetName(cons));
    7424#endif
    7425
    7426 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7427 assert( conshdlrdata != NULL );
    7428
    7429 consdata = SCIPconsGetData(cons);
    7430 assert( consdata != NULL );
    7431
    7432 if ( conshdlrdata->altlp != NULL )
    7433 {
    7434 assert( conshdlrdata->sepaalternativelp );
    7435
    7436 if ( consdata->colindex >= 0 )
    7437 {
    7438 SCIP_CALL( unfixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
    7439 }
    7440 }
    7441
    7442 return SCIP_OKAY;
    7443}
    7444
    7445
    7446/** constraint disabling notification method of constraint handler */
    7447static
    7448SCIP_DECL_CONSDISABLE(consDisableIndicator)
    7449{
    7450 SCIP_CONSHDLRDATA* conshdlrdata;
    7451
    7452 assert( scip != NULL );
    7453 assert( conshdlr != NULL );
    7454 assert( cons != NULL );
    7455
    7457
    7458#ifdef SCIP_MORE_DEBUG
    7459 SCIPdebugMsg(scip, "Disabling constraint <%s>.\n", SCIPconsGetName(cons));
    7460#endif
    7461
    7462 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7463 assert( conshdlrdata != NULL );
    7464
    7465 if ( conshdlrdata->altlp != NULL )
    7466 {
    7467 SCIP_CONSDATA* consdata;
    7468
    7469 consdata = SCIPconsGetData(cons);
    7470 assert( consdata != NULL );
    7471 assert( conshdlrdata->sepaalternativelp );
    7472
    7473 if ( consdata->colindex >= 0 )
    7474 {
    7475 SCIP_CALL( fixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
    7476 }
    7477 }
    7478
    7479 return SCIP_OKAY;
    7480}
    7481
    7482
    7483/** constraint method of constraint handler which returns the variables (if possible) */
    7484static
    7485SCIP_DECL_CONSGETVARS(consGetVarsIndicator)
    7486{ /*lint --e{715}*/
    7487 SCIP_CONSDATA* consdata;
    7488 int nvars = 0;
    7489
    7490 assert( scip != NULL );
    7491 assert( cons != NULL );
    7492 assert( vars != NULL );
    7493 assert( success != NULL );
    7494
    7495 if ( varssize < 0 )
    7496 return SCIP_INVALIDDATA;
    7497 assert( varssize >= 0 );
    7498
    7499 (*success) = TRUE;
    7500
    7501 /* if indicator constraint is already deleted */
    7502 if ( SCIPconsIsDeleted(cons) )
    7503 return SCIP_OKAY;
    7504
    7505 consdata = SCIPconsGetData(cons);
    7506 assert( consdata != NULL );
    7507 assert( consdata->lincons != NULL );
    7508
    7509 if ( consdata->binvar != NULL )
    7510 {
    7511 assert( varssize > 0 );
    7512 vars[nvars++] = consdata->binvar;
    7513 }
    7514 if ( consdata->slackvar != NULL )
    7515 {
    7516 assert( varssize > nvars );
    7517 vars[nvars++] = consdata->slackvar;
    7518 }
    7519
    7520 /* if linear constraint of indicator is already deleted */
    7521 if ( SCIPconsIsDeleted(consdata->lincons) )
    7522 return SCIP_OKAY;
    7523
    7524 SCIP_CALL( SCIPgetConsVars(scip, consdata->lincons, &(vars[nvars]), varssize - nvars, success) );
    7525
    7526 return SCIP_OKAY;
    7527}
    7528
    7529
    7530/** constraint method of constraint handler which returns the number of variables (if possible) */
    7531static
    7532SCIP_DECL_CONSGETNVARS(consGetNVarsIndicator)
    7533{ /*lint --e{715}*/
    7534 SCIP_CONSDATA* consdata;
    7535 int nlinvars;
    7536
    7537 assert( scip != NULL );
    7538 assert( cons != NULL );
    7539 assert( nvars != NULL );
    7540 assert( success != NULL );
    7541
    7542 *success = TRUE;
    7543 *nvars = 0;
    7544
    7545 /* if indicator constraint is already deleted */
    7546 if ( SCIPconsIsDeleted(cons) )
    7547 return SCIP_OKAY;
    7548
    7549 consdata = SCIPconsGetData(cons);
    7550 assert( consdata != NULL );
    7551 assert( consdata->lincons != NULL );
    7552
    7553 if ( consdata->binvar != NULL )
    7554 ++(*nvars);
    7555 if ( consdata->slackvar != NULL )
    7556 ++(*nvars);
    7557
    7558 /* if linear constraint of indicator is already deleted */
    7559 if ( SCIPconsIsDeleted(consdata->lincons) )
    7560 return SCIP_OKAY;
    7561
    7562 SCIP_CALL( SCIPgetConsNVars(scip, consdata->lincons, &nlinvars, success) );
    7563
    7564 if ( *success )
    7565 {
    7566 assert( nlinvars >= 0 );
    7567 *nvars += nlinvars;
    7568 }
    7569
    7570 return SCIP_OKAY;
    7571}
    7572
    7573
    7574/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
    7575static
    7576SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsIndicator)
    7577{
    7578 SCIP_CONS** indconss;
    7579 int nindconss;
    7580 int c;
    7581 SCIP_VAR* bestvar = NULL;
    7582 SCIP_Bool bestvarroundup = FALSE;
    7583 SCIP_Real bestscore = SCIP_REAL_MIN;
    7584
    7585 assert(scip != NULL);
    7586 assert(conshdlr != NULL);
    7587 assert(diveset != NULL);
    7588 assert(success != NULL);
    7589 assert(infeasible != NULL);
    7590
    7592
    7593 *success = FALSE;
    7594 *infeasible = FALSE;
    7595
    7596 indconss = SCIPconshdlrGetConss(conshdlr);
    7597 nindconss = SCIPconshdlrGetNConss(conshdlr);
    7598
    7599 /* loop over indicator constraints and score indicator variables with already integral solution value */
    7600 for (c = 0; c < nindconss; ++c)
    7601 {
    7602 /* check whether constraint is violated */
    7603 if ( SCIPisViolatedIndicator(scip, indconss[c], sol) )
    7604 {
    7605 SCIP_VAR* binvar;
    7606 SCIP_Real solval;
    7607
    7608 binvar = SCIPgetBinaryVarIndicator(indconss[c]);
    7609 solval = SCIPgetSolVal(scip, sol, binvar);
    7610
    7611 /* we only treat indicator variables with integral solution values that are not yet fixed */
    7612 if ( SCIPisFeasIntegral(scip, solval) && SCIPvarGetLbLocal(binvar) < SCIPvarGetUbLocal(binvar) - 0.5 )
    7613 {
    7614 SCIP_Real score;
    7615 SCIP_Bool roundup;
    7616
    7617 SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_INTEGRALITY, binvar, solval, 0.0,
    7618 &score, &roundup) );
    7619
    7620 /* best candidate maximizes the score */
    7621 if ( score > bestscore )
    7622 {
    7623 bestscore = score;
    7624 *success = TRUE;
    7625 bestvar = binvar;
    7626 bestvarroundup = roundup;
    7627 }
    7628 }
    7629 }
    7630 }
    7631
    7632 assert(! *success || bestvar != NULL);
    7633
    7634 if ( *success )
    7635 {
    7636 /* if the diving score voted for fixing the best variable to 1.0, we add this as the preferred bound change */
    7637 SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_UPWARDS, 1.0, bestvarroundup) );
    7638 SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_DOWNWARDS, 0.0, ! bestvarroundup) );
    7639 }
    7640
    7641 return SCIP_OKAY;
    7642}
    7643
    7644/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
    7645static
    7646SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphIndicator)
    7647{ /*lint --e{715}*/
    7648 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
    7649
    7650 return SCIP_OKAY;
    7651}
    7652
    7653/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
    7654static
    7655SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphIndicator)
    7656{ /*lint --e{715}*/
    7657 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
    7658
    7659 return SCIP_OKAY;
    7660}
    7661
    7662/* ---------------- Constraint specific interface methods ---------------- */
    7663
    7664/** creates the handler for indicator constraints and includes it in SCIP */
    7666 SCIP* scip /**< SCIP data structure */
    7667 )
    7668{
    7669 SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
    7670 SCIP_CONFLICTHDLR* conflicthdlr;
    7671 SCIP_CONSHDLRDATA* conshdlrdata;
    7672 SCIP_CONSHDLR* conshdlr;
    7673
    7674 /* create constraint handler data (used in conflicthdlrdata) */
    7675 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
    7676
    7677 /* create event handler for bound change events */
    7678 conshdlrdata->eventhdlrbound = NULL;
    7680 eventExecIndicatorBound, NULL) );
    7681 assert(conshdlrdata->eventhdlrbound != NULL);
    7682
    7683 /* create event handler for bound change events on linear constraint */
    7684 conshdlrdata->eventhdlrlinconsbound = NULL;
    7686 eventExecIndicatorLinconsBound, NULL) );
    7687 assert(conshdlrdata->eventhdlrlinconsbound != NULL);
    7688
    7689 /* create event handler for restart events */
    7690 conshdlrdata->eventhdlrrestart = NULL;
    7692 eventExecIndicatorRestart, NULL) );
    7693 assert( conshdlrdata->eventhdlrrestart != NULL );
    7694
    7695 conshdlrdata->heurtrysol = NULL;
    7696 conshdlrdata->sepaalternativelp = DEFAULT_SEPAALTERNATIVELP;
    7697 conshdlrdata->nolinconscont = DEFAULT_NOLINCONSCONT;
    7698 conshdlrdata->forcerestart = DEFAULT_FORCERESTART;
    7699 conshdlrdata->binvarhash = NULL;
    7700 conshdlrdata->binslackvarhash = NULL;
    7701
    7702 /* initialize constraint handler data */
    7703 initConshdlrData(scip, conshdlrdata);
    7704
    7705 /* the following three variables cannot be initialized in the above method, because initConshdlrData() is also called
    7706 * in the CONSINIT callback, but these variables might be used even before the is ccallback is called, so we would
    7707 * lose the data added before calling this callback */
    7708 conshdlrdata->addlincons = NULL;
    7709 conshdlrdata->naddlincons = 0;
    7710 conshdlrdata->maxaddlincons = 0;
    7711
    7712 /* include constraint handler */
    7715 consEnfolpIndicator, consEnfopsIndicator, consCheckIndicator, consLockIndicator,
    7716 conshdlrdata) );
    7717
    7718 assert( conshdlr != NULL );
    7719
    7720 /* set non-fundamental callbacks via specific setter functions */
    7721 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyIndicator, consCopyIndicator) );
    7722 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteIndicator) );
    7723 SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableIndicator) );
    7724 SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableIndicator) );
    7725 SCIP_CALL( SCIPsetConshdlrGetDiveBdChgs(scip, conshdlr, consGetDiveBdChgsIndicator) );
    7726 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitIndicator) );
    7727 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolIndicator) );
    7728 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeIndicator) );
    7729 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsIndicator) );
    7730 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsIndicator) );
    7731 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitIndicator) );
    7732 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreIndicator) );
    7733 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolIndicator) );
    7734 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpIndicator) );
    7735 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseIndicator) );
    7737 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintIndicator) );
    7740 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropIndicator) );
    7741 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpIndicator, consSepasolIndicator, CONSHDLR_SEPAFREQ,
    7743 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransIndicator) );
    7744 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxIndicator) );
    7745 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphIndicator) );
    7746 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphIndicator) );
    7747
    7748 /* add upgrading method */
    7749 if ( SCIPfindConshdlr(scip, "linear") != NULL )
    7750 {
    7751 /* include the linear constraint upgrade in the linear constraint handler */
    7753 }
    7754
    7755 /* create conflict handler data */
    7756 SCIP_CALL( SCIPallocBlockMemory(scip, &conflicthdlrdata) );
    7757 conflicthdlrdata->conshdlrdata = conshdlrdata;
    7758 conflicthdlrdata->conshdlr = conshdlr;
    7759 assert( conflicthdlrdata->conshdlr != NULL );
    7760
    7761 /* create conflict handler for indicator constraints */
    7763 conflictExecIndicator, conflicthdlrdata) );
    7764
    7765 SCIP_CALL( SCIPsetConflicthdlrFree(scip, conflicthdlr, conflictFreeIndicator) );
    7766
    7767 /* add indicator constraint handler parameters */
    7769 "constraints/indicator/branchindicators",
    7770 "Branch on indicator constraints in enforcing?",
    7771 &conshdlrdata->branchindicators, TRUE, DEFAULT_BRANCHINDICATORS, NULL, NULL) );
    7772
    7774 "constraints/indicator/genlogicor",
    7775 "Generate logicor constraints instead of cuts?",
    7776 &conshdlrdata->genlogicor, TRUE, DEFAULT_GENLOGICOR, NULL, NULL) );
    7777
    7779 "constraints/indicator/addcoupling",
    7780 "Add coupling constraints or rows if big-M is small enough?",
    7781 &conshdlrdata->addcoupling, TRUE, DEFAULT_ADDCOUPLING, NULL, NULL) );
    7782
    7784 "constraints/indicator/maxcouplingvalue",
    7785 "maximum coefficient for binary variable in coupling constraint",
    7786 &conshdlrdata->maxcouplingvalue, TRUE, DEFAULT_MAXCOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
    7787
    7789 "constraints/indicator/addcouplingcons",
    7790 "Add initial variable upper bound constraints, if 'addcoupling' is true?",
    7791 &conshdlrdata->addcouplingcons, TRUE, DEFAULT_ADDCOUPLINGCONS, NULL, NULL) );
    7792
    7794 "constraints/indicator/sepacouplingcuts",
    7795 "Should the coupling inequalities be separated dynamically?",
    7796 &conshdlrdata->sepacouplingcuts, TRUE, DEFAULT_SEPACOUPLINGCUTS, NULL, NULL) );
    7797
    7799 "constraints/indicator/sepacouplinglocal",
    7800 "Allow to use local bounds in order to separate coupling inequalities?",
    7801 &conshdlrdata->sepacouplinglocal, TRUE, DEFAULT_SEPACOUPLINGLOCAL, NULL, NULL) );
    7802
    7804 "constraints/indicator/sepacouplingvalue",
    7805 "maximum coefficient for binary variable in separated coupling constraint",
    7806 &conshdlrdata->sepacouplingvalue, TRUE, DEFAULT_SEPACOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
    7807
    7809 "constraints/indicator/sepaperspective",
    7810 "Separate cuts based on perspective formulation?",
    7811 &conshdlrdata->sepaperspective, TRUE, DEFAULT_SEPAPERSPECTIVE, NULL, NULL) );
    7812
    7814 "constraints/indicator/sepapersplocal",
    7815 "Allow to use local bounds in order to separate perspective cuts?",
    7816 &conshdlrdata->sepapersplocal, TRUE, DEFAULT_SEPAPERSPLOCAL, NULL, NULL) );
    7817
    7819 "constraints/indicator/maxsepanonviolated",
    7820 "maximal number of separated non violated IISs, before separation is stopped",
    7821 &conshdlrdata->maxsepanonviolated, FALSE, DEFAULT_MAXSEPANONVIOLATED, 0, INT_MAX, NULL, NULL) );
    7822
    7824 "constraints/indicator/updatebounds",
    7825 "Update bounds of original variables for separation?",
    7826 &conshdlrdata->updatebounds, TRUE, DEFAULT_UPDATEBOUNDS, NULL, NULL) );
    7827
    7829 "constraints/indicator/maxconditionaltlp",
    7830 "maximum estimated condition of the solution basis matrix of the alternative LP to be trustworthy (0.0 to disable check)",
    7831 &conshdlrdata->maxconditionaltlp, TRUE, DEFAULT_MAXCONDITIONALTLP, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    7832
    7834 "constraints/indicator/maxsepacuts",
    7835 "maximal number of cuts separated per separation round",
    7836 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
    7837
    7839 "constraints/indicator/maxsepacutsroot",
    7840 "maximal number of cuts separated per separation round in the root node",
    7841 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
    7842
    7844 "constraints/indicator/removeindicators",
    7845 "Remove indicator constraint if corresponding variable bound constraint has been added?",
    7846 &conshdlrdata->removeindicators, TRUE, DEFAULT_REMOVEINDICATORS, NULL, NULL) );
    7847
    7849 "constraints/indicator/generatebilinear",
    7850 "Do not generate indicator constraint, but a bilinear constraint instead?",
    7851 &conshdlrdata->generatebilinear, TRUE, DEFAULT_GENERATEBILINEAR, NULL, NULL) );
    7852
    7854 "constraints/indicator/scaleslackvar",
    7855 "Scale slack variable coefficient at construction time?",
    7856 &conshdlrdata->scaleslackvar, TRUE, DEFAULT_SCALESLACKVAR, NULL, NULL) );
    7857
    7859 "constraints/indicator/trysolutions",
    7860 "Try to make solutions feasible by setting indicator variables?",
    7861 &conshdlrdata->trysolutions, TRUE, DEFAULT_TRYSOLUTIONS, NULL, NULL) );
    7862
    7864 "constraints/indicator/enforcecuts",
    7865 "In enforcing try to generate cuts (only if sepaalternativelp is true)?",
    7866 &conshdlrdata->enforcecuts, TRUE, DEFAULT_ENFORCECUTS, NULL, NULL) );
    7867
    7869 "constraints/indicator/dualreductions",
    7870 "Should dual reduction steps be performed?",
    7871 &conshdlrdata->dualreductions, TRUE, DEFAULT_DUALREDUCTIONS, NULL, NULL) );
    7872
    7874 "constraints/indicator/addopposite",
    7875 "Add opposite inequality in nodes in which the binary variable has been fixed to 0?",
    7876 &conshdlrdata->addopposite, TRUE, DEFAULT_ADDOPPOSITE, NULL, NULL) );
    7877
    7879 "constraints/indicator/conflictsupgrade",
    7880 "Try to upgrade bounddisjunction conflicts by replacing slack variables?",
    7881 &conshdlrdata->conflictsupgrade, TRUE, DEFAULT_CONFLICTSUPGRADE, NULL, NULL) );
    7882
    7884 "constraints/indicator/restartfrac",
    7885 "fraction of binary variables that need to be fixed before restart occurs (in forcerestart)",
    7886 &conshdlrdata->restartfrac, TRUE, DEFAULT_RESTARTFRAC, 0.0, 1.0, NULL, NULL) );
    7887
    7889 "constraints/indicator/useotherconss",
    7890 "Collect other constraints to alternative LP?",
    7891 &conshdlrdata->useotherconss, TRUE, DEFAULT_USEOTHERCONSS, NULL, NULL) );
    7892
    7894 "constraints/indicator/useobjectivecut",
    7895 "Use objective cut with current best solution to alternative LP?",
    7896 &conshdlrdata->useobjectivecut, TRUE, DEFAULT_USEOBJECTIVECUT, NULL, NULL) );
    7897
    7899 "constraints/indicator/trysolfromcover",
    7900 "Try to construct a feasible solution from a cover?",
    7901 &conshdlrdata->trysolfromcover, TRUE, DEFAULT_TRYSOLFROMCOVER, NULL, NULL) );
    7902
    7904 "constraints/indicator/upgradelinear",
    7905 "Try to upgrade linear constraints to indicator constraints?",
    7906 &conshdlrdata->upgradelinear, TRUE, DEFAULT_UPGRADELINEAR, NULL, NULL) );
    7907
    7909 "constraints/indicator/usesameslackvar",
    7910 "Use same slack variable for indicator constraints with common binary variable?",
    7911 &conshdlrdata->usesameslackvar, TRUE, DEFAULT_USESAMESLACKVAR, NULL, NULL) );
    7912
    7913 /* parameters that should not be changed after problem stage: */
    7915 "constraints/indicator/sepaalternativelp",
    7916 "Separate using the alternative LP?",
    7917 &conshdlrdata->sepaalternativelp_, TRUE, DEFAULT_SEPAALTERNATIVELP, paramChangedIndicator, NULL) );
    7918
    7920 "constraints/indicator/forcerestart",
    7921 "Force restart if absolute gap is 1 or enough binary variables have been fixed?",
    7922 &conshdlrdata->forcerestart_, TRUE, DEFAULT_FORCERESTART, paramChangedIndicator, NULL) );
    7923
    7925 "constraints/indicator/nolinconscont",
    7926 "Decompose problem (do not generate linear constraint if all variables are continuous)?",
    7927 &conshdlrdata->nolinconscont_, TRUE, DEFAULT_NOLINCONSCONT, paramChangedIndicator, NULL) );
    7928
    7929 return SCIP_OKAY;
    7930}
    7931
    7932/** creates and captures an indicator constraint
    7933 *
    7934 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    7935 * procedures reading an instance.
    7936 *
    7937 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    7938 */
    7940 SCIP* scip, /**< SCIP data structure */
    7941 SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
    7942 const char* name, /**< name of constraint */
    7943 SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
    7944 int nvars, /**< number of variables in the inequality */
    7945 SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
    7946 SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
    7947 SCIP_Real rhs, /**< rhs of the inequality */
    7948 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    7949 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    7950 * Usually set to TRUE. */
    7951 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    7952 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    7953 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    7954 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    7955 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    7956 * Usually set to TRUE. */
    7957 SCIP_Bool local, /**< is constraint only valid locally?
    7958 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    7959 SCIP_Bool dynamic, /**< is constraint subject to aging?
    7960 * Usually set to FALSE. Set to TRUE for own cuts which
    7961 * are separated as constraints. */
    7962 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    7963 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    7964 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    7965 * if it may be moved to a more global node?
    7966 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    7967 )
    7968{
    7969 return SCIPcreateConsIndicatorGeneric(scip, cons, name, binvar, nvars, vars, vals, rhs, TRUE, TRUE, initial,
    7970 separate, enforce, check, propagate, local, dynamic, removable, stickingatnode);
    7971}
    7972
    7973/** creates and captures a indicator constraint in a more generic version.
    7974 *
    7975 * The key difference from SCIPcreateConsIndicator() is the activeone and lessthanineq Booleans.
    7976 * If \f$z = o\f$, with \f$o\f$ the activeone flag, then:
    7977 * if lessthanineq then \f$a^T x \leq b\f$ holds, else the passed vectors are assumed to be of the form \f$a^T x \geq b\f$.
    7978 * The underlying linear constraint is always created as a less-than inequality.
    7979 */
    7981 SCIP* scip, /**< SCIP data structure */
    7982 SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
    7983 const char* name, /**< name of constraint */
    7984 SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
    7985 int nvars, /**< number of variables in the inequality */
    7986 SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
    7987 SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
    7988 SCIP_Real rhs, /**< rhs of the inequality */
    7989 SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
    7990 SCIP_Bool lessthanineq, /**< is the linear constraint a less than RHS (TRUE) or greater than RHS (FALSE)? */
    7991 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    7992 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    7993 * Usually set to TRUE. */
    7994 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    7995 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    7996 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    7997 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    7998 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    7999 * Usually set to TRUE. */
    8000 SCIP_Bool local, /**< is constraint only valid locally?
    8001 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    8002 SCIP_Bool dynamic, /**< is constraint subject to aging?
    8003 * Usually set to FALSE. Set to TRUE for own cuts which
    8004 * are separated as constraints. */
    8005 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    8006 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    8007 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    8008 * if it may be moved to a more global node?
    8009 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    8010 )
    8011{
    8012 SCIP_CONSHDLR* conshdlr;
    8013 SCIP_CONSHDLRDATA* conshdlrdata;
    8014 SCIP_CONSDATA* consdata = NULL;
    8015 SCIP_CONS* lincons;
    8016 SCIP_VAR* slackvar = NULL;
    8017 SCIP_VAR* binvarinternal;
    8018 SCIP_Bool modifiable = FALSE;
    8019 SCIP_Bool linconsactive;
    8020 SCIP_Bool integral = TRUE;
    8021 SCIP_Real* valscopy;
    8022 SCIP_Real absvalsum = 0.0;
    8023 char s[SCIP_MAXSTRLEN];
    8024 int v;
    8025
    8026 if ( nvars < 0 )
    8027 {
    8028 SCIPerrorMessage("Indicator constraint <%s> needs nonnegative number of variables in linear constraint.\n", name);
    8029 return SCIP_INVALIDDATA;
    8030 }
    8031
    8032 /* find the indicator constraint handler */
    8033 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    8034 if ( conshdlr == NULL )
    8035 {
    8036 SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
    8037 return SCIP_PLUGINNOTFOUND;
    8038 }
    8039
    8040 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8041 assert( conshdlrdata != NULL );
    8042
    8043 if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
    8044 {
    8045 SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
    8046 return SCIP_INVALIDDATA;
    8047 }
    8048
    8049 if ( conshdlrdata->nolinconscont && conshdlrdata->generatebilinear )
    8050 {
    8051 SCIPerrorMessage("constraint handler <%s>: parameters <nolinconscont> and <generatebilinear> cannot both be true.\n", CONSHDLR_NAME);
    8052 return SCIP_INVALIDDATA;
    8053 }
    8054
    8055 valscopy = NULL;
    8056 if ( lessthanineq )
    8057 valscopy = vals;
    8058 else
    8059 {
    8060 /* flip coefficients and RHS of indicator */
    8061 SCIP_CALL( SCIPallocBufferArray(scip, &valscopy, nvars) );
    8062 for ( v = 0; v < nvars; ++v )
    8063 valscopy[v] = -vals[v];
    8064 rhs = -rhs;
    8065 }
    8066 assert( nvars == 0 || valscopy != NULL );
    8067
    8068 /* determine integrality of slack variable and whether problem is decomposed if no variables are integral */
    8069 linconsactive = !conshdlrdata->nolinconscont;
    8070 for ( v = 0; v < nvars; ++v )
    8071 {
    8072 if ( conshdlrdata->scaleslackvar )
    8073 absvalsum += REALABS(valscopy[v]);
    8074 if ( SCIPvarIsIntegral(vars[v]) )
    8075 {
    8076 linconsactive = TRUE;
    8077 if ( !conshdlrdata->scaleslackvar && !integral )
    8078 break;
    8079 if ( !SCIPisIntegral(scip, valscopy[v]) )
    8080 {
    8081 integral = FALSE;
    8082 if ( !conshdlrdata->scaleslackvar )
    8083 break;
    8084 }
    8085 }
    8086 else
    8087 {
    8088 integral = FALSE;
    8089 if ( !conshdlrdata->scaleslackvar && linconsactive )
    8090 break;
    8091 }
    8092 }
    8093
    8094 /* if active on 0, a provided binary variable is negated */
    8095 if ( activeone || binvar == NULL )
    8096 binvarinternal = binvar;
    8097 else
    8098 {
    8099 assert( SCIPvarIsBinary(binvar) );
    8100 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
    8101 }
    8102
    8103 /* Check whether the same slack variable should be use for constraints with a common binary variable. This can
    8104 * reduce the size of the problem, because only one coupling constraint is needed. However, it is less tight. */
    8105 if ( binvarinternal != NULL )
    8106 {
    8107 /* make sure that the hashmap exists if we want to use the same slack variable */
    8108 if ( conshdlrdata->usesameslackvar && conshdlrdata->binslackvarhash == NULL )
    8109 {
    8110 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binslackvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
    8111 }
    8112
    8113 if ( conshdlrdata->binslackvarhash != NULL && SCIPhashmapExists(conshdlrdata->binslackvarhash, (void*) binvarinternal) )
    8114 {
    8115 slackvar = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->binslackvarhash, (void*) binvarinternal);
    8116
    8117 /* make sure that the type of the slack is as general as necessary */
    8118 if ( !integral && SCIPvarIsIntegral(slackvar) )
    8119 {
    8120 SCIP_Bool infeasible;
    8121
    8122 SCIP_CALL( SCIPchgVarType(scip, slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
    8123 assert( !infeasible );
    8124 SCIP_CALL( SCIPchgVarImplType(scip, slackvar, SCIP_IMPLINTTYPE_NONE, &infeasible) );
    8125 assert( !infeasible );
    8126 }
    8127
    8128 SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
    8129 }
    8130 else
    8131 {
    8132 /* create slack variable */
    8133 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
    8134 SCIP_CALL( SCIPcreateVarImpl(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0,
    8136 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    8137
    8138 SCIP_CALL( SCIPaddVar(scip, slackvar) );
    8139
    8140 /* mark slack variable not to be multi-aggregated */
    8142
    8143 if ( conshdlrdata->binslackvarhash != NULL )
    8144 {
    8145 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binslackvarhash, (void*) binvarinternal, (void*) slackvar) );
    8146 }
    8147 }
    8148 }
    8149 else
    8150 {
    8151 /* create slack variable */
    8152 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
    8153 SCIP_CALL( SCIPcreateVarImpl(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0,
    8155 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    8156
    8157 SCIP_CALL( SCIPaddVar(scip, slackvar) );
    8158
    8159 /* mark slack variable not to be multi-aggregated */
    8161 }
    8162 assert( slackvar != NULL );
    8163
    8164 /* create linear constraint */
    8165 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indlin_%s", name);
    8166
    8167 /* if the linear constraint should be activated (lincons is captured) */
    8168 if ( linconsactive )
    8169 {
    8170 /* the constraint is initial if initial is true, enforced, separated, and checked */
    8171 SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, s, nvars, vars, valscopy, -SCIPinfinity(scip), rhs,
    8172 initial, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
    8173 }
    8174 else
    8175 {
    8176 /* create non-active linear constraint, which is neither initial, nor enforced, nor separated, nor checked */
    8177 SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, s, nvars, vars, valscopy, -SCIPinfinity(scip), rhs,
    8179 }
    8180
    8181 if ( ! lessthanineq )
    8182 SCIPfreeBufferArray(scip, &valscopy);
    8183
    8184 /* mark linear constraint not to be upgraded - otherwise we loose control over it */
    8185 SCIPconsAddUpgradeLocks(lincons, 1);
    8186 assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
    8187
    8188 /* add slack variable */
    8189 if ( conshdlrdata->scaleslackvar && nvars > 0 )
    8190 {
    8191 absvalsum = absvalsum/((SCIP_Real) nvars);
    8192 if ( integral )
    8193 absvalsum = SCIPceil(scip, absvalsum);
    8194 if ( SCIPisZero(scip, absvalsum) )
    8195 absvalsum = 1.0;
    8196 SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, -absvalsum) );
    8197 }
    8198 else
    8199 {
    8200 SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, -1.0) );
    8201 }
    8202 SCIP_CALL( SCIPaddCons(scip, lincons) );
    8203
    8204 /* check whether we should generate a bilinear constraint instead of an indicator constraint */
    8205 if ( conshdlrdata->generatebilinear )
    8206 {
    8207 assert( linconsactive );
    8208
    8209 SCIP_Real val = 1.0;
    8210
    8211 /* create a quadratic constraint with a single bilinear term - note that cons is used */
    8212 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
    8214 }
    8215 else
    8216 {
    8217 /* create constraint data */
    8218 SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrrestart,
    8219 binvar, activeone, lessthanineq, slackvar, lincons, linconsactive) );
    8220 assert( consdata != NULL );
    8221
    8222 /* do not need to capture slack variable and linear constraint here */
    8223 if( consdata->binvar != NULL )
    8224 {
    8225 SCIP_CALL( SCIPcaptureVar(scip, consdata->binvar) );
    8226 }
    8227
    8228 /* create constraint */
    8229 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    8230 local, modifiable, dynamic, removable, stickingatnode) );
    8231
    8232 if ( SCIPisTransformed(scip) )
    8233 {
    8234 /* catch local bound change events on binary variable */
    8235 if ( linconsactive )
    8236 {
    8237 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8238 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8239 }
    8240
    8241 /* make sure that binary variable hash exists */
    8242 if ( conshdlrdata->sepaalternativelp )
    8243 {
    8244 if ( conshdlrdata->binvarhash == NULL )
    8245 {
    8246 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
    8247 }
    8248
    8249 /* check whether binary variable is present: note that a binary variable might appear several times, but this seldomly happens. */
    8250 assert( conshdlrdata->binvarhash != NULL );
    8251 if ( ! SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarinternal) )
    8252 {
    8253 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binvarhash, (void*) binvarinternal, (void*) (*cons)) );
    8254 }
    8255 }
    8256 }
    8257 }
    8258
    8259 return SCIP_OKAY;
    8260}
    8261
    8262/** creates and captures an indicator constraint in its most basic version, i. e., all constraint flags are set to their
    8263 * basic value as explained for the method SCIPcreateConsIndicator(); all flags can be set via
    8264 * SCIPsetConsFLAGNAME-methods in scip.h
    8265 *
    8266 * @see SCIPcreateConsIndicator() for information about the basic constraint flag configuration
    8267 *
    8268 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8269 */
    8271 SCIP* scip, /**< SCIP data structure */
    8272 SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
    8273 const char* name, /**< name of constraint */
    8274 SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
    8275 int nvars, /**< number of variables in the inequality */
    8276 SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
    8277 SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
    8278 SCIP_Real rhs /**< rhs of the inequality */
    8279 )
    8280{
    8281 assert( scip != NULL );
    8282
    8283 SCIP_CALL( SCIPcreateConsIndicator(scip, cons, name, binvar, nvars, vars, vals, rhs,
    8285
    8286 return SCIP_OKAY;
    8287}
    8288
    8289/** creates and captures an indicator constraint with given linear constraint and slack variable
    8290 * in a generic version, i.e., with a flag activeone indicating whether the constraint is active on
    8291 * value 1 or 0 of the binary variable.
    8292
    8293 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    8294 * procedures reading an instance.
    8295 *
    8296 * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
    8297 * the role of a slack variable!
    8298 *
    8299 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8300 *
    8301 * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
    8302 */
    8304 SCIP* scip, /**< SCIP data structure */
    8305 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    8306 const char* name, /**< name of constraint */
    8307 SCIP_VAR* binvar, /**< binary indicator variable */
    8308 SCIP_CONS* lincons, /**< linear constraint */
    8309 SCIP_VAR* slackvar, /**< slack variable */
    8310 SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
    8311 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    8312 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    8313 * Usually set to TRUE. */
    8314 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    8315 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8316 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    8317 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8318 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    8319 * Usually set to TRUE. */
    8320 SCIP_Bool local, /**< is constraint only valid locally?
    8321 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    8322 SCIP_Bool dynamic, /**< is constraint subject to aging?
    8323 * Usually set to FALSE. Set to TRUE for own cuts which
    8324 * are separated as constraints. */
    8325 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    8326 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    8327 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    8328 * if it may be moved to a more global node?
    8329 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    8330 )
    8331{
    8332 SCIP_CONSHDLR* conshdlr;
    8333 SCIP_CONSHDLRDATA* conshdlrdata;
    8334 SCIP_CONSDATA* consdata = NULL;
    8335 SCIP_VAR** vars;
    8336 SCIP_Bool modifiable = FALSE;
    8337 SCIP_Bool linconsactive;
    8338 int nvars;
    8339 int v;
    8340
    8341 assert( scip != NULL );
    8342 assert( lincons != NULL );
    8343 assert( binvar != NULL );
    8344 assert( slackvar != NULL );
    8345
    8346 /* check whether lincons is really a linear constraint */
    8347 conshdlr = SCIPconsGetHdlr(lincons);
    8348
    8349 SCIP_STRINGEQ( SCIPconshdlrGetName(conshdlr), "linear", SCIP_INVALIDDATA );
    8350
    8351 /* find the indicator constraint handler */
    8352 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    8353 if ( conshdlr == NULL )
    8354 {
    8355 SCIPerrorMessage("<%s> constraint handler not found.\n", CONSHDLR_NAME);
    8356 return SCIP_PLUGINNOTFOUND;
    8357 }
    8358
    8359 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8360 assert( conshdlrdata != NULL );
    8361
    8362 if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
    8363 {
    8364 SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
    8365 return SCIP_INVALIDDATA;
    8366 }
    8367
    8368 /* determine whether the linear constraint needs to be active */
    8369 nvars = SCIPgetNVarsLinear(scip, lincons);
    8370 vars = SCIPgetVarsLinear(scip, lincons);
    8371 linconsactive = ! conshdlrdata->nolinconscont;
    8372 for ( v = 0; v < nvars && ! linconsactive; ++v )
    8373 {
    8374 if ( vars[v] == slackvar )
    8375 continue;
    8376
    8377 if ( SCIPvarIsIntegral(vars[v]) )
    8378 linconsactive = TRUE;
    8379 }
    8380
    8381 /* Note that we do not change the type of the slackvariable here, because it might appear in other constraints and
    8382 * the locks are note yet set up if we are copying. */
    8383
    8384 /* mark slack variable not to be multi-aggregated */
    8386
    8387 /* mark linear constraint not to be upgraded - otherwise we loose control over it */
    8388 SCIPconsAddUpgradeLocks(lincons, 1);
    8389 assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
    8390
    8391 /* check whether we should generate a bilinear constraint instead of an indicator constraint */
    8392 if ( conshdlrdata->generatebilinear )
    8393 {
    8394 assert( linconsactive );
    8395
    8396 SCIP_Real val = 1.0;
    8397
    8398 /* if active on 0, the binary variable is negated */
    8399 SCIP_VAR* binvarinternal;
    8400 if ( activeone )
    8401 binvarinternal = binvar;
    8402 else
    8403 {
    8404 assert( SCIPvarIsBinary(binvar) );
    8405 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
    8406 }
    8407
    8408 /* create a quadratic constraint with a single bilinear term - note that cons is used */
    8409 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
    8411 }
    8412 else
    8413 {
    8414 /* create constraint data */
    8415 SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrrestart,
    8416 binvar, activeone, TRUE, slackvar, lincons, linconsactive) );
    8417 assert( consdata != NULL );
    8418
    8419 /* create constraint */
    8420 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    8421 local, modifiable, dynamic, removable, stickingatnode) );
    8422
    8423 /* catch local bound change events on binary variable */
    8424 if ( consdata->linconsactive && SCIPisTransformed(scip) )
    8425 {
    8426 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8427 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8428 }
    8429 }
    8430
    8431 /* capture binary variable, slack variable, and linear constraint */
    8432 if( consdata != NULL )
    8433 {
    8434 SCIP_CALL( SCIPcaptureVar(scip, consdata->binvar) );
    8435 }
    8436 SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
    8437 SCIP_CALL( SCIPcaptureCons(scip, lincons) );
    8438
    8439 return SCIP_OKAY;
    8440}
    8441
    8442/** creates and captures an indicator constraint with given linear constraint and slack variable
    8443 *
    8444 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    8445 * procedures reading an instance.
    8446 *
    8447 * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
    8448 * the role of a slack variable!
    8449 *
    8450 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8451 */
    8453 SCIP* scip, /**< SCIP data structure */
    8454 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    8455 const char* name, /**< name of constraint */
    8456 SCIP_VAR* binvar, /**< binary indicator variable */
    8457 SCIP_CONS* lincons, /**< linear constraint */
    8458 SCIP_VAR* slackvar, /**< slack variable */
    8459 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    8460 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    8461 * Usually set to TRUE. */
    8462 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    8463 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8464 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    8465 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8466 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    8467 * Usually set to TRUE. */
    8468 SCIP_Bool local, /**< is constraint only valid locally?
    8469 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    8470 SCIP_Bool dynamic, /**< is constraint subject to aging?
    8471 * Usually set to FALSE. Set to TRUE for own cuts which
    8472 * are separated as constraints. */
    8473 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    8474 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    8475 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    8476 * if it may be moved to a more global node?
    8477 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    8478 )
    8479{
    8480 return SCIPcreateConsIndicatorGenericLinCons(scip, cons, name, binvar, lincons, slackvar, TRUE, initial, separate,
    8481 enforce, check, propagate, local, dynamic, removable, stickingatnode);
    8482}
    8483
    8484
    8485/** creates and captures an indicator constraint with given linear constraint and slack variable
    8486 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
    8487 * method SCIPcreateConsIndicator(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
    8488 *
    8489 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    8490 * procedures reading an instance.
    8491 *
    8492 * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
    8493 * the role of a slack variable!
    8494 *
    8495 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8496 *
    8497 * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
    8498 *
    8499 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8500 */
    8502 SCIP* scip, /**< SCIP data structure */
    8503 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    8504 const char* name, /**< name of constraint */
    8505 SCIP_VAR* binvar, /**< binary indicator variable */
    8506 SCIP_CONS* lincons, /**< linear constraint */
    8507 SCIP_VAR* slackvar /**< slack variable */
    8508 )
    8509{
    8510 assert( scip != NULL );
    8511
    8512 SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
    8514
    8515 return SCIP_OKAY;
    8516}
    8517
    8518
    8519/** creates and captures an indicator constraint with given linear constraint in a generic version, i. e., with a flag
    8520 * activeone indicating whether the constraint is active on value 1 or 0 of the binary variable; no slack variable is
    8521 * given
    8522
    8523 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    8524 * procedures reading an instance.
    8525 *
    8526 * @note The linear constraint must be single-sided, i.e., either rhs or lhs have to be infinite.
    8527 *
    8528 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8529 *
    8530 * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
    8531 */
    8533 SCIP* scip, /**< SCIP data structure */
    8534 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    8535 const char* name, /**< name of constraint */
    8536 SCIP_VAR* binvar, /**< binary indicator variable */
    8537 SCIP_CONS* lincons, /**< linear constraint */
    8538 SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
    8539 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    8540 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    8541 * Usually set to TRUE. */
    8542 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    8543 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8544 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    8545 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8546 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    8547 * Usually set to TRUE. */
    8548 SCIP_Bool local, /**< is constraint only valid locally?
    8549 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    8550 SCIP_Bool dynamic, /**< is constraint subject to aging?
    8551 * Usually set to FALSE. Set to TRUE for own cuts which
    8552 * are separated as constraints. */
    8553 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    8554 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    8555 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    8556 * if it may be moved to a more global node?
    8557 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    8558 )
    8559{
    8560 char s[SCIP_MAXSTRLEN];
    8561 SCIP_CONSHDLR* conshdlr;
    8562 SCIP_CONSHDLRDATA* conshdlrdata;
    8563 SCIP_CONSDATA* consdata = NULL;
    8564 SCIP_VAR** vars;
    8565 SCIP_VAR* binvarinternal;
    8566 SCIP_VAR* slackvar = NULL;
    8567 SCIP_Bool modifiable = FALSE;
    8568 SCIP_Bool linconsactive;
    8569 SCIP_Bool integral = TRUE;
    8570 SCIP_Real* vals;
    8571 SCIP_Real sign;
    8572 SCIP_Real lhs;
    8573 SCIP_Real rhs;
    8574 int nvars;
    8575 int v;
    8576
    8577 assert( scip != NULL );
    8578 assert( lincons != NULL );
    8579 assert( binvar != NULL );
    8580
    8581 /* check whether lincons is really a linear constraint */
    8582 conshdlr = SCIPconsGetHdlr(lincons);
    8583
    8584 SCIP_STRINGEQ( SCIPconshdlrGetName(conshdlr), "linear", SCIP_INVALIDDATA );
    8585
    8586 /* find the indicator constraint handler */
    8587 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    8588 if ( conshdlr == NULL )
    8589 {
    8590 SCIPerrorMessage("<%s> constraint handler not found.\n", CONSHDLR_NAME);
    8591 return SCIP_PLUGINNOTFOUND;
    8592 }
    8593
    8594 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8595 assert( conshdlrdata != NULL );
    8596
    8597 if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
    8598 {
    8599 SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
    8600 return SCIP_INVALIDDATA;
    8601 }
    8602
    8603 lhs = SCIPgetLhsLinear(scip, lincons);
    8604 rhs = SCIPgetRhsLinear(scip, lincons);
    8605 if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
    8606 {
    8607 SCIPerrorMessage("Lincons constraint has finite lhs and rhs.\n");
    8608 return SCIP_INVALIDDATA;
    8609 }
    8610
    8611 /* determine integrality of slack variable and whether problem is decomposed if no variables are integral */
    8612 nvars = SCIPgetNVarsLinear(scip, lincons);
    8613 vars = SCIPgetVarsLinear(scip, lincons);
    8614 vals = SCIPgetValsLinear(scip, lincons);
    8615 linconsactive = !conshdlrdata->nolinconscont;
    8616 for ( v = 0; v < nvars; ++v )
    8617 {
    8618 if ( SCIPvarIsIntegral(vars[v]) )
    8619 {
    8620 linconsactive = TRUE;
    8621 if ( !SCIPisIntegral(scip, vals[v]) )
    8622 integral = FALSE;
    8623 }
    8624 else
    8625 integral = FALSE;
    8626
    8627 /* check whether variable is marked to not be multi-aggregated: this should only be the case for slack variables
    8628 * added by the indicator constraint handler */
    8629 if ( SCIPdoNotMultaggrVar(scip, vars[v]) )
    8630 {
    8631 /* double check name */
    8632 if ( strncmp(SCIPvarGetName(vars[v]), "indslack", 8) == 0 )
    8633 {
    8634 SCIPerrorMessage("Linear constraint <%s> already used in an indicator constraint.\n", SCIPconsGetName(lincons));
    8635 return SCIP_INVALIDDATA;
    8636 }
    8637 }
    8638 }
    8639
    8640 /* if active on 0, the binary variable is negated */
    8641 if ( activeone )
    8642 binvarinternal = binvar;
    8643 else
    8644 {
    8645 assert( SCIPvarIsBinary(binvar) );
    8646 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
    8647 }
    8648
    8649 /* Check whether the same slack variable should be use for constraints with a common binary variable. This can
    8650 * reduce the size of the problem, because only one coupling constraint is needed. However, it is less tight. */
    8651 if ( conshdlrdata->usesameslackvar && conshdlrdata->binslackvarhash == NULL )
    8652 {
    8653 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binslackvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
    8654 }
    8655
    8656 if ( conshdlrdata->binslackvarhash != NULL && SCIPhashmapExists(conshdlrdata->binslackvarhash, (void*) binvarinternal) )
    8657 {
    8658 /* determine slack variable */
    8659 slackvar = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->binslackvarhash, (void*) binvarinternal);
    8660
    8661 /* make sure that the type of the slack is as general as necessary */
    8662 if ( !integral && SCIPvarIsIntegral(slackvar) )
    8663 {
    8664 SCIP_Bool infeasible;
    8665
    8666 SCIP_CALL( SCIPchgVarType(scip, slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
    8667 assert( !infeasible );
    8668 SCIP_CALL( SCIPchgVarImplType(scip, slackvar, SCIP_IMPLINTTYPE_NONE, &infeasible) );
    8669 assert( !infeasible );
    8670 }
    8671
    8672 SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
    8673 }
    8674 else
    8675 {
    8676 /* create slack variable */
    8677 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
    8678 SCIP_CALL( SCIPcreateVarImpl(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0,
    8680 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    8681
    8682 SCIP_CALL( SCIPaddVar(scip, slackvar) );
    8683
    8684 /* mark slack variable not to be multi-aggregated */
    8686
    8687 if ( conshdlrdata->binslackvarhash != NULL )
    8688 {
    8689 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binslackvarhash, (void*) binvarinternal, (void*) slackvar) );
    8690 }
    8691 }
    8692 assert( slackvar != NULL );
    8693
    8694 /* determine sign of slack variable */
    8695 sign = -1.0;
    8696 if ( SCIPisInfinity(scip, rhs) )
    8697 sign = 1.0;
    8698
    8699 /* add slack variable */
    8700 SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, sign) );
    8701
    8702 /* mark linear constraint not to be upgraded - otherwise we loose control over it */
    8703 SCIPconsAddUpgradeLocks(lincons, 1);
    8704 assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
    8705
    8706 /* check whether we should generate a bilinear constraint instead of an indicator constraint */
    8707 if ( conshdlrdata->generatebilinear )
    8708 {
    8709 assert( linconsactive );
    8710
    8711 SCIP_Real val = 1.0;
    8712
    8713 /* create a quadratic constraint with a single bilinear term - note that cons is used */
    8714 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
    8716 }
    8717 else
    8718 {
    8719 /* create constraint data */
    8720 SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrrestart,
    8721 binvar, activeone, TRUE, slackvar, lincons, linconsactive) );
    8722 assert( consdata != NULL );
    8723
    8724 /* create constraint */
    8725 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    8726 local, modifiable, dynamic, removable, stickingatnode) );
    8727
    8728 /* catch local bound change events on binary variable */
    8729 if ( consdata->linconsactive && SCIPisTransformed(scip) )
    8730 {
    8731 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8732 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8733 }
    8734 }
    8735
    8736 /* capture binary variable and linear constraint */
    8737 if( consdata != NULL )
    8738 {
    8739 SCIP_CALL( SCIPcaptureVar(scip, consdata->binvar) );
    8740 }
    8741 SCIP_CALL( SCIPcaptureCons(scip, lincons) );
    8742
    8743 return SCIP_OKAY;
    8744}
    8745
    8746
    8747/** creates and captures an indicator constraint with given linear constraint; no slack variable is specified
    8748 *
    8749 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    8750 * procedures reading an instance.
    8751 *
    8752 * @note The linear constraint has to be single sided only, i.e., either rhs or lhs have to be infinite.
    8753 *
    8754 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8755 */
    8757 SCIP* scip, /**< SCIP data structure */
    8758 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    8759 const char* name, /**< name of constraint */
    8760 SCIP_VAR* binvar, /**< binary indicator variable */
    8761 SCIP_CONS* lincons, /**< linear constraint */
    8762 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    8763 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    8764 * Usually set to TRUE. */
    8765 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    8766 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8767 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    8768 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8769 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    8770 * Usually set to TRUE. */
    8771 SCIP_Bool local, /**< is constraint only valid locally?
    8772 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    8773 SCIP_Bool dynamic, /**< is constraint subject to aging?
    8774 * Usually set to FALSE. Set to TRUE for own cuts which
    8775 * are separated as constraints. */
    8776 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    8777 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    8778 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    8779 * if it may be moved to a more global node?
    8780 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    8781 )
    8782{
    8783 return SCIPcreateConsIndicatorGenericLinConsPure(scip, cons, name, binvar, lincons, TRUE, initial, separate,
    8784 enforce, check, propagate, local, dynamic, removable, stickingatnode);
    8785}
    8786
    8787
    8788/** adds variable to the inequality of the indicator constraint */
    8790 SCIP* scip, /**< SCIP data structure */
    8791 SCIP_CONS* cons, /**< indicator constraint */
    8792 SCIP_VAR* var, /**< variable to add to the inequality */
    8793 SCIP_Real val /**< value of variable */
    8794 )
    8795{
    8796 SCIP_CONSDATA* consdata;
    8797
    8798 assert( cons != NULL );
    8799
    8801
    8802 consdata = SCIPconsGetData(cons);
    8803 assert( consdata != NULL );
    8804
    8805 /* if linear inequality is flipped, variable is added with negative coefficient */
    8806 if ( !consdata->lessthanineq )
    8807 val = -val;
    8808
    8809 SCIP_CALL( SCIPaddCoefLinear(scip, consdata->lincons, var, val) );
    8810
    8811 /* make sure that the type of the slack is as general as necessary */
    8812 if ( ( !SCIPvarIsIntegral(var) || !SCIPisIntegral(scip, val) ) && SCIPvarIsIntegral(consdata->slackvar) )
    8813 {
    8814 SCIP_Bool infeasible;
    8815
    8816 SCIP_CALL( SCIPchgVarType(scip, consdata->slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
    8817 assert( !infeasible );
    8818 SCIP_CALL( SCIPchgVarImplType(scip, consdata->slackvar, SCIP_IMPLINTTYPE_NONE, &infeasible) );
    8819 assert( !infeasible );
    8820 }
    8821
    8822 return SCIP_OKAY;
    8823}
    8824
    8825
    8826/** gets the linear constraint corresponding to the indicator constraint (may be NULL) */
    8828 SCIP_CONS* cons /**< indicator constraint */
    8829 )
    8830{
    8831 SCIP_CONSDATA* consdata;
    8832
    8833 assert( cons != NULL );
    8834
    8836
    8837 consdata = SCIPconsGetData(cons);
    8838 assert( consdata != NULL );
    8839
    8840 return consdata->lincons;
    8841}
    8842
    8843
    8844/** sets the linear constraint corresponding to the indicator constraint (may be NULL) */
    8846 SCIP* scip, /**< SCIP data structure */
    8847 SCIP_CONS* cons, /**< indicator constraint */
    8848 SCIP_CONS* lincons /**< linear constraint */
    8849 )
    8850{
    8851 SCIP_CONSHDLR* conshdlr;
    8852 SCIP_CONSHDLRDATA* conshdlrdata;
    8853 SCIP_CONSDATA* consdata;
    8854
    8856 {
    8857 SCIPerrorMessage("Cannot set linear constraint in SCIP stage <%d>\n", SCIPgetStage(scip) );
    8858 return SCIP_INVALIDCALL;
    8859 }
    8860
    8861 assert( cons != NULL );
    8862 conshdlr = SCIPconsGetHdlr(cons);
    8863
    8865
    8866 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8867 assert( conshdlrdata != NULL );
    8868
    8869 consdata = SCIPconsGetData(cons);
    8870 assert( consdata != NULL );
    8871
    8872 /* free old linear constraint */
    8873 assert( consdata->lincons != NULL );
    8874 SCIP_CALL( SCIPdelCons(scip, consdata->lincons) );
    8875 SCIP_CALL( SCIPreleaseCons(scip, &(consdata->lincons) ) );
    8876
    8877 assert( lincons != NULL );
    8878 consdata->lincons = lincons;
    8879 consdata->linconsactive = !conshdlrdata->nolinconscont;
    8880 SCIP_CALL( SCIPcaptureCons(scip, lincons) );
    8881
    8882 /* determine whether problem is decomposed if no variables are integral */
    8883 if ( !consdata->linconsactive )
    8884 {
    8885 SCIP_VAR** vars = SCIPgetVarsLinear(scip, lincons);
    8886 int nvars = SCIPgetNVarsLinear(scip, lincons);
    8887 int v;
    8888
    8889 for ( v = 0; v < nvars; ++v )
    8890 {
    8891 if ( SCIPvarIsIntegral(vars[v]) )
    8892 {
    8893 consdata->linconsactive = TRUE;
    8894 break;
    8895 }
    8896 }
    8897 }
    8898
    8899 return SCIP_OKAY;
    8900}
    8901
    8902/** gets activation value of an indicator constraint, TRUE for active on 1, FALSE for active on 0 */
    8904 SCIP_CONS* cons /**< indicator constraint */
    8905 )
    8906{
    8907 SCIP_CONSDATA* consdata;
    8908
    8909 assert( cons != NULL );
    8910
    8912
    8913 consdata = SCIPconsGetData(cons);
    8914 assert( consdata != NULL );
    8915
    8916 return consdata->activeone;
    8917}
    8918
    8919
    8920/** gets binary variable corresponding to indicator constraint */
    8922 SCIP_CONS* cons /**< indicator constraint */
    8923 )
    8924{
    8925 SCIP_CONSDATA* consdata;
    8926
    8927 assert( cons != NULL );
    8928
    8930
    8931 consdata = SCIPconsGetData(cons);
    8932 assert( consdata != NULL );
    8933
    8934 return consdata->binvar;
    8935}
    8936
    8937/** similar to SCIPgetBinaryVarIndicator but returns the original binary variable passed by the user. */
    8939 SCIP_CONS* cons /**< indicator constraint */
    8940 )
    8941{
    8942 SCIP_CONSDATA* consdata;
    8943 SCIP_VAR* binvar;
    8944
    8945 assert(cons != NULL);
    8946
    8948
    8949 consdata = SCIPconsGetData(cons);
    8950 assert(consdata != NULL);
    8951 binvar = consdata->binvar;
    8952
    8953 if ( ! consdata->activeone )
    8954 binvar = SCIPvarGetNegationVar(binvar);
    8955 assert(binvar != NULL);
    8956
    8957 return binvar;
    8958}
    8959
    8960/** sets binary indicator variable for indicator constraint */
    8962 SCIP* scip, /**< SCIP data structure */
    8963 SCIP_CONS* cons, /**< indicator constraint */
    8964 SCIP_VAR* binvar /**< binary variable to add to the inequality */
    8965 )
    8966{
    8967 SCIP_CONSDATA* consdata;
    8968
    8969 assert( cons != NULL );
    8970 assert( binvar != NULL );
    8971
    8973
    8974 consdata = SCIPconsGetData(cons);
    8975 assert( consdata != NULL );
    8976
    8977 /* check type */
    8978 if ( !SCIPvarIsBinary(binvar) || SCIPvarIsImpliedIntegral(binvar) )
    8979 {
    8980 SCIPerrorMessage("Indicator variable <%s> is not binary %d.\n", SCIPvarGetName(binvar), SCIPvarGetType(binvar));
    8981 return SCIP_ERROR;
    8982 }
    8983
    8984 /* check previous binary variable */
    8985 if ( consdata->binvar != NULL )
    8986 {
    8987 /* to allow replacement of binary variables, we would need to drop events etc. */
    8988 SCIPerrorMessage("Cannot replace binary variable <%s> for indicator constraint <%s>.\n", SCIPvarGetName(binvar), SCIPconsGetName(cons));
    8989 return SCIP_INVALIDCALL;
    8990 }
    8991
    8992 /* if we are transformed, obtain transformed variables and catch events */
    8993 if ( SCIPconsIsTransformed(cons) )
    8994 {
    8995 SCIP_VAR* var;
    8996 SCIP_CONSHDLR* conshdlr;
    8997 SCIP_CONSHDLRDATA* conshdlrdata;
    8998
    8999 /* make sure we have a transformed binary variable */
    9000 /* coverity[copy_paste_error] */
    9001 SCIP_CALL( SCIPgetTransformedVar(scip, binvar, &var) );
    9002 assert( var != NULL );
    9003 if ( ! consdata->activeone )
    9004 SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
    9005
    9006 SCIP_CALL( SCIPcaptureVar(scip, var) );
    9007 consdata->binvar = var;
    9008
    9009 conshdlr = SCIPconsGetHdlr(cons);
    9010 assert( conshdlr != NULL );
    9011
    9013
    9014 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9015 assert( conshdlrdata != NULL );
    9016 assert( conshdlrdata->eventhdlrbound != NULL );
    9017 assert( conshdlrdata->eventhdlrrestart != NULL );
    9018
    9019 /* catch local bound change events on binary variable */
    9020 if ( consdata->linconsactive )
    9021 {
    9022 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, NULL) );
    9023 }
    9024
    9025 /* catch global bound change events on binary variable */
    9026 if ( conshdlrdata->forcerestart )
    9027 {
    9028 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
    9029 }
    9030
    9031 /* if binary variable is fixed to be nonzero */
    9032 if ( SCIPvarGetLbLocal(var) > 0.5 )
    9033 ++(consdata->nfixednonzero);
    9034 }
    9035 else
    9036 {
    9037 if ( ! consdata->activeone )
    9038 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
    9039
    9040 SCIP_CALL( SCIPcaptureVar(scip, binvar) );
    9041 consdata->binvar = binvar;
    9042 }
    9043
    9044 return SCIP_OKAY;
    9045}
    9046
    9047/** gets slack variable corresponding to indicator constraint */
    9049 SCIP_CONS* cons /**< indicator constraint */
    9050 )
    9051{
    9052 SCIP_CONSDATA* consdata;
    9053
    9054 assert( cons != NULL );
    9055
    9057
    9058 consdata = SCIPconsGetData(cons);
    9059 assert( consdata != NULL );
    9060
    9061 return consdata->slackvar;
    9062}
    9063
    9064
    9065/** sets upper bound for slack variable corresponding to indicator constraint
    9066 *
    9067 * Use with care if you know that the maximal violation of the corresponding constraint is at most @p ub. This bound
    9068 * might be improved automatically during the solution process.
    9069 *
    9070 * @pre This method should only be called if SCIP is in one of the following stages:
    9071 * - \ref SCIP_STAGE_INIT
    9072 * - \ref SCIP_STAGE_PROBLEM
    9073 */
    9075 SCIP* scip, /**< SCIP data structure */
    9076 SCIP_CONS* cons, /**< indicator constraint */
    9077 SCIP_Real ub /**< upper bound for slack variable */
    9078 )
    9079{
    9080 SCIP_CONSDATA* consdata;
    9081
    9082 assert( scip != NULL );
    9083 assert( cons != NULL );
    9084
    9086
    9087 consdata = SCIPconsGetData(cons);
    9088 assert( consdata != NULL );
    9089
    9091 return SCIP_OKAY;
    9092
    9093 assert( consdata->slackvar != NULL );
    9094 SCIP_CALL( SCIPchgVarUb(scip, consdata->slackvar, ub) );
    9095
    9096 return SCIP_OKAY;
    9097}
    9098
    9099
    9100/** checks whether indicator constraint is violated w.r.t. sol */
    9102 SCIP* scip, /**< SCIP data structure */
    9103 SCIP_CONS* cons, /**< indicator constraint */
    9104 SCIP_SOL* sol /**< solution, or NULL to use current node's solution */
    9105 )
    9106{
    9107 SCIP_CONSDATA* consdata;
    9108
    9109 assert( cons != NULL );
    9110
    9111 /* deleted constraints should always be satisfied */
    9112 if ( SCIPconsIsDeleted(cons) )
    9113 return FALSE;
    9114
    9115 consdata = SCIPconsGetData(cons);
    9116 assert( consdata != NULL );
    9117
    9118 if ( consdata->linconsactive )
    9119 {
    9120 assert( consdata->slackvar != NULL );
    9121 assert( consdata->binvar != NULL );
    9122 return(
    9123 SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) &&
    9124 SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
    9125 }
    9126
    9127 /* @todo: check how this can be decided for linconsactive == FALSE */
    9128 return TRUE;
    9129}
    9130
    9131
    9132/** based on values of other variables, computes slack and binary variable to turn constraint feasible
    9133 *
    9134 * It will also clean up the solution, i.e., shift slack variable, as follows:
    9135 *
    9136 * If the inequality is \f$a^T x + \gamma\, s \leq \beta\f$, the value of the slack variable
    9137 * \f$s\f$ to achieve equality is
    9138 * \f[
    9139 * s^* = \frac{\beta - a^T x^*}{\gamma},
    9140 * \f]
    9141 * where \f$x^*\f$ is the given solution. In case of \f$a^T x + \gamma\, s \geq \alpha\f$, we
    9142 * arrive at
    9143 * \f[
    9144 * s^* = \frac{\alpha - a^T x^*}{\gamma}.
    9145 * \f]
    9146 * The typical values of \f$\gamma\f$ in the first case is -1 and +1 in the second case.
    9147 *
    9148 * Now, let \f$\sigma\f$ be the sign of \f$\gamma\f$ in the first case and \f$-\gamma\f$ in the
    9149 * second case. Thus, if \f$\sigma > 0\f$ and \f$s^* < 0\f$, the inequality cannot be satisfied by
    9150 * a nonnegative value for the slack variable; in this case, we have to leave the values as they
    9151 * are. If \f$\sigma < 0\f$ and \f$s^* > 0\f$, the solution violates the indicator constraint (we
    9152 * can set the slack variable to value \f$s^*\f$). If \f$\sigma < 0\f$ and \f$s^* \leq 0\f$ or
    9153 * \f$\sigma > 0\f$ and \f$s^* \geq 0\f$, the constraint is satisfied, and we can set the slack
    9154 * variable to 0.
    9155 */
    9157 SCIP* scip, /**< SCIP data structure */
    9158 SCIP_CONS* cons, /**< indicator constraint */
    9159 SCIP_SOL* sol, /**< solution */
    9160 SCIP_Bool* changed /**< pointer to store whether the solution has been changed */
    9161 )
    9162{
    9163 SCIP_CONSDATA* consdata;
    9164 SCIP_CONS* lincons;
    9165 SCIP_VAR** linvars;
    9166 SCIP_Real* linvals;
    9167 SCIP_VAR* slackvar;
    9168 SCIP_VAR* binvar;
    9169 SCIP_Real slackcoef;
    9170 SCIP_Real sum;
    9171 SCIP_Real val;
    9172 int nlinvars;
    9173 int sigma;
    9174 int v;
    9175
    9176 assert( cons != NULL );
    9177 assert( sol != NULL );
    9178 assert( changed != NULL );
    9179
    9181
    9182 *changed = FALSE;
    9183
    9184 /* avoid deleted indicator constraints, e.g., due to preprocessing */
    9186 return SCIP_OKAY;
    9187
    9188 assert( cons != NULL );
    9189 consdata = SCIPconsGetData(cons);
    9190 assert( consdata != NULL );
    9191
    9192 /* if the linear constraint is not present, we cannot do anything */
    9193 if ( ! consdata->linconsactive )
    9194 return SCIP_OKAY;
    9195
    9196 lincons = consdata->lincons;
    9197 assert( lincons != NULL );
    9198
    9199 /* avoid non-active linear constraints, e.g., due to preprocessing */
    9201 {
    9202 slackvar = consdata->slackvar;
    9203 binvar = consdata->binvar;
    9204 assert( slackvar != NULL );
    9205 assert( binvar != NULL );
    9206
    9207 nlinvars = SCIPgetNVarsLinear(scip, lincons);
    9208 linvars = SCIPgetVarsLinear(scip, lincons);
    9209 linvals = SCIPgetValsLinear(scip, lincons);
    9210
    9211 /* compute value of regular variables */
    9212 sum = 0.0;
    9213 slackcoef = 0.0;
    9214 for (v = 0; v < nlinvars; ++v)
    9215 {
    9216 SCIP_VAR* var;
    9217 var = linvars[v];
    9218 if ( var != slackvar )
    9219 sum += linvals[v] * SCIPgetSolVal(scip, sol, var);
    9220 else
    9221 slackcoef = linvals[v];
    9222 }
    9223
    9224 /* do nothing if slack variable does not appear */
    9225 if ( SCIPisFeasZero(scip, slackcoef) )
    9226 return SCIP_OKAY;
    9227
    9228 assert( ! SCIPisZero(scip, slackcoef) );
    9229 assert( slackcoef != 0.0 ); /* to satisfy lint */
    9230 assert( SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, lincons)) || SCIPisInfinity(scip, SCIPgetRhsLinear(scip, lincons)) );
    9231 assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(slackvar), 0.0) );
    9232
    9233 val = SCIPgetRhsLinear(scip, lincons);
    9234 sigma = 1;
    9235 if ( SCIPisInfinity(scip, val) )
    9236 {
    9237 val = SCIPgetLhsLinear(scip, lincons);
    9238 assert( ! SCIPisInfinity(scip, REALABS(val)) );
    9239 sigma = -1;
    9240 }
    9241 /* compute value of slack that would achieve equality */
    9242 val = (val - sum)/slackcoef;
    9243
    9244 /* compute direction into which slack variable would be infeasible */
    9245 if ( slackcoef < 0 )
    9246 sigma *= -1;
    9247
    9248 /* filter out cases in which no sensible change is possible */
    9249 if ( sigma > 0 && SCIPisFeasNegative(scip, val) )
    9250 return SCIP_OKAY;
    9251
    9252 /* check if linear constraint w/o slack variable is violated */
    9253 if ( sigma < 0 && SCIPisFeasPositive(scip, val) )
    9254 {
    9255 /* the original constraint is violated */
    9256 if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, slackvar), val) )
    9257 {
    9258 SCIP_CALL( SCIPsetSolVal(scip, sol, slackvar, val) );
    9259 *changed = TRUE;
    9260 }
    9261 /* check whether binary variable is fixed or its negated variable is fixed */
    9262 if ( SCIPvarGetStatus(binvar) != SCIP_VARSTATUS_FIXED &&
    9264 {
    9265 if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 0.0) )
    9266 {
    9267 SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 0.0) );
    9268 *changed = TRUE;
    9269 }
    9270 }
    9271 }
    9272 else
    9273 {
    9274 assert( SCIPisFeasGE(scip, val * ((SCIP_Real) sigma), 0.0) );
    9275
    9276 /* the original constraint is satisfied - we can set the slack variable to 0 (slackvar
    9277 * should only occur in this indicator constraint) */
    9278 if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, slackvar), 0.0) && SCIPisFeasPositive(scip, SCIPvarGetLbLocal(slackvar)) )
    9279 {
    9280 SCIP_CALL( SCIPsetSolVal(scip, sol, slackvar, 0.0) );
    9281 *changed = TRUE;
    9282 }
    9283
    9284 /* check whether binary variable is fixed or its negated variable is fixed */
    9285 if ( SCIPvarGetStatus(binvar) != SCIP_VARSTATUS_FIXED &&
    9287 {
    9288 SCIP_Real obj;
    9289 obj = varGetObjDelta(binvar);
    9290
    9291 /* check objective for possibly setting binary variable */
    9292 if ( obj <= 0 )
    9293 {
    9294 /* setting variable to 1 does not increase objective - check whether we can set it to 1 */
    9295 if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 1.0) )
    9296 {
    9297 /* check whether variable only occurs in the current constraint */
    9298 if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
    9299 {
    9300 SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 1.0) );
    9301 *changed = TRUE;
    9302 /* make sure that the other case does not occur if obj = 0: prefer variables set to 1 */
    9303 obj = -1.0;
    9304 }
    9305 }
    9306 else
    9307 {
    9308 /* make sure that the other case does not occur if obj = 0: prefer variables set to 1 */
    9309 obj = -1.0;
    9310 }
    9311 }
    9312 if ( obj >= 0 )
    9313 {
    9314 /* setting variable to 0 does not increase objective -> check whether variable only occurs in the current constraint
    9315 * note: binary variables are only locked up */
    9317 && ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 0.0) )
    9318 {
    9319 SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 0.0) );
    9320 *changed = TRUE;
    9321 }
    9322 }
    9323 }
    9324 }
    9325 }
    9326
    9327 return SCIP_OKAY;
    9328}
    9329
    9330
    9331/** based on values of other variables, computes slack and binary variable to turn all constraints feasible */
    9333 SCIP* scip, /**< SCIP data structure */
    9334 SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
    9335 SCIP_SOL* sol, /**< solution */
    9336 SCIP_Bool* changed /**< pointer to store whether the solution has been changed */
    9337 )
    9338{
    9339 SCIP_CONS** conss;
    9340 int nconss;
    9341 int c;
    9342
    9343 assert( conshdlr != NULL );
    9344 assert( sol != NULL );
    9345 assert( changed != NULL );
    9346
    9348
    9349 *changed = FALSE;
    9350
    9351 /* only run after or in presolving */
    9353 return SCIP_OKAY;
    9354
    9355 conss = SCIPconshdlrGetConss(conshdlr);
    9356 nconss = SCIPconshdlrGetNConss(conshdlr);
    9357
    9358 for (c = 0; c < nconss; ++c)
    9359 {
    9360 SCIP_CONSDATA* consdata;
    9361 SCIP_Bool chg = FALSE;
    9362 assert( conss[c] != NULL );
    9363
    9364 consdata = SCIPconsGetData(conss[c]);
    9365 assert( consdata != NULL );
    9366
    9367 /* if the linear constraint is not present, we stop */
    9368 if ( ! consdata->linconsactive )
    9369 break;
    9370
    9371 SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], sol, &chg) );
    9372 *changed = *changed || chg;
    9373 }
    9374
    9375 return SCIP_OKAY;
    9376}
    9377
    9378
    9379/** adds additional linear constraint that is not connected with an indicator constraint, but can be used for separation */
    9381 SCIP* scip, /**< SCIP data structure */
    9382 SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
    9383 SCIP_CONS* lincons /**< linear constraint */
    9384 )
    9385{
    9386 assert( scip != NULL );
    9387 assert( lincons != NULL );
    9388
    9390
    9391 /* do not add locally valid constraints (this would require much more bookkeeping) */
    9392 if ( ! SCIPconsIsLocal(lincons) && ! SCIPconsIsModifiable(lincons) )
    9393 {
    9394 SCIP_CONSHDLRDATA* conshdlrdata;
    9395
    9396 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9397 assert( conshdlrdata != NULL );
    9398
    9399 SCIP_CALL( consdataEnsureAddLinConsSize(scip, conshdlr, conshdlrdata->naddlincons+1) );
    9400 assert( conshdlrdata->naddlincons+1 <= conshdlrdata->maxaddlincons );
    9401
    9402 conshdlrdata->addlincons[conshdlrdata->naddlincons++] = lincons;
    9403 }
    9404
    9405 return SCIP_OKAY;
    9406}
    9407
    9408
    9409/** adds additional row that is not connected with an indicator constraint, but can be used for separation
    9410 *
    9411 * @note The row is directly added to the alternative polyhedron and is not stored.
    9412 */
    9414 SCIP* scip, /**< SCIP data structure */
    9415 SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
    9416 SCIP_ROW* row /**< row to add */
    9417 )
    9418{
    9419 assert( scip != NULL );
    9420 assert( row != NULL );
    9421
    9423
    9424 /* skip local cuts (local cuts would require to dynamically add and remove columns from the alternative polyhedron */
    9425 if ( ! SCIProwIsLocal(row) )
    9426 {
    9427 int colindex;
    9428 SCIP_CONSHDLRDATA* conshdlrdata;
    9429
    9430 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9431 assert( conshdlrdata != NULL );
    9432
    9433 /* do not add rows if we do not separate */
    9434 if ( ! conshdlrdata->sepaalternativelp )
    9435 return SCIP_OKAY;
    9436
    9437 SCIPdebugMsg(scip, "Adding row <%s> to alternative LP.\n", SCIProwGetName(row));
    9438
    9439 /* add row directly to alternative polyhedron */
    9440 SCIP_CALL( addAltLPRow(scip, conshdlr, row, 0.0, &colindex) );
    9441 }
    9442
    9443 return SCIP_OKAY;
    9444}
    static long bound
    static SCIP_RETCODE branchCons(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result)
    #define DEFAULT_FORCERESTART
    static SCIP_DECL_CONSCHECK(consCheckIndicator)
    #define DEFAULT_TRYSOLUTIONS
    #define EVENTHDLR_RESTART_NAME
    static SCIP_RETCODE addAltLPRow(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_ROW *row, SCIP_Real objcoef, int *colindex)
    #define CONSHDLR_NEEDSCONS
    #define CONSHDLR_SEPAFREQ
    #define CONFLICTHDLR_PRIORITY
    #define SCIP_CALL_PARAM(x)
    static SCIP_DECL_CONSCOPY(consCopyIndicator)
    static SCIP_DECL_CONSSEPALP(consSepalpIndicator)
    static SCIP_DECL_CONSPARSE(consParseIndicator)
    #define CONFLICTHDLR_NAME
    static SCIP_DECL_CONSENFOPS(consEnfopsIndicator)
    #define CONSHDLR_CHECKPRIORITY
    #define DEFAULT_ADDCOUPLINGCONS
    #define MAXROUNDINGROUNDS
    #define CONSHDLR_DESC
    #define DEFAULT_ADDOPPOSITE
    static SCIP_RETCODE checkLPBoundsClean(SCIP *scip, SCIP_LPI *lp, int nconss, SCIP_CONS **conss)
    static SCIP_DECL_CONSPRINT(consPrintIndicator)
    static SCIP_RETCODE propIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_Bool dualreductions, SCIP_Bool addopposite, SCIP_Bool *cutoff, int *nGen)
    static SCIP_RETCODE updateFirstRowGlobal(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
    static SCIP_DECL_CONSEXIT(consExitIndicator)
    static SCIP_RETCODE fixAltLPVariables(SCIP *scip, SCIP_LPI *lp, int nconss, SCIP_CONS **conss, SCIP_Bool *S)
    static SCIP_RETCODE createVarUbs(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *ngen)
    static SCIP_DECL_CONSEXITSOL(consExitsolIndicator)
    #define CONSHDLR_PROP_TIMING
    #define DEFAULT_USEOBJECTIVECUT
    static SCIP_RETCODE addAltLPConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *lincons, SCIP_VAR *slackvar, SCIP_Real objcoef, int *colindex)
    static SCIP_RETCODE extendToCover(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_LPI *lp, SCIP_SOL *sol, SCIP_ENFOSEPATYPE enfosepatype, SCIP_Bool removable, SCIP_Bool genlogicor, int nconss, SCIP_CONS **conss, SCIP_Bool *S, int *size, SCIP_Real *value, SCIP_Bool *error, SCIP_Bool *cutoff, int *nGen)
    #define CONFLICTHDLR_DESC
    static SCIP_RETCODE scaleFirstRow(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
    static SCIP_RETCODE separateIISRounding(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_ENFOSEPATYPE enfosepatype, int nconss, SCIP_CONS **conss, int maxsepacuts, SCIP_Bool *cutoff, int *nGen)
    static SCIP_DECL_CONSFREE(consFreeIndicator)
    static SCIP_DECL_CONSGETNVARS(consGetNVarsIndicator)
    static SCIP_Real varGetObjDelta(SCIP_VAR *var)
    #define CONSHDLR_MAXPREROUNDS
    static SCIP_RETCODE addAltLPColumn(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *slackvar, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real rhscoef, SCIP_Real objcoef, SCIP_Real sign, SCIP_Bool colfree, int *colindex)
    #define DEFAULT_MAXCONDITIONALTLP
    static SCIP_RETCODE presolRoundIndicator(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_Bool dualreductions, SCIP_Bool *cutoff, SCIP_Bool *success, int *ndelconss, int *nfixedvars)
    #define DEFAULT_SCALESLACKVAR
    static SCIP_RETCODE checkAltLPInfeasible(SCIP *scip, SCIP_LPI *lp, SCIP_Real maxcondition, SCIP_Bool primal, SCIP_Bool *infeasible, SCIP_Bool *error)
    static SCIP_DECL_CONSDISABLE(consDisableIndicator)
    #define CONSHDLR_SEPAPRIORITY
    static SCIP_RETCODE setAltLPObj(SCIP *scip, SCIP_LPI *lp, SCIP_SOL *sol, int nconss, SCIP_CONS **conss)
    static SCIP_RETCODE checkIISlocal(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_Real *vector, SCIP_Bool *isLocal)
    #define DEFAULT_USESAMESLACKVAR
    static SCIP_DECL_CONSSEPASOL(consSepasolIndicator)
    static SCIP_DECL_LINCONSUPGD(linconsUpgdIndicator)
    #define DEFAULT_SEPAPERSPLOCAL
    static SCIP_DECL_CONSDELETE(consDeleteIndicator)
    static SCIP_DECL_CONFLICTFREE(conflictFreeIndicator)
    static SCIP_RETCODE unfixAltLPVariables(SCIP *scip, SCIP_LPI *lp, int nconss, SCIP_CONS **conss, SCIP_Bool *S)
    static SCIP_RETCODE separatePerspective(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, int nconss, SCIP_CONS **conss, int maxsepacuts, int *nGen)
    #define DEFAULT_SEPAPERSPECTIVE
    static SCIP_DECL_CONSGETVARS(consGetVarsIndicator)
    static SCIP_RETCODE enforceCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_ENFOSEPATYPE enfosepatype, SCIP_Bool genlogicor, SCIP_Bool *cutoff, int *nGen)
    #define DEFAULT_CONFLICTSUPGRADE
    static SCIP_RETCODE initAlternativeLP(SCIP *scip, SCIP_CONSHDLR *conshdlr)
    #define DEFAULT_MAXCOUPLINGVALUE
    #define SEPAALTTHRESHOLD
    #define DEFAULT_SEPACOUPLINGVALUE
    static SCIP_DECL_CONSINITSOL(consInitsolIndicator)
    static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
    #define DEFAULT_REMOVEINDICATORS
    #define DEFAULT_UPGRADELINEAR
    static SCIP_DECL_CONSLOCK(consLockIndicator)
    #define EVENTHDLR_LINCONSBOUND_DESC
    #define DEFAULT_MAXSEPACUTSROOT
    static SCIP_DECL_CONSINITPRE(consInitpreIndicator)
    static SCIP_DECL_CONSTRANS(consTransIndicator)
    static SCIP_RETCODE updateObjUpperbound(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
    static SCIP_RETCODE checkTransferBoolParam(SCIP *scip, SCIP_PARAM *param, const char *name, SCIP_Bool newvalue, SCIP_Bool *value)
    #define EVENTHDLR_BOUND_DESC
    static SCIP_RETCODE separateIndicators(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, int nusefulconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_ENFOSEPATYPE enfosepatype, SCIP_RESULT *result)
    static SCIP_RETCODE fixAltLPVariable(SCIP_LPI *lp, int ind)
    enum SCIP_enfosepatype SCIP_ENFOSEPATYPE
    #define DEFAULT_SEPACOUPLINGLOCAL
    #define EVENTHDLR_LINCONSBOUND_NAME
    #define DEFAULT_UPDATEBOUNDS
    static SCIP_DECL_CONSINITLP(consInitlpIndicator)
    #define DEFAULT_RESTARTFRAC
    static SCIP_RETCODE enforceIndicators(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_ENFOSEPATYPE enfosepatype, SCIP_Bool genlogicor, SCIP_RESULT *result)
    #define CONSHDLR_PROPFREQ
    #define DEFAULT_SEPAALTERNATIVELP
    static void initConshdlrData(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
    #define DEFAULT_ENFORCECUTS
    #define CONSHDLR_PRESOLTIMING
    static SCIP_RETCODE unfixAltLPVariable(SCIP_LPI *lp, int ind)
    static SCIP_RETCODE consdataEnsureAddLinConsSize(SCIP *scip, SCIP_CONSHDLR *conshdlr, int num)
    static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyIndicator)
    #define DEFAULT_MAXSEPACUTS
    static SCIP_RETCODE setAltLPObjZero(SCIP *scip, SCIP_LPI *lp, int nconss, SCIP_CONS **conss)
    #define EVENTHDLR_BOUND_NAME
    #define OBJEPSILON
    #define DEFAULT_BRANCHINDICATORS
    static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphIndicator)
    #define CONSHDLR_EAGERFREQ
    static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphIndicator)
    static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, const char *consname, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlrrestart, SCIP_VAR *binvar, SCIP_Bool activeone, SCIP_Bool lessthanineq, SCIP_VAR *slackvar, SCIP_CONS *lincons, SCIP_Bool linconsactive)
    static SCIP_DECL_CONSRESPROP(consRespropIndicator)
    static SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsIndicator)
    #define DEFAULT_USEOTHERCONSS
    SCIP_enfosepatype
    @ SCIP_TYPE_ENFORELAX
    @ SCIP_TYPE_SEPALP
    @ SCIP_TYPE_SEPARELAX
    @ SCIP_TYPE_ENFOLP
    @ SCIP_TYPE_SEPASOL
    @ SCIP_TYPE_ENFOPS
    #define CONSHDLR_ENFOPRIORITY
    #define DEFAULT_DUALREDUCTIONS
    static SCIP_DECL_CONSENABLE(consEnableIndicator)
    static SCIP_RETCODE deleteAltLPConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
    #define LINCONSUPGD_PRIORITY
    #define DEFAULT_GENERATEBILINEAR
    #define CONSHDLR_DELAYSEPA
    static SCIP_RETCODE addObjcut(SCIP *scip, SCIP_CONSHDLR *conshdlr)
    #define DEFAULT_GENLOGICOR
    #define CONSHDLR_NAME
    #define DEFAULT_TRYSOLFROMCOVER
    static SCIP_DECL_CONSENFOLP(consEnfolpIndicator)
    static SCIP_DECL_CONSENFORELAX(consEnforelaxIndicator)
    #define EVENTHDLR_RESTART_DESC
    static SCIP_DECL_CONSPROP(consPropIndicator)
    static SCIP_DECL_CONSPRESOL(consPresolIndicator)
    static SCIP_DECL_EVENTEXEC(eventExecIndicatorBound)
    #define DEFAULT_MAXSEPANONVIOLATED
    #define DEFAULT_ADDCOUPLING
    #define DEFAULT_SEPACOUPLINGCUTS
    static SCIP_RETCODE updateFirstRow(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
    static SCIP_DECL_PARAMCHGD(paramChangedIndicator)
    static SCIP_DECL_CONSINIT(consInitIndicator)
    #define CONSHDLR_DELAYPROP
    #define DEFAULT_NOLINCONSCONT
    static SCIP_DECL_CONFLICTEXEC(conflictExecIndicator)
    constraint handler for indicator constraints
    Constraint handler for linear constraints in their most general form, .
    Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
    constraint handler for nonlinear constraints specified by algebraic expressions
    Constraint handler for variable bound constraints .
    #define NULL
    Definition: def.h:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #define MAX3(x, y, z)
    Definition: def.h:237
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define SCIPABORT()
    Definition: def.h:336
    #define SCIP_REAL_MIN
    Definition: def.h:168
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    product expression handler
    variable expression handler
    SCIP_RETCODE SCIPcreateConsIndicatorGenericLinConsPure(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, SCIP_CONS *lincons, SCIP_Bool activeone, 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)
    SCIP_RETCODE SCIPcreateConsIndicatorLinCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, SCIP_CONS *lincons, SCIP_VAR *slackvar, 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)
    SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
    SCIP_RETCODE SCIPcreateConsBasicIndicator(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real rhs)
    SCIP_VAR * SCIPgetBinaryVarIndicatorGeneric(SCIP_CONS *cons)
    SCIP_RETCODE SCIPsetSlackVarUb(SCIP *scip, SCIP_CONS *cons, SCIP_Real ub)
    SCIP_Real SCIPgetRhsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
    SCIP_RETCODE SCIPaddRowIndicator(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_ROW *row)
    SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsIndicatorGeneric(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real rhs, SCIP_Bool activeone, SCIP_Bool lessthanineq, 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)
    int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPaddLinearConsIndicator(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *lincons)
    SCIP_RETCODE SCIPsetLinearConsIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_CONS *lincons)
    SCIP_RETCODE SCIPcreateConsIndicator(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real rhs, 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)
    SCIP_Real * SCIPgetValsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsIndicatorGenericLinCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, SCIP_CONS *lincons, SCIP_VAR *slackvar, SCIP_Bool activeone, 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)
    SCIP_RETCODE SCIPcreateConsBasicIndicatorLinCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, SCIP_CONS *lincons, SCIP_VAR *slackvar)
    SCIP_RETCODE SCIPmakeIndicatorsFeasible(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_Bool *changed)
    SCIP_VAR * SCIPgetBinaryVarIndicator(SCIP_CONS *cons)
    SCIP_VAR * SCIPgetSlackVarIndicator(SCIP_CONS *cons)
    SCIP_CONS * SCIPgetLinearConsIndicator(SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    SCIP_RETCODE SCIPcreateConsLogicor(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)
    SCIP_RETCODE SCIPsetBinaryVarIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *binvar)
    SCIP_RETCODE SCIPmakeIndicatorFeasible(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *changed)
    SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    SCIP_RETCODE SCIPcreateConsQuadraticNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, 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_RETCODE SCIPcreateConsIndicatorLinConsPure(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, SCIP_CONS *lincons, 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)
    SCIP_Bool SCIPisViolatedIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
    SCIP_RETCODE SCIPaddVarIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
    SCIP_Bool SCIPgetActiveOnIndicator(SCIP_CONS *cons)
    SCIP_RETCODE SCIPincludeConshdlrIndicator(SCIP *scip)
    SCIP_RETCODE SCIPgetConsCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_CONS *sourcecons, SCIP_CONS **targetcons, SCIP_CONSHDLR *sourceconshdlr, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, const char *name, 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_Bool global, SCIP_Bool *valid)
    Definition: scip_copy.c:1581
    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
    SCIP_RETCODE SCIPcreateExprVar(SCIP *scip, SCIP_EXPR **expr, SCIP_VAR *var, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_var.c:397
    SCIP_RETCODE SCIPcreateExprProduct(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real coefficient, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    SCIP_Bool SCIPisTransformed(SCIP *scip)
    Definition: scip_general.c:655
    SCIP_STATUS SCIPgetStatus(SCIP *scip)
    Definition: scip_general.c:562
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_prob.c:1907
    int SCIPgetNIntVars(SCIP *scip)
    Definition: scip_prob.c:2340
    SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
    Definition: scip_prob.c:2115
    SCIP_CONS ** SCIPgetConss(SCIP *scip)
    Definition: scip_prob.c:3666
    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
    int SCIPgetNConss(SCIP *scip)
    Definition: scip_prob.c:3620
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    int SCIPgetNOrigVars(SCIP *scip)
    Definition: scip_prob.c:2838
    int SCIPgetNBinVars(SCIP *scip)
    Definition: scip_prob.c:2293
    SCIP_Bool SCIPisObjIntegral(SCIP *scip)
    Definition: scip_prob.c:1801
    SCIP_VAR * SCIPfindVar(SCIP *scip, const char *name)
    Definition: scip_prob.c:3189
    SCIP_CONS * SCIPfindCons(SCIP *scip, const char *name)
    Definition: scip_prob.c:3525
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    void SCIPhashmapPrintStatistics(SCIP_HASHMAP *hashmap, SCIP_MESSAGEHDLR *messagehdlr)
    Definition: misc.c:3528
    int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3304
    void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3284
    SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
    Definition: misc.c:3143
    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 SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3400
    SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
    Definition: lpi_clp.cpp:1179
    SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:3947
    SCIP_Bool SCIPlpiIsInfinity(SCIP_LPI *lpi, SCIP_Real val)
    Definition: lpi_clp.cpp:3959
    SCIP_Bool SCIPlpiExistsPrimalRay(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:2478
    SCIP_RETCODE SCIPlpiAddRows(SCIP_LPI *lpi, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
    Definition: lpi_clp.cpp:920
    SCIP_RETCODE SCIPlpiWriteLP(SCIP_LPI *lpi, const char *fname)
    Definition: lpi_clp.cpp:4029
    SCIP_RETCODE SCIPlpiGetBounds(SCIP_LPI *lpi, int firstcol, int lastcol, SCIP_Real *lbs, SCIP_Real *ubs)
    Definition: lpi_clp.cpp:1733
    int SCIPlpiGetInternalStatus(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:2780
    SCIP_RETCODE SCIPlpiChgBounds(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *lb, const SCIP_Real *ub)
    Definition: lpi_clp.cpp:1096
    SCIP_Bool SCIPlpiIsPrimalUnbounded(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:2516
    SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
    Definition: lpi_clp.cpp:643
    SCIP_RETCODE SCIPlpiGetCoef(SCIP_LPI *lpi, int row, int col, SCIP_Real *val)
    Definition: lpi_clp.cpp:1799
    SCIP_RETCODE SCIPlpiGetRealSolQuality(SCIP_LPI *lpi, SCIP_LPSOLQUALITY qualityindicator, SCIP_Real *quality)
    Definition: lpi_clp.cpp:2968
    SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
    Definition: lpi_clp.cpp:3720
    SCIP_RETCODE SCIPlpiGetRows(SCIP_LPI *lpi, int firstrow, int lastrow, SCIP_Real *lhs, SCIP_Real *rhs, int *nnonz, int *beg, int *ind, SCIP_Real *val)
    Definition: lpi_clp.cpp:1552
    SCIP_Bool SCIPlpiIsOptimal(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:2651
    SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
    Definition: lpi_clp.cpp:2816
    SCIP_Bool SCIPlpiIsPrimalInfeasible(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:2530
    SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:1908
    SCIP_RETCODE SCIPlpiAddCols(SCIP_LPI *lpi, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
    Definition: lpi_clp.cpp:758
    SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:1833
    SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
    Definition: lpi_clp.cpp:531
    SCIP_RETCODE SCIPlpiChgObj(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *obj)
    Definition: lpi_clp.cpp:1252
    SCIP_Bool SCIPlpiIsStable(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:2675
    SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
    Definition: lpi_clp.cpp:1447
    SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
    Definition: lpi_clp.cpp:1429
    SCIP_RETCODE SCIPlpiChgCoef(SCIP_LPI *lpi, int row, int col, SCIP_Real newval)
    Definition: lpi_clp.cpp:1209
    SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:4067
    SCIP_RETCODE SCIPaddConflict(SCIP *scip, SCIP_NODE *node, SCIP_CONS **cons, SCIP_NODE *validnode, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
    Definition: scip_prob.c:3806
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:225
    SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
    Definition: scip_message.c:88
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
    Definition: scip_message.c:120
    SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
    Definition: misc.c:11162
    SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
    Definition: heur_trysol.c:259
    SCIP_RETCODE SCIPheurPassIndicator(SCIP *scip, SCIP_HEUR *heur, int nindconss, SCIP_CONS **indconss, SCIP_Bool *solcand, SCIP_Real obj)
    SCIP_Bool SCIPisParamFixed(SCIP *scip, const char *name)
    Definition: scip_param.c:219
    SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:83
    SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:139
    SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
    Definition: scip_param.c:487
    SCIP_RETCODE SCIPchgBoolParam(SCIP *scip, SCIP_PARAM *param, SCIP_Bool value)
    Definition: scip_param.c:403
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    SCIP_RETCODE SCIPgetCharParam(SCIP *scip, const char *name, char *value)
    Definition: scip_param.c:326
    SCIP_BRANCHRULE * SCIPfindBranchrule(SCIP *scip, const char *name)
    Definition: scip_branch.c:304
    SCIP_Real SCIPcalcChildEstimate(SCIP *scip, SCIP_VAR *var, SCIP_Real targetvalue)
    Definition: scip_branch.c:955
    SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
    Definition: scip_branch.c:1025
    SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
    Definition: lp.c:17425
    SCIP_BOUNDTYPE SCIPboundtypeOpposite(SCIP_BOUNDTYPE boundtype)
    Definition: lp.c:17597
    SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
    SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
    SCIP_CONFLICTHDLRDATA * SCIPconflicthdlrGetData(SCIP_CONFLICTHDLR *conflicthdlr)
    SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
    const char * SCIPconflicthdlrGetName(SCIP_CONFLICTHDLR *conflicthdlr)
    SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
    SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
    SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
    SCIP_RETCODE SCIPincludeConflicthdlrBasic(SCIP *scip, SCIP_CONFLICTHDLR **conflicthdlrptr, const char *name, const char *desc, int priority, SCIP_DECL_CONFLICTEXEC((*conflictexec)), SCIP_CONFLICTHDLRDATA *conflicthdlrdata)
    SCIP_RETCODE SCIPsetConflicthdlrFree(SCIP *scip, SCIP_CONFLICTHDLR *conflicthdlr, SCIP_DECL_CONFLICTFREE((*conflictfree)))
    SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
    Definition: scip_cons.c:808
    SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
    Definition: scip_cons.c:716
    SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
    Definition: scip_cons.c:540
    SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
    Definition: scip_cons.c:396
    SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
    Definition: scip_cons.c:831
    SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
    Definition: scip_cons.c:492
    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 SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
    Definition: scip_cons.c:739
    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:4782
    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:4320
    SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
    Definition: scip_cons.c:420
    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:4340
    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
    int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4816
    SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
    Definition: scip_cons.c:854
    int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:5276
    SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4739
    SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
    Definition: scip_cons.c:785
    SCIP_RETCODE SCIPgetConsNVars(SCIP *scip, SCIP_CONS *cons, int *nvars, SCIP_Bool *success)
    Definition: scip_cons.c:2621
    SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
    Definition: cons.c:8423
    SCIP_RETCODE SCIPenfopsCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool solinfeasible, SCIP_Bool objinfeasible, SCIP_RESULT *result)
    Definition: scip_cons.c:2163
    void SCIPconsAddUpgradeLocks(SCIP_CONS *cons, int nlocks)
    Definition: cons.c:8832
    SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
    Definition: cons.c:8652
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8413
    SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
    Definition: cons.c:8562
    SCIP_RETCODE SCIPenfolpCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool solinfeasible, SCIP_RESULT *result)
    Definition: scip_cons.c:2194
    SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
    Definition: scip_cons.c:2536
    int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
    Definition: cons.c:8845
    SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
    Definition: cons.c:8592
    SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
    Definition: cons.c:8522
    SCIP_RETCODE SCIPsepalpCons(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result)
    Definition: scip_cons.c:2283
    SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
    Definition: cons.c:8702
    SCIP_RETCODE SCIPgetConsVars(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **vars, int varssize, SCIP_Bool *success)
    Definition: scip_cons.c:2577
    SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
    Definition: cons.c:8582
    SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
    Definition: cons.c:8454
    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:8612
    SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
    Definition: cons.c:8632
    SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
    Definition: cons.c:8490
    SCIP_RETCODE SCIPdisableCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1871
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8393
    SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1812
    SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
    Definition: cons.c:8642
    SCIP_RETCODE SCIPgetTransformedCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONS **transcons)
    Definition: scip_cons.c:1674
    SCIP_RETCODE SCIPenforelaxCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
    Definition: scip_cons.c:2224
    SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
    Definition: cons.c:8672
    SCIP_RETCODE SCIPsepasolCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_RESULT *result)
    Definition: scip_cons.c:2310
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
    Definition: cons.c:8572
    SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1138
    SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1784
    SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
    Definition: cons.c:8662
    SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:336
    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_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_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
    Definition: scip_event.c:293
    SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
    Definition: scip_event.c:333
    SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
    Definition: scip_expr.c:1443
    SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
    Definition: scip_heur.c:263
    #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 SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #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 SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
    Definition: scip_nlp.c:396
    SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
    Definition: scip_nlp.c:110
    SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
    Definition: scip_nlp.c:1058
    SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
    Definition: scip_nlp.c:954
    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_Bool SCIPinProbing(SCIP *scip)
    Definition: scip_probing.c:98
    SCIP_RETCODE SCIPaddDiveBoundChange(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir, SCIP_Real value, SCIP_Bool preferred)
    SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
    Definition: lp.c:17686
    SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1581
    int SCIProwGetNNonz(SCIP_ROW *row)
    Definition: lp.c:17607
    SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
    Definition: lp.c:17632
    SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
    Definition: lp.c:17696
    SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1398
    SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1604
    SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
    Definition: lp.c:17795
    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
    const char * SCIProwGetName(SCIP_ROW *row)
    Definition: lp.c:17745
    SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
    Definition: scip_lp.c:2131
    SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
    Definition: lp.c:17652
    SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_lp.c:1672
    SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
    Definition: lp.c:17642
    SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
    Definition: scip_sol.c:882
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1250
    void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
    Definition: scip_sol.c:451
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1569
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
    Definition: scip_solve.c:3616
    SCIP_Real SCIPgetPrimalbound(SCIP *scip)
    SCIP_Real SCIPgetUpperbound(SCIP *scip)
    SCIP_Real SCIPgetDualbound(SCIP *scip)
    int SCIPgetNRuns(SCIP *scip)
    SCIP_Longint SCIPgetNConflictConssApplied(SCIP *scip)
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasZero(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_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPinRepropagation(SCIP *scip)
    Definition: scip_tree.c:146
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_RETCODE SCIPvarGetProbvarBound(SCIP_VAR **var, SCIP_Real *bound, SCIP_BOUNDTYPE *boundtype)
    Definition: var.c:17846
    SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
    Definition: var.c:23566
    SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
    Definition: scip_var.c:5210
    SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
    Definition: var.c:23900
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23674
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23418
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4380
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23530
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Bool SCIPdoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:10942
    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_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:5875
    SCIP_RETCODE SCIPchgVarUbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:6088
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    SCIP_Real SCIPvarGetAggrScalar(SCIP_VAR *var)
    Definition: var.c:23780
    SCIP_RETCODE SCIPchgVarImplType(SCIP *scip, SCIP_VAR *var, SCIP_IMPLINTTYPE impltype, SCIP_Bool *infeasible)
    Definition: scip_var.c:10218
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
    Definition: scip_var.c:2499
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    SCIP_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_RETCODE SCIPcreateVarImpl(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_IMPLINTTYPE impltype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
    Definition: scip_var.c:225
    SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
    Definition: scip_var.c:2872
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23694
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_VAR * SCIPbdchginfoGetVar(SCIP_BDCHGINFO *bdchginfo)
    Definition: var.c:24961
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
    Definition: scip_var.c:5634
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23522
    SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
    Definition: scip_var.c:10113
    SCIP_Real SCIPgetVarSol(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:3051
    SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
    Definition: scip_var.c:2166
    SCIP_RETCODE SCIPaddVarImplication(SCIP *scip, SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool *infeasible, int *nbdchgs)
    Definition: scip_var.c:8740
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
    Definition: var.c:23475
    SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
    Definition: var.c:23910
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    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
    SCIP_RETCODE SCIPchgVarLbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:6044
    SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
    Definition: var.c:17687
    SCIP_BOUNDTYPE SCIPbdchginfoGetBoundtype(SCIP_BDCHGINFO *bdchginfo)
    Definition: var.c:24981
    SCIP_Real SCIPbdchginfoGetNewbound(SCIP_BDCHGINFO *bdchginfo)
    Definition: var.c:24951
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4322
    SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
    Definition: scip_var.c:10998
    SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
    Definition: scip_var.c:2078
    SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:1853
    SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
    Definition: scip_var.c:10984
    SCIP_VAR * SCIPvarGetAggrVar(SCIP_VAR *var)
    Definition: var.c:23768
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    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)
    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)
    handle partial solutions for linear problems with indicators and otherwise continuous variables
    primal heuristic that tries a given solution
    interface methods for specific LP solvers
    static const char * paramname[]
    Definition: lpi_msk.c:5172
    memory allocation routines
    #define BMScopyMemoryArray(ptr, source, num)
    Definition: memory.h:134
    const char * SCIPparamGetName(SCIP_PARAM *param)
    Definition: paramset.c:656
    SCIP_PARAMTYPE SCIPparamGetType(SCIP_PARAM *param)
    Definition: paramset.c:646
    public methods for conflict analysis handlers
    public methods for managing constraints
    public methods for managing events
    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
    #define SCIPdebugPrintCons(x, y, z)
    Definition: pub_message.h:102
    public data structures and miscellaneous methods
    public methods for handling parameter settings
    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 event handler plugins and event handlers
    general public methods
    public methods for primal heuristic plugins and divesets
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for nonlinear relaxation
    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 solving methods
    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:1219
    structs for symmetry computations
    methods for dealing with symmetry detection graphs
    @ SCIP_CONFTYPE_PROPAGATION
    Definition: type_conflict.h:62
    struct SCIP_ConflicthdlrData SCIP_CONFLICTHDLRDATA
    Definition: type_conflict.h:50
    struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
    Definition: type_cons.h:64
    struct SCIP_ConsData SCIP_CONSDATA
    Definition: type_cons.h:65
    #define SCIP_EVENTTYPE_BOUNDCHANGED
    Definition: type_event.h:127
    #define SCIP_EVENTTYPE_GUBCHANGED
    Definition: type_event.h:76
    #define SCIP_EVENTTYPE_GBDCHANGED
    Definition: type_event.h:122
    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_BESTSOLFOUND
    Definition: type_event.h:106
    #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
    @ SCIP_EXPRCURV_UNKNOWN
    Definition: type_expr.h:62
    #define SCIP_DIVETYPE_INTEGRALITY
    Definition: type_heur.h:60
    @ SCIP_BRANCHDIR_DOWNWARDS
    Definition: type_history.h:43
    @ SCIP_BRANCHDIR_UPWARDS
    Definition: type_history.h:44
    @ SCIP_BOUNDTYPE_UPPER
    Definition: type_lp.h:58
    @ SCIP_BOUNDTYPE_LOWER
    Definition: type_lp.h:57
    enum SCIP_BoundType SCIP_BOUNDTYPE
    Definition: type_lp.h:60
    type definitions for specific LP solvers interface
    @ SCIP_LPSOLQUALITY_ESTIMCONDITION
    Definition: type_lpi.h:101
    @ SCIP_LPPAR_SCALING
    Definition: type_lpi.h:52
    @ SCIP_LPPAR_PRESOLVING
    Definition: type_lpi.h:53
    @ SCIP_LPPAR_FASTMIP
    Definition: type_lpi.h:51
    @ SCIP_LPPAR_FROMSCRATCH
    Definition: type_lpi.h:50
    @ SCIP_OBJSEN_MINIMIZE
    Definition: type_lpi.h:43
    @ SCIP_VERBLEVEL_MINIMAL
    Definition: type_message.h:59
    @ SCIP_VERBLEVEL_NORMAL
    Definition: type_message.h:60
    @ SCIP_PARAMTYPE_BOOL
    Definition: type_paramset.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_CONSADDED
    Definition: type_result.h:52
    @ 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_LPERROR
    Definition: type_retcode.h:49
    @ SCIP_INVALIDDATA
    Definition: type_retcode.h:52
    @ SCIP_PLUGINNOTFOUND
    Definition: type_retcode.h:54
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    @ SCIP_ERROR
    Definition: type_retcode.h:43
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_PROBLEM
    Definition: type_set.h:45
    @ SCIP_STAGE_INITPRESOLVE
    Definition: type_set.h:48
    @ SCIP_STAGE_SOLVED
    Definition: type_set.h:54
    @ SCIP_STAGE_INITSOLVE
    Definition: type_set.h:52
    @ SCIP_STAGE_EXITSOLVE
    Definition: type_set.h:55
    @ SCIP_STAGE_SOLVING
    Definition: type_set.h:53
    @ SCIP_STAGE_TRANSFORMING
    Definition: type_set.h:46
    @ SCIP_STATUS_OPTIMAL
    Definition: type_stat.h:43
    @ SCIP_STATUS_UNBOUNDED
    Definition: type_stat.h:45
    @ SCIP_STATUS_UNKNOWN
    Definition: type_stat.h:42
    @ SCIP_STATUS_INFORUNBD
    Definition: type_stat.h:46
    @ SCIP_STATUS_INFEASIBLE
    Definition: type_stat.h:44
    enum SYM_Symtype SYM_SYMTYPE
    Definition: type_symmetry.h:64
    @ SYM_CONSOPTYPE_EQ
    Definition: type_symmetry.h:81
    @ SYM_CONSOPTYPE_SUM
    Definition: type_symmetry.h:83
    @ SYM_CONSOPTYPE_SLACK
    Definition: type_symmetry.h:84
    @ SYM_SYMTYPE_SIGNPERM
    Definition: type_symmetry.h:62
    @ SYM_SYMTYPE_PERM
    Definition: type_symmetry.h:61
    @ SCIP_IMPLINTTYPE_NONE
    Definition: type_var.h:90
    @ SCIP_IMPLINTTYPE_WEAK
    Definition: type_var.h:91
    @ SCIP_VARTYPE_CONTINUOUS
    Definition: type_var.h:71
    @ SCIP_VARSTATUS_FIXED
    Definition: type_var.h:54
    @ 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