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