Scippy

    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-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file cons_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 binvary variable */
    3731 consdata->binvar = var;
    3732 }
    3733 }
    3734 else if ( SCIPvarGetStatus(consdata->binvar) == SCIP_VARSTATUS_NEGATED )
    3735 {
    3736 SCIP_VAR* var;
    3737
    3738 var = SCIPvarGetNegatedVar(consdata->binvar);
    3739 assert( var != NULL );
    3740
    3741 /* if the binary variable is the negated slack variable, we have 1 - s = 1 -> s = 0, i.e., the constraint is redundant */
    3742 if ( var == consdata->slackvar )
    3743 {
    3744 /* delete constraint */
    3745 assert( ! SCIPconsIsModifiable(cons) );
    3746 SCIP_CALL( SCIPdelCons(scip, cons) );
    3747 ++(*ndelconss);
    3748 *success = TRUE;
    3749 return SCIP_OKAY;
    3750 }
    3751 }
    3752
    3753 /* check whether slack variable is aggregated */
    3754 if ( SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_AGGREGATED || SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_NEGATED )
    3755 {
    3758 SCIP_VAR* var;
    3759
    3760 /* possibly get representation of slack variable by active variable */
    3761 var = consdata->slackvar;
    3763
    3764 SCIP_CALL( SCIPvarGetProbvarBound(&var, &bound, &boundtype) );
    3765 assert( var != consdata->slackvar );
    3766
    3767 /* we can replace the slack variable by the active variable if it is also a >= variable */
    3768 if ( var != consdata->binvar && boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisEQ(scip, bound, 0.0) )
    3769 {
    3770 assert( SCIPvarIsActive(var) );
    3771 SCIPdebugMsg(scip, "Slack variable <%s> is aggregated or negated and replaced by active variable <%s>.\n", SCIPvarGetName(consdata->slackvar), SCIPvarGetName(var) );
    3772
    3773 /* we need to update the events, locks, and captures */
    3774 assert( conshdlrdata->eventhdlrbound != NULL );
    3775 SCIP_CALL( SCIPdropVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, -1) );
    3776 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, NULL) );
    3777
    3778 SCIP_CALL( SCIPunlockVarCons(scip, consdata->slackvar, cons, FALSE, TRUE) );
    3779 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
    3780
    3781 SCIP_CALL( SCIPreleaseVar(scip, &consdata->slackvar) );
    3782 SCIP_CALL( SCIPcaptureVar(scip, var) );
    3783
    3784 /* change slack variable */
    3785 consdata->slackvar = var;
    3786 }
    3787 else if ( var == consdata->binvar )
    3788 {
    3789 /* check special case that aggregating variable is equal to the indicator variable */
    3790 assert( SCIPisEQ(scip, bound, 0.0) || SCIPisEQ(scip, bound, 1.0) );
    3791
    3792 /* if the lower bound is transformed to an upper bound, we have "y = 1 -> 1 - y = 0", i.e., the constraint is redundant */
    3793 if ( boundtype == SCIP_BOUNDTYPE_UPPER )
    3794 {
    3795 SCIPdebugMsg(scip, "Slack variable <%s> is aggregated to negated indicator variable <%s> -> constraint redundant.\n",
    3796 SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
    3797 assert( SCIPisEQ(scip, bound, 1.0) );
    3798
    3799 /* delete constraint */
    3800 assert( ! SCIPconsIsModifiable(cons) );
    3801 SCIP_CALL( SCIPdelCons(scip, cons) );
    3802 ++(*ndelconss);
    3803 *success = TRUE;
    3804 return SCIP_OKAY;
    3805 }
    3806 else
    3807 {
    3808 /* 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 */
    3809 SCIPdebugMsg(scip, "Slack variable <%s> is aggregated to the indicator variable <%s> -> fix indicator variable to 0.\n",
    3810 SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
    3811 assert( boundtype == SCIP_BOUNDTYPE_LOWER );
    3812 assert( SCIPisEQ(scip, bound, 0.0) );
    3813
    3814 SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
    3815 assert( ! infeasible );
    3816
    3817 if ( fixed )
    3818 ++(*nfixedvars);
    3819
    3820 SCIP_CALL( SCIPdelCons(scip, cons) );
    3821
    3822 ++(*ndelconss);
    3823 *success = TRUE;
    3824
    3825 return SCIP_OKAY;
    3826 }
    3827 }
    3828 }
    3829
    3830 /* Note that because of possible multi-aggregation we cannot simply remove the indicator
    3831 * constraint if the linear constraint is not active or disabled - see the note in @ref
    3832 * PREPROC. */
    3833
    3834 return SCIP_OKAY;
    3835}
    3836
    3837
    3838/** propagate indicator constraint */
    3839static
    3841 SCIP* scip, /**< SCIP pointer */
    3842 SCIP_CONS* cons, /**< constraint */
    3843 SCIP_CONSDATA* consdata, /**< constraint data */
    3844 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    3845 SCIP_Bool dualreductions, /**< should dual reductions be performed? */
    3846 SCIP_Bool addopposite, /**< add opposite inequalities if binary var = 0? */
    3847 SCIP_Bool* cutoff, /**< whether a cutoff happened */
    3848 int* nGen /**< number of domain changes */
    3849 )
    3850{
    3851 SCIP_Bool infeasible;
    3852 SCIP_Bool tightened;
    3853
    3854 assert( scip != NULL );
    3855 assert( cons != NULL );
    3856 assert( consdata != NULL );
    3857 assert( cutoff != NULL );
    3858 assert( nGen != NULL );
    3859
    3860 *cutoff = FALSE;
    3861 *nGen = 0;
    3862
    3863 /* if the linear constraint has not been generated, we do nothing */
    3864 if ( ! consdata->linconsactive )
    3865 return SCIP_OKAY;
    3866
    3867 assert( consdata->slackvar != NULL );
    3868 assert( consdata->binvar != NULL );
    3869 assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(consdata->slackvar), 0.0) );
    3870
    3871 /* increase age of constraint; age will be reset to zero, if a conflict or a propagation was found */
    3872 if ( ! SCIPinRepropagation(scip) )
    3873 {
    3874 SCIP_CALL( SCIPincConsAge(scip, cons) );
    3875 }
    3876
    3877 /* if both slackvar and binvar are fixed to be nonzero */
    3878 if ( consdata->nfixednonzero > 1 )
    3879 {
    3880 SCIPdebugMsg(scip, "The node is infeasible, both the slack variable and the binary variable are fixed to be nonzero.\n");
    3881 *cutoff = TRUE;
    3882
    3884 assert( SCIPvarGetLbLocal(consdata->binvar) > 0.5 );
    3885 assert( SCIPisPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) );
    3886
    3887 /* check if conflict analysis is turned on */
    3889 return SCIP_OKAY;
    3890
    3891 /* conflict analysis can only be applied in solving stage */
    3893
    3894 /* perform conflict analysis */
    3896
    3897 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->binvar) );
    3898 SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, NULL) );
    3900
    3901 return SCIP_OKAY;
    3902 }
    3903
    3904 /* if exactly one of the variables is fixed to be nonzero */
    3905 if ( consdata->nfixednonzero == 1 )
    3906 {
    3907 /* if binvar is fixed to be nonzero */
    3908 if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
    3909 {
    3910 assert( SCIPvarGetStatus(consdata->slackvar) != SCIP_VARSTATUS_MULTAGGR );
    3911
    3912 /* if slack variable is not already fixed to 0 */
    3913 if ( ! SCIPisZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
    3914 {
    3915 SCIPdebugMsg(scip, "Binary variable <%s> is fixed to be nonzero, fixing slack variable <%s> to 0.\n",
    3916 SCIPvarGetName(consdata->binvar), SCIPvarGetName(consdata->slackvar));
    3917
    3918 /* fix slack variable to 0 */
    3919 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->slackvar, 0.0, cons, 0, FALSE, &infeasible, &tightened) );
    3920 assert( ! infeasible );
    3921 if ( tightened )
    3922 ++(*nGen);
    3923 }
    3924 }
    3925
    3926 /* if slackvar is fixed to be nonzero */
    3927 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
    3928 {
    3929 /* if binary variable is not yet fixed to 0 */
    3930 if ( SCIPvarGetUbLocal(consdata->binvar) > 0.5 )
    3931 {
    3932 SCIPdebugMsg(scip, "Slack variable <%s> is fixed to be nonzero, fixing binary variable <%s> to 0.\n",
    3933 SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
    3934
    3935 /* fix binary variable to 0 */
    3936 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->binvar, 0.0, cons, 1, FALSE, &infeasible, &tightened) );
    3937 assert( ! infeasible );
    3938 if ( tightened )
    3939 ++(*nGen);
    3940 }
    3941 }
    3942
    3943 /* remove constraint if we are not in probing */
    3944 if ( ! SCIPinProbing(scip) )
    3945 {
    3946 /* delete constraint locally */
    3947 assert( ! SCIPconsIsModifiable(cons) );
    3949 }
    3950 }
    3951 else
    3952 {
    3953 /* if the binary variable is fixed to zero */
    3954 if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
    3955 {
    3956 if ( addopposite && consdata->linconsactive )
    3957 {
    3958 char name[SCIP_MAXSTRLEN];
    3959 SCIP_CONS* reversecons;
    3960 SCIP_VAR** linvars;
    3961 SCIP_Real* linvals;
    3962 SCIP_Bool allintegral = TRUE;
    3963 SCIP_VAR* slackvar;
    3964 SCIP_VAR** vars;
    3965 SCIP_Real* vals;
    3966 SCIP_Real lhs;
    3967 SCIP_Real rhs;
    3968 int nlinvars;
    3969 int nvars = 0;
    3970 int j;
    3971
    3972 /* determine lhs/rhs (first exchange lhs/rhs) */
    3973 lhs = SCIPgetRhsLinear(scip, consdata->lincons);
    3974 if ( SCIPisInfinity(scip, lhs) )
    3975 lhs = -SCIPinfinity(scip);
    3976 rhs = SCIPgetLhsLinear(scip, consdata->lincons);
    3977 if ( SCIPisInfinity(scip, -rhs) )
    3978 rhs = SCIPinfinity(scip);
    3979
    3980 assert( ! SCIPisInfinity(scip, lhs) );
    3981 assert( ! SCIPisInfinity(scip, -rhs) );
    3982
    3983 /* consider only finite lhs/rhs */
    3984 if ( ! SCIPisInfinity(scip, -lhs) || ! SCIPisInfinity(scip, rhs) )
    3985 {
    3986 /* ignore equations (cannot add opposite constraint) */
    3987 if ( ! SCIPisEQ(scip, lhs, rhs) )
    3988 {
    3989 assert( consdata->lincons != NULL );
    3990 nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    3991 linvars = SCIPgetVarsLinear(scip, consdata->lincons);
    3992 linvals = SCIPgetValsLinear(scip, consdata->lincons);
    3993 slackvar = consdata->slackvar;
    3994 assert( slackvar != NULL );
    3995
    3996 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlinvars) );
    3997 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlinvars) );
    3998
    3999 /* copy data and check whether the linear constraint is integral */
    4000 for (j = 0; j < nlinvars; ++j)
    4001 {
    4002 if ( linvars[j] != slackvar )
    4003 {
    4004 if (! SCIPvarIsIntegral(linvars[j]) || ! SCIPisIntegral(scip, linvals[j]) )
    4005 allintegral = FALSE;
    4006
    4007 vars[nvars] = linvars[j];
    4008 vals[nvars++] = linvals[j];
    4009 }
    4010 }
    4011 assert( nlinvars == nvars + 1 );
    4012
    4013 /* possibly adjust lhs/rhs */
    4014 if ( allintegral && ! SCIPisInfinity(scip, REALABS(lhs)) )
    4015 lhs += 1.0;
    4016
    4017 if ( allintegral && ! SCIPisInfinity(scip, REALABS(rhs)) )
    4018 rhs -= 1.0;
    4019
    4020 /* create reverse constraint */
    4021 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "reverse_%s", SCIPconsGetName(consdata->lincons));
    4022
    4023 /* constraint is initial, separated, not enforced, not checked, propagated, local, not modifiable, dynamic, removable */
    4024 SCIP_CALL( SCIPcreateConsLinear(scip, &reversecons, name, nvars, vars, vals, lhs, rhs,
    4026
    4027 SCIPdebugMsg(scip, "Binary variable <%s> fixed to 0. Adding opposite linear inequality.\n", SCIPvarGetName(consdata->binvar));
    4028 SCIPdebugPrintCons(scip, reversecons, NULL);
    4029
    4030 /* add constraint */
    4031 SCIP_CALL( SCIPaddCons(scip, reversecons) );
    4032 SCIP_CALL( SCIPreleaseCons(scip, &reversecons) );
    4033
    4034 SCIPfreeBufferArray(scip, &vals);
    4035 SCIPfreeBufferArray(scip, &vars);
    4036 }
    4037 }
    4038 }
    4039
    4040 /* remove constraint if we are not in probing */
    4041 if ( ! SCIPinProbing(scip) )
    4042 {
    4043 /* delete constraint locally */
    4044 assert( ! SCIPconsIsModifiable(cons) );
    4046 }
    4047 }
    4048 /* if the slack variable is fixed to zero */
    4049 else if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
    4050 {
    4051 /* perform dual reduction - if required */
    4052 if ( dualreductions )
    4053 {
    4054 SCIP_VAR* binvar;
    4055 SCIP_Real obj;
    4056
    4057 /* check objective of binary variable */
    4058 binvar = consdata->binvar;
    4059 obj = varGetObjDelta(binvar);
    4060
    4061 /* if obj = 0, we prefer setting the binary variable to 1 (if possible) */
    4062 if ( obj <= 0.0 )
    4063 {
    4064 /* In this case we would like to fix the binary variable to 1, if it is not locked up
    4065 * except by this indicator constraint. If more than one indicator constraint is
    4066 * affected, we have to hope that they are all fulfilled - in this case the last
    4067 * constraint will fix the binary variable to 1. */
    4068 if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
    4069 {
    4070 if ( SCIPvarGetUbLocal(binvar) > 0.5 )
    4071 {
    4072 SCIPdebugMsg(scip, "Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
    4073 SCIP_CALL( SCIPinferVarLbCons(scip, binvar, 1.0, cons, 2, FALSE, &infeasible, &tightened) );
    4074 assert( ! infeasible );
    4075 if ( tightened )
    4076 ++(*nGen);
    4077 /* Make sure that the other case does not occur, since we are not sure whether SCIPinferVarLbCons() directly changes the bounds. */
    4078 obj = -1.0;
    4079 }
    4080 }
    4081 }
    4082
    4083 if ( obj >= 0.0 )
    4084 {
    4085 /* In this case we would like to fix the binary variable to 0, if it is not locked down
    4086 * (should also have been performed by other dual reductions). */
    4088 {
    4089 if ( SCIPvarGetLbLocal(binvar) < 0.5 )
    4090 {
    4091 SCIPdebugMsg(scip, "Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
    4092 SCIP_CALL( SCIPinferVarUbCons(scip, binvar, 0.0, cons, 2, FALSE, &infeasible, &tightened) );
    4093 assert( ! infeasible );
    4094 if ( tightened )
    4095 ++(*nGen);
    4096 }
    4097 }
    4098 }
    4099 }
    4100
    4101 SCIPdebugMsg(scip, "Slack variable fixed to zero, delete redundant indicator constraint <%s>.\n", SCIPconsGetName(cons));
    4102
    4103 /* delete constraint */
    4104 assert( ! SCIPconsIsModifiable(cons) );
    4105
    4106 /* remove constraint if we are not in probing */
    4107 if ( ! SCIPinProbing(scip) )
    4108 {
    4110 }
    4111 }
    4112
    4113 /* Note that because of possible multi-aggregation we cannot simply remove the indicator
    4114 * constraint if the linear constraint is not active or disabled - see the note in @ref
    4115 * PREPROC and consPresolIndicator(). Moreover, it would drastically increase memory
    4116 * consumption, because the linear constraints have to be stored in each node. */
    4117 }
    4118
    4119 /* propagate maximal activity of linear constraint to upper bound of slack variable
    4120 *
    4121 * It is especially worth to tighten the upper bound if it is greater than maxcouplingvalue or sepacouplingvalue.
    4122 * But do not tighten it if slackvar is locked down by other constraints,
    4123 * or if it has a nonzero coefficient in the objective function.
    4124 *
    4125 * ax - c * s <= rhs -> s <= (maxActivity(ax) - rhs) / c;
    4126 */
    4127 if ( (SCIPvarGetUbLocal(consdata->slackvar) > conshdlrdata->maxcouplingvalue
    4128 || SCIPvarGetUbLocal(consdata->slackvar) > conshdlrdata->sepacouplingvalue)
    4129 && SCIPvarGetNLocksDownType(consdata->slackvar, SCIP_LOCKTYPE_MODEL) <= 1
    4130 && SCIPvarGetObj(consdata->slackvar) == 0.0 && SCIPconsIsActive(consdata->lincons) )
    4131 {
    4132 SCIP_VAR** linconsvars;
    4133 SCIP_Real* linconsvals;
    4134 SCIP_Real maxactivity = 0.0;
    4135 SCIP_Real coeffslack = SCIP_INVALID; /* -c */
    4136 SCIP_Real newub;
    4137 SCIP_Real rhs;
    4138 int nlinconsvars;
    4139 int j;
    4140
    4141 nlinconsvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    4142 linconsvars = SCIPgetVarsLinear(scip, consdata->lincons);
    4143 linconsvals = SCIPgetValsLinear(scip, consdata->lincons);
    4144
    4145 /* calculate maximal activity of linear constraint without slackvar */
    4146 for (j = 0; j < nlinconsvars; ++j)
    4147 {
    4148 SCIP_VAR* var;
    4149 SCIP_Real val;
    4151
    4152 val = linconsvals[j];
    4153 assert( ! SCIPisZero(scip, val) );
    4154
    4155 var = linconsvars[j];
    4156 assert( var != NULL );
    4157
    4158 /* store slackvar coefficient */
    4159 if ( var == consdata->slackvar )
    4160 {
    4161 coeffslack = val;
    4162 continue;
    4163 }
    4164
    4165 if ( val > 0.0 )
    4166 bound = SCIPvarGetUbLocal(var);
    4167 else
    4168 bound = SCIPvarGetLbLocal(var);
    4169
    4171 {
    4172 maxactivity = SCIPinfinity(scip);
    4173 break;
    4174 }
    4175 else
    4176 maxactivity += val * bound;
    4177 }
    4178
    4179 /* continue only if maxactivity is not infinity */
    4180 if ( !SCIPisInfinity(scip, maxactivity) && coeffslack != SCIP_INVALID && coeffslack < 0.0 ) /*lint !e777*/
    4181 {
    4182 rhs = SCIPgetRhsLinear(scip, consdata->lincons);
    4183
    4184 /* continue if rhs is not finite; happens, e.g., if variables are multiaggregated; we would need the minimal activity in this case */
    4185 if ( !SCIPisInfinity(scip, rhs) )
    4186 {
    4187 /* divide by coeff of slackvar */
    4188 newub = (maxactivity - rhs) / (-1.0 * coeffslack);
    4189 assert( !SCIPisInfinity(scip, newub) );
    4190
    4191 /* adjust bound if slackvar is (implicit) integer */
    4192 newub = SCIPadjustedVarUb(scip, consdata->slackvar, newub);
    4193
    4194 if ( SCIPisFeasLT(scip, newub, SCIPvarGetUbLocal(consdata->slackvar))
    4195 && newub > SCIPvarGetLbLocal(consdata->slackvar) )
    4196 {
    4197 SCIPdebugMsg(scip, "Adjusting upper bound of slack variable <%s> to %g for indicator constraint <%s>.\n",
    4198 SCIPvarGetName(consdata->slackvar), newub, SCIPconsGetName(cons));
    4199
    4200 /* propagate bound */
    4201 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->slackvar, newub, cons, 3, FALSE, &infeasible, &tightened) );
    4202 assert( !infeasible );
    4203 if ( tightened )
    4204 ++(*nGen);
    4205 }
    4206 }
    4207 }
    4208 }
    4209
    4210 /* reset constraint age counter */
    4211 if ( *nGen > 0 )
    4212 {
    4214 }
    4215
    4216 return SCIP_OKAY;
    4217}
    4218
    4219
    4220/** enforcement method that produces cuts if possible
    4221 *
    4222 * This is a variant of the enforcement method that generates cuts/constraints via the alternative
    4223 * LP, if possible.
    4224 */
    4225static
    4227 SCIP* scip, /**< SCIP pointer */
    4228 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4229 int nconss, /**< number of constraints */
    4230 SCIP_CONS** conss, /**< indicator constraints */
    4231 SCIP_SOL* sol, /**< solution to be enforced */
    4232 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
    4233 SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
    4234 SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
    4235 int* nGen /**< number of cuts generated */
    4236 )
    4237{
    4238 SCIP_CONSHDLRDATA* conshdlrdata;
    4239 SCIP_LPI* lp;
    4240 SCIP_Bool* S;
    4241 SCIP_Real value = 0.0;
    4242 SCIP_Bool error;
    4243 int size = 0;
    4244 int nCuts;
    4245 int j;
    4246
    4247 assert( scip != NULL );
    4248 assert( conshdlr != NULL );
    4249 assert( conss != NULL );
    4250 assert( cutoff != NULL );
    4251 assert( nGen != NULL );
    4252
    4253 SCIPdebugMsg(scip, "Enforcing via cuts ...\n");
    4254 *cutoff = FALSE;
    4255 *nGen = 0;
    4256
    4257 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4258 assert( conshdlrdata != NULL );
    4259 lp = conshdlrdata->altlp;
    4260 assert( lp != NULL );
    4261
    4262#ifndef NDEBUG
    4263 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    4264#endif
    4265
    4266 /* change coefficients of bounds in alternative LP */
    4267 if ( conshdlrdata->updatebounds )
    4268 SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
    4269
    4270 /* possibly update upper bound */
    4271 SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
    4272
    4273 /* scale first row if necessary */
    4274 SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
    4275
    4276 /* set objective function to current solution */
    4277 SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
    4278
    4279 SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
    4280
    4281 /* set up variables fixed to 1 */
    4282 for (j = 0; j < nconss; ++j)
    4283 {
    4284 SCIP_CONSDATA* consdata;
    4285
    4286 assert( conss[j] != NULL );
    4287 consdata = SCIPconsGetData(conss[j]);
    4288 assert( consdata != NULL );
    4289
    4290 assert( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
    4291 if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
    4292 {
    4293 ++size;
    4294 value += varGetObjDelta(consdata->binvar);
    4295 S[j] = TRUE;
    4296 }
    4297 else
    4298 S[j] = FALSE;
    4299 }
    4300
    4301 /* fix the variables in S */
    4302 SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
    4303
    4304 /* extend set S to a cover and generate cuts */
    4305 error = FALSE;
    4306 SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, genlogicor, nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
    4307 *nGen = nCuts;
    4308
    4309 /* return with an error if no cuts have been produced and and error occurred in extendToCover() */
    4310 if ( nCuts == 0 && error )
    4311 return SCIP_LPERROR;
    4312
    4313 SCIPdebugMsg(scip, "Generated %d IIS-cuts.\n", nCuts);
    4314
    4315 /* reset bounds */
    4316 SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
    4317
    4318#ifndef NDEBUG
    4319 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    4320#endif
    4321
    4323
    4324 return SCIP_OKAY;
    4325}
    4326
    4327
    4328/** enforcement method
    4329 *
    4330 * We check whether the current solution is feasible, i.e., if binvar = 1
    4331 * implies that slackvar = 0. If not, we branch as follows:
    4332 *
    4333 * In one branch we fix binvar = 1 and slackvar = 0. In the other branch
    4334 * we fix binvar = 0 and leave slackvar unchanged.
    4335 */
    4336static
    4338 SCIP* scip, /**< SCIP pointer */
    4339 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4340 int nconss, /**< number of constraints */
    4341 SCIP_CONS** conss, /**< indicator constraints */
    4342 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
    4343 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
    4344 SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
    4345 SCIP_RESULT* result /**< result */
    4346 )
    4347{
    4348 SCIP_CONSHDLRDATA* conshdlrdata;
    4349 SCIP_CONSDATA* consdata;
    4350 SCIP_NODE* node1;
    4351 SCIP_NODE* node2;
    4352 SCIP_VAR* slackvar;
    4353 SCIP_VAR* binvar;
    4355 SCIP_Real maxSlack = -1.0;
    4356 SCIP_Bool someLinconsNotActive = FALSE;
    4357 SCIP_Bool dualreductions;
    4358 int c;
    4359
    4360 assert( scip != NULL );
    4361 assert( conshdlr != NULL );
    4362 assert( conss != NULL );
    4363 assert( result != NULL );
    4364
    4365 *result = SCIP_FEASIBLE;
    4366
    4367 SCIPdebugMsg(scip, "Enforcing indicator constraints for <%s> ...\n", SCIPconshdlrGetName(conshdlr) );
    4368
    4369 /* get constraint handler data */
    4370 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4371 assert( conshdlrdata != NULL );
    4372
    4373 dualreductions = conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip);
    4374
    4375 /* check each constraint */
    4376 for (c = 0; c < nconss; ++c)
    4377 {
    4378 SCIP_Bool cutoff;
    4379 SCIP_Real valSlack;
    4380 int cnt;
    4381
    4382 assert( conss[c] != NULL );
    4383 consdata = SCIPconsGetData(conss[c]);
    4384 assert( consdata != NULL );
    4385 assert( consdata->lincons != NULL );
    4386
    4387 /* if the linear constraint has not been generated, we do nothing */
    4388 if ( ! consdata->linconsactive )
    4389 {
    4390 someLinconsNotActive = TRUE;
    4391 continue;
    4392 }
    4393
    4394 /* first perform propagation (it might happen that standard propagation is turned off) */
    4395 SCIP_CALL( propIndicator(scip, conss[c], consdata, conshdlrdata, dualreductions, conshdlrdata->addopposite, &cutoff, &cnt) );
    4396 if ( cutoff )
    4397 {
    4398 SCIPdebugMsg(scip, "Propagation in enforcing <%s> detected cutoff.\n", SCIPconsGetName(conss[c]));
    4399 *result = SCIP_CUTOFF;
    4400 return SCIP_OKAY;
    4401 }
    4402 if ( cnt > 0 )
    4403 {
    4404 SCIPdebugMsg(scip, "Propagation in enforcing <%s> reduced domains: %d.\n", SCIPconsGetName(conss[c]), cnt);
    4405 *result = SCIP_REDUCEDDOM;
    4406 return SCIP_OKAY;
    4407 }
    4408
    4409 /* check whether constraint is infeasible */
    4410 binvar = consdata->binvar;
    4411 valSlack = SCIPgetSolVal(scip, sol, consdata->slackvar);
    4412 assert( ! SCIPisFeasNegative(scip, valSlack) );
    4413 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, binvar)) && ! SCIPisFeasZero(scip, valSlack) )
    4414 {
    4415 /* binary variable is not fixed - otherwise we would not be infeasible */
    4416 assert( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 );
    4417
    4418 if ( valSlack > maxSlack )
    4419 {
    4420 maxSlack = valSlack;
    4421 branchCons = conss[c];
    4422#ifdef SCIP_OUTPUT
    4423 SCIPinfoMessage(scip, NULL, "Violated indicator constraint:\n");
    4424 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
    4425 SCIPinfoMessage(scip, NULL, ";\n");
    4426 SCIPinfoMessage(scip, NULL, "Corresponding linear constraint:\n");
    4427 SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
    4428 SCIPinfoMessage(scip, NULL, ";\n");
    4429#endif
    4430 }
    4431 }
    4432 }
    4433
    4434 /* if some constraint has a linear constraint that is not active, we need to check feasibility via the alternative polyhedron */
    4435 if ( (someLinconsNotActive || conshdlrdata->enforcecuts) && conshdlrdata->sepaalternativelp )
    4436 {
    4437 SCIP_Bool cutoff;
    4438 int ngen;
    4439
    4440 SCIP_CALL( enforceCuts(scip, conshdlr, nconss, conss, sol, enfosepatype, genlogicor, &cutoff, &ngen) );
    4441 if ( cutoff )
    4442 {
    4443 conshdlrdata->niiscutsgen += ngen;
    4444 *result = SCIP_CUTOFF;
    4445 return SCIP_OKAY;
    4446 }
    4447
    4448 if ( ngen > 0 )
    4449 {
    4450 conshdlrdata->niiscutsgen += ngen;
    4451 if ( genlogicor )
    4452 {
    4453 SCIPdebugMsg(scip, "Generated %d constraints.\n", ngen);
    4454 *result = SCIP_CONSADDED;
    4455 }
    4456 else
    4457 {
    4458 SCIPdebugMsg(scip, "Generated %d cuts.\n", ngen);
    4459 *result = SCIP_SEPARATED;
    4460 }
    4461 return SCIP_OKAY;
    4462 }
    4463 SCIPdebugMsg(scip, "Enforcing produced no cuts.\n");
    4464
    4465 assert( ! someLinconsNotActive || branchCons == NULL );
    4466 }
    4467
    4468 /* if all constraints are feasible */
    4469 if ( branchCons == NULL )
    4470 {
    4471 SCIPdebugMsg(scip, "All indicator constraints are feasible.\n");
    4472 return SCIP_OKAY;
    4473 }
    4474
    4475 /* skip branching if required */
    4476 if ( ! conshdlrdata->branchindicators )
    4477 {
    4478 *result = SCIP_INFEASIBLE;
    4479 return SCIP_OKAY;
    4480 }
    4481
    4482 /* otherwise create branches */
    4483 SCIPdebugMsg(scip, "Branching on constraint <%s> (slack value: %f).\n", SCIPconsGetName(branchCons), maxSlack);
    4484 consdata = SCIPconsGetData(branchCons);
    4485 assert( consdata != NULL );
    4486 binvar = consdata->binvar;
    4487 slackvar = consdata->slackvar;
    4488
    4489 /* node1: binvar = 1, slackvar = 0 */
    4490 SCIP_CALL( SCIPcreateChild(scip, &node1, 0.0, SCIPcalcChildEstimate(scip, binvar, 1.0) ) );
    4491
    4492 if ( SCIPvarGetLbLocal(binvar) < 0.5 )
    4493 {
    4494 SCIP_CALL( SCIPchgVarLbNode(scip, node1, binvar, 1.0) );
    4495 }
    4496
    4497 /* if slack-variable is multi-aggregated */
    4498 assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
    4499 if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(slackvar)) )
    4500 {
    4501 SCIP_CALL( SCIPchgVarUbNode(scip, node1, slackvar, 0.0) );
    4502 }
    4503
    4504 /* node2: binvar = 0, no restriction on slackvar */
    4505 SCIP_CALL( SCIPcreateChild(scip, &node2, 0.0, SCIPcalcChildEstimate(scip, binvar, 0.0) ) );
    4506
    4507 if ( SCIPvarGetUbLocal(binvar) > 0.5 )
    4508 {
    4509 SCIP_CALL( SCIPchgVarUbNode(scip, node2, binvar, 0.0) );
    4510 }
    4511
    4513 *result = SCIP_BRANCHED;
    4514
    4515 return SCIP_OKAY;
    4516}
    4517
    4518
    4519/** separate IIS-cuts via rounding
    4520 *
    4521 * @todo Check whether the cover produced at the end is a feasible solution.
    4522 */
    4523static
    4525 SCIP* scip, /**< SCIP pointer */
    4526 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4527 SCIP_SOL* sol, /**< solution to be separated */
    4528 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
    4529 int nconss, /**< number of constraints */
    4530 SCIP_CONS** conss, /**< indicator constraints */
    4531 int maxsepacuts, /**< maximal number of cuts to be generated */
    4532 SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
    4533 int* nGen /**< number of domain changes */
    4534 )
    4535{ /*lint --e{850}*/
    4536 SCIP_CONSHDLRDATA* conshdlrdata;
    4537 SCIP_LPI* lp;
    4538 int rounds;
    4539 SCIP_Real threshold;
    4540 SCIP_Bool* S;
    4541 SCIP_Bool error;
    4542 int oldsize = -1;
    4543 SCIPdebug( int nGenOld = *nGen; )
    4544
    4545 assert( scip != NULL );
    4546 assert( conshdlr != NULL );
    4547 assert( conss != NULL );
    4548 assert( cutoff != NULL );
    4549 assert( nGen != NULL );
    4550
    4551 if ( *nGen >= maxsepacuts )
    4552 return SCIP_OKAY;
    4553
    4554 *cutoff = FALSE;
    4555 rounds = 0;
    4556
    4557 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4558 assert( conshdlrdata != NULL );
    4559 lp = conshdlrdata->altlp;
    4560 assert( lp != NULL );
    4561
    4562 SCIPdebugMsg(scip, "Separating IIS-cuts by rounding ...\n");
    4563
    4564#ifndef NDEBUG
    4565 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    4566#endif
    4567
    4568 /* change coefficients of bounds in alternative LP */
    4569 if ( conshdlrdata->updatebounds )
    4570 {
    4571 /* update to local bounds */
    4572 SCIP_CALL( updateFirstRow(scip, conshdlrdata) );
    4573 }
    4574
    4575 /* possibly update upper bound */
    4576 SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
    4577
    4578 /* scale first row if necessary */
    4579 SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
    4580
    4581 /* set objective function to current solution */
    4582 SCIP_CALL( setAltLPObj(scip, lp, sol, nconss, conss) );
    4583
    4584 SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
    4585
    4586 /* loop through the possible thresholds */
    4587 for (threshold = conshdlrdata->roundingmaxthres;
    4588 rounds < conshdlrdata->maxroundingrounds && threshold >= conshdlrdata->roundingminthres && *nGen < maxsepacuts && ! (*cutoff);
    4589 threshold -= conshdlrdata->roundingoffset )
    4590 {
    4591 SCIP_Real value = 0.0;
    4592 int size = 0;
    4593 int nCuts = 0;
    4594 int j;
    4595#ifdef SCIP_DEBUG
    4596 int nvarsone = 0;
    4597 int nvarszero = 0;
    4598 int nvarsfrac = 0;
    4599#endif
    4600
    4601 SCIPdebugMsg(scip, "Threshold: %g.\n", threshold);
    4602
    4603 /* choose variables that have a value < current threshold value */
    4604 for (j = 0; j < nconss; ++j)
    4605 {
    4606 SCIP_CONSDATA* consdata;
    4607 SCIP_Real binvarval;
    4608 SCIP_VAR* binvarneg;
    4609
    4610 assert( conss[j] != NULL );
    4611 consdata = SCIPconsGetData(conss[j]);
    4612 assert( consdata != NULL );
    4613
    4614 binvarval = SCIPgetVarSol(scip, consdata->binvar);
    4615
    4616#ifdef SCIP_DEBUG
    4617 if ( SCIPisFeasEQ(scip, binvarval, 1.0) )
    4618 ++nvarsone;
    4619 else if ( SCIPisFeasZero(scip, binvarval) )
    4620 ++nvarszero;
    4621 else
    4622 ++nvarsfrac;
    4623#endif
    4624
    4625 /* check whether complementary (negated) variable is present as well */
    4626 binvarneg = SCIPvarGetNegatedVar(consdata->binvar);
    4627 assert( conshdlrdata->binvarhash != NULL );
    4628 if ( binvarneg != NULL && SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarneg) )
    4629 {
    4630 SCIP_Real binvarnegval = SCIPgetVarSol(scip, binvarneg);
    4631
    4632 /* take larger one */
    4633 if ( binvarval > binvarnegval )
    4634 S[j] = TRUE;
    4635 else
    4636 S[j] = FALSE;
    4637 continue;
    4638 }
    4639
    4640 /* check for threshold */
    4641 if ( SCIPisFeasLT(scip, SCIPgetVarSol(scip, consdata->binvar), threshold) )
    4642 {
    4643 S[j] = TRUE;
    4644 value += varGetObjDelta(consdata->binvar);
    4645 ++size;
    4646 }
    4647 else
    4648 S[j] = FALSE;
    4649 }
    4650
    4651 if ( size == nconss )
    4652 {
    4653 SCIPdebugMsg(scip, "All variables in the set. Continue ...\n");
    4654 continue;
    4655 }
    4656
    4657 /* skip computation if size has not changed (computation is likely the same) */
    4658 if ( size == oldsize )
    4659 {
    4660 SCIPdebugMsg(scip, "Skipping computation: size support has not changed.\n");
    4661 continue;
    4662 }
    4663 oldsize = size;
    4664
    4665#ifdef SCIP_DEBUG
    4666 SCIPdebugMsg(scip, " Vars with value 1: %d 0: %d and fractional: %d.\n", nvarsone, nvarszero, nvarsfrac);
    4667#endif
    4668
    4669 /* fix the variables in S */
    4670 SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
    4671
    4672 /* extend set S to a cover and generate cuts */
    4673 SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, conshdlrdata->genlogicor,
    4674 nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
    4675
    4676 /* we ignore errors in extendToCover */
    4677 if ( nCuts > 0 )
    4678 {
    4679 *nGen += nCuts;
    4680 ++rounds;
    4681 }
    4682 else
    4683 {
    4684 /* possibly update upper bound */
    4685 SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
    4686 }
    4687
    4688 /* reset bounds */
    4689 SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
    4690 }
    4691 SCIPdebug( SCIPdebugMsg(scip, "Generated %d IISs.\n", *nGen - nGenOld); )
    4692
    4693#ifndef NDEBUG
    4694 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    4695#endif
    4696
    4698
    4699 return SCIP_OKAY;
    4700}
    4701
    4702
    4703
    4704/** separate cuts based on perspective formulation
    4705 *
    4706 * Hijazi, Bonami, and Ouorou (2014) introduced the following cuts: We consider an indicator constraint
    4707 * \f[
    4708 * y = 1 \rightarrow \alpha^T x \leq \beta
    4709 * \f]
    4710 * and assume finite bounds \f$\ell \leq x \leq u\f$. Then for \f$I \subseteq \{1, \dots, n\}\f$ define
    4711 * \f[
    4712 * \Sigma(I,x,y) = \sum_{i \notin I} \alpha_i x_i +
    4713 * y \Big(\sum_{i \in I, \alpha_i < 0} \alpha_i u_i + \sum_{i \in I, \alpha_i > 0} \alpha_i \ell_i +
    4714 * \sum_{i \notin I, \alpha_i < 0} \alpha_i \ell_i + \sum_{i \notin I, \alpha_i > 0} \alpha_i u_i - \beta\Big).
    4715 * \f]
    4716 * Then the cuts
    4717 * \f[
    4718 * \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
    4719 * \f]
    4720 * are valid for the disjunction
    4721 * \f[
    4722 * \{y = 0,\; \ell \leq x \leq u\} \cup \{y = 1,\; \ell \leq x \leq u,\; \alpha^T x \leq \beta\}.
    4723 * \f]
    4724 * 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
    4725 * \f[
    4726 * y^*(\alpha_i\, u_i\, [\alpha_i < 0] + \alpha_i\, \ell_i\, [\alpha_i > 0]) >
    4727 * \alpha_i x_i^* + y^* )\alpha_i \ell_i [\alpha_i < 0] + \alpha_i u_i [\alpha_i > 0]),
    4728 * \f]
    4729 * where \f$[C] = 1\f$ if condition \f$C\f$ is satisfied, otherwise it is 0.
    4730 * If the above inequality holds, \f$i\f$ is included in \f$I\f$, otherwise not.
    4731 */
    4732static
    4734 SCIP* scip, /**< SCIP pointer */
    4735 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4736 SCIP_SOL* sol, /**< solution to be separated */
    4737 int nconss, /**< number of constraints */
    4738 SCIP_CONS** conss, /**< indicator constraints */
    4739 int maxsepacuts, /**< maximal number of cuts to be generated */
    4740 int* nGen /**< number of generated cuts */
    4741 )
    4742{ /*lint --e{850}*/
    4743 SCIP_CONSHDLRDATA* conshdlrdata;
    4744 SCIP_VAR** cutvars;
    4745 SCIP_Real* cutvals;
    4746 int nvars;
    4747 int c;
    4748
    4749 assert( scip != NULL );
    4750 assert( conshdlr != NULL );
    4751 assert( conss != NULL );
    4752 assert( nGen != NULL );
    4753
    4754 if ( *nGen >= maxsepacuts )
    4755 return SCIP_OKAY;
    4756
    4757 nvars = SCIPgetNVars(scip);
    4758 SCIP_CALL( SCIPallocBufferArray(scip, &cutvars, nvars+1) );
    4759 SCIP_CALL( SCIPallocBufferArray(scip, &cutvals, nvars+1) );
    4760
    4761 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4762 assert( conshdlrdata != NULL );
    4763
    4764 /* loop through constraints */
    4765 for (c = 0; c < nconss; ++c)
    4766 {
    4767 SCIP_CONSDATA* consdata;
    4768 SCIP_CONS* lincons;
    4769 SCIP_VAR* slackvar;
    4770 SCIP_VAR* binvar;
    4771 SCIP_Real binval;
    4772
    4773 assert( conss[c] != NULL );
    4774 consdata = SCIPconsGetData(conss[c]);
    4775 assert( consdata != NULL );
    4776 slackvar = consdata->slackvar;
    4777
    4778 lincons = consdata->lincons;
    4779 assert( lincons != NULL );
    4780
    4781 binvar = consdata->binvar;
    4782 assert( binvar != NULL );
    4783 binval = SCIPgetSolVal(scip, sol, binvar);
    4784
    4785 if ( SCIPconsIsActive(lincons) )
    4786 {
    4787 SCIP_VAR** linvars;
    4788 SCIP_Real* linvals;
    4789 SCIP_Real linrhs;
    4790 SCIP_Bool finitebound = TRUE;
    4791 SCIP_Real cutrhs = 0.0;
    4792 SCIP_Real cutval;
    4793 SCIP_Real signfactor = 1.0;
    4794 SCIP_Real ypart;
    4795 SCIP_Bool islocal = FALSE;
    4796 int nlinvars;
    4797 int cnt = 0;
    4798 int j;
    4799
    4800 linvars = SCIPgetVarsLinear(scip, lincons);
    4801 linvals = SCIPgetValsLinear(scip, lincons);
    4802 nlinvars = SCIPgetNVarsLinear(scip, lincons);
    4803
    4804 linrhs = SCIPgetRhsLinear(scip, lincons);
    4805 if ( SCIPisInfinity(scip, linrhs) )
    4806 {
    4807 if ( ! SCIPisInfinity(scip, SCIPgetLhsLinear(scip, lincons)) )
    4808 {
    4809 linrhs = -SCIPgetLhsLinear(scip, lincons);
    4810 signfactor = -1.0;
    4811 }
    4812 else
    4813 continue;
    4814 }
    4815 ypart = -linrhs;
    4816 cutval = binval * ypart;
    4817
    4818 for (j = 0; j < nlinvars; ++j)
    4819 {
    4820 SCIP_Real linval;
    4821 SCIP_Real lb;
    4822 SCIP_Real ub;
    4823 SCIP_Real din = 0.0;
    4824 SCIP_Real dout = 0.0;
    4825 SCIP_Real xpart;
    4826 SCIP_Real xval;
    4827
    4828 if ( linvars[j] == slackvar )
    4829 continue;
    4830
    4831 if ( conshdlrdata->sepapersplocal )
    4832 {
    4833 lb = SCIPvarGetLbLocal(linvars[j]);
    4834 ub = SCIPvarGetUbLocal(linvars[j]);
    4835
    4836 if ( lb > SCIPvarGetLbGlobal(linvars[j]) )
    4837 islocal = TRUE;
    4838 if ( ub < SCIPvarGetUbGlobal(linvars[j]) )
    4839 islocal = TRUE;
    4840 }
    4841 else
    4842 {
    4843 lb = SCIPvarGetLbGlobal(linvars[j]);
    4844 ub = SCIPvarGetUbGlobal(linvars[j]);
    4845 }
    4846
    4847 /* skip cases with unbounded variables */
    4848 if ( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
    4849 {
    4850 finitebound = FALSE;
    4851 break;
    4852 }
    4853
    4854 /* compute rest parts for i in the set (din) or not in the set (dout) */
    4855 linval = signfactor * linvals[j];
    4856 if ( SCIPisNegative(scip, linval) )
    4857 {
    4858 din += linval * ub;
    4859 dout += linval * lb;
    4860 }
    4861 else if ( SCIPisPositive(scip, linval) )
    4862 {
    4863 din += linval * lb;
    4864 dout += linval * ub;
    4865 }
    4866
    4867 xval = SCIPgetSolVal(scip, sol, linvars[j]);
    4868 xpart = linval * xval;
    4869
    4870 /* if din > dout, we want to include i in the set */
    4871 if ( SCIPisGT(scip, binval * din, binval * dout + xpart) )
    4872 {
    4873 ypart += din;
    4874 cutval += binval * din;
    4875 }
    4876 else
    4877 {
    4878 /* otherwise i is not in the set */
    4879 ypart += dout;
    4880
    4881 cutrhs += dout;
    4882 cutval += binval * dout + xpart;
    4883
    4884 cutvars[cnt] = linvars[j];
    4885 cutvals[cnt++] = linval;
    4886 }
    4887 }
    4888
    4889 if ( ! finitebound )
    4890 continue;
    4891
    4892 if ( SCIPisEfficacious(scip, cutval - cutrhs) )
    4893 {
    4894 SCIP_ROW* row;
    4895 SCIP_Bool infeasible;
    4896 char name[50];
    4897
    4898 /* add y-variable */
    4899 cutvars[cnt] = binvar;
    4900 cutvals[cnt] = ypart;
    4901 ++cnt;
    4902
    4903 SCIPdebugMsg(scip, "Found cut of lhs value %f > %f.\n", cutval, cutrhs);
    4904 (void) SCIPsnprintf(name, 50, "persp%d", conshdlrdata->nperspcutsgen + *nGen);
    4905 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), cutrhs, islocal, FALSE, conshdlrdata->removable) );
    4906 SCIP_CALL( SCIPaddVarsToRow(scip, row, cnt, cutvars, cutvals) );
    4907#ifdef SCIP_OUTPUT
    4908 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
    4909#endif
    4910 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
    4911 assert( ! infeasible );
    4912 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    4913 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
    4914 ++(*nGen);
    4915 }
    4916 }
    4917 if ( *nGen >= maxsepacuts )
    4918 break;
    4919 }
    4920
    4921 SCIPfreeBufferArray(scip, &cutvals);
    4922 SCIPfreeBufferArray(scip, &cutvars);
    4923
    4924 return SCIP_OKAY;
    4925}
    4926
    4927
    4928/** separation method
    4929 *
    4930 * We first check whether coupling inequalities can be separated (if required). If not enough of
    4931 * these could be generated, we check whether IIS inequalities can be separated.
    4932 */
    4933static
    4935 SCIP* scip, /**< SCIP pointer */
    4936 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4937 int nconss, /**< number of constraints */
    4938 int nusefulconss, /**< number of useful constraints */
    4939 SCIP_CONS** conss, /**< indicator constraints */
    4940 SCIP_SOL* sol, /**< solution to be separated */
    4941 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
    4942 SCIP_RESULT* result /**< result */
    4943 )
    4944{
    4945 SCIP_CONSHDLRDATA* conshdlrdata;
    4946 int maxsepacuts;
    4947 int ncuts;
    4948
    4949 assert( scip != NULL );
    4950 assert( conshdlr != NULL );
    4951 assert( conss != NULL );
    4952 assert( result != NULL );
    4953
    4954 *result = SCIP_DIDNOTRUN;
    4955
    4956 if ( nconss == 0 )
    4957 return SCIP_OKAY;
    4958
    4959 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4960 assert( conshdlrdata != NULL );
    4961 ncuts = 0;
    4962
    4963 /* get the maximal number of cuts allowed in a separation round */
    4964 if ( SCIPgetDepth(scip) == 0 )
    4965 maxsepacuts = conshdlrdata->maxsepacutsroot;
    4966 else
    4967 maxsepacuts = conshdlrdata->maxsepacuts;
    4968
    4969 /* first separate coupling inequalities (if required) */
    4970 if ( conshdlrdata->sepacouplingcuts )
    4971 {
    4972 int c;
    4973
    4974 *result = SCIP_DIDNOTFIND;
    4975
    4976 /* check each constraint */
    4977 for (c = 0; c < nusefulconss && ncuts < maxsepacuts; ++c)
    4978 {
    4979 SCIP_CONSDATA* consdata;
    4980 SCIP_Bool islocal;
    4981 SCIP_Real ub;
    4982
    4983 assert( conss != NULL );
    4984 assert( conss[c] != NULL );
    4985 consdata = SCIPconsGetData(conss[c]);
    4986 assert( consdata != NULL );
    4987 assert( consdata->slackvar != NULL );
    4988 assert( consdata->binvar != NULL );
    4989
    4990 /* get upper bound for slack variable in linear constraint */
    4991 islocal = FALSE;
    4992 if ( conshdlrdata->sepacouplinglocal )
    4993 {
    4994 ub = SCIPvarGetUbLocal(consdata->slackvar);
    4995 if ( ub < SCIPvarGetUbGlobal(consdata->slackvar) )
    4996 islocal = TRUE;
    4997 }
    4998 else
    4999 ub = SCIPvarGetUbGlobal(consdata->slackvar);
    5000 assert( ! SCIPisFeasNegative(scip, ub) );
    5001
    5002 /* only use coefficients that are not too large */
    5003 if ( ub <= conshdlrdata->sepacouplingvalue )
    5004 {
    5005 SCIP_Real activity;
    5006
    5007 activity = SCIPgetSolVal(scip, sol, consdata->slackvar) + ub * SCIPgetSolVal(scip, sol, consdata->binvar) - ub;
    5008 if ( SCIPisEfficacious(scip, activity) )
    5009 {
    5010 SCIP_ROW* row;
    5011 SCIP_Bool infeasible;
    5012#ifndef NDEBUG
    5013 char name[50];
    5014
    5015 (void) SCIPsnprintf(name, 50, "couple%d", c);
    5016 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
    5017#else
    5018 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], "", -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
    5019#endif
    5021
    5022 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
    5023 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
    5025
    5026 SCIPdebugMsg(scip, "Separated coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
    5027#ifdef SCIP_OUTPUT
    5028 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
    5029#endif
    5030 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
    5031 assert( ! infeasible );
    5032 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    5033
    5034 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
    5035 *result = SCIP_SEPARATED;
    5036
    5037 ++ncuts;
    5038 }
    5039 }
    5040 }
    5041 SCIPdebugMsg(scip, "Number of separated coupling inequalities: %d.\n", ncuts);
    5042 }
    5043
    5044 /* separate cuts from the alternative lp (if required) */
    5045 if ( conshdlrdata->sepaalternativelp && ncuts < SEPAALTTHRESHOLD )
    5046 {
    5047 SCIP_Bool cutoff;
    5048 int noldcuts;
    5049
    5050 SCIPdebugMsg(scip, "Separating inequalities for indicator constraints.\n");
    5051
    5052 noldcuts = ncuts;
    5053 if ( *result == SCIP_DIDNOTRUN )
    5054 *result = SCIP_DIDNOTFIND;
    5055
    5056 /* start separation */
    5057 SCIP_CALL( separateIISRounding(scip, conshdlr, sol, enfosepatype, nconss, conss, maxsepacuts, &cutoff, &ncuts) );
    5058 SCIPdebugMsg(scip, "Separated %d cuts from indicator constraints.\n", ncuts - noldcuts);
    5059
    5060 if ( cutoff )
    5061 *result = SCIP_CUTOFF;
    5062 else if ( ncuts > noldcuts )
    5063 {
    5064 conshdlrdata->niiscutsgen += ncuts;
    5065
    5066 /* possibly overwrite result from separation above */
    5067 if ( conshdlrdata->genlogicor )
    5068 *result = SCIP_CONSADDED;
    5069 else
    5070 *result = SCIP_SEPARATED;
    5071 }
    5072 }
    5073
    5074 /* separate cuts based on perspective formulation */
    5075 if ( conshdlrdata->sepaperspective && ncuts < SEPAALTTHRESHOLD )
    5076 {
    5077 int noldcuts;
    5078
    5079 SCIPdebugMsg(scip, "Separating inequalities based on perspective formulation.\n");
    5080
    5081 noldcuts = ncuts;
    5082 if ( *result == SCIP_DIDNOTRUN )
    5083 *result = SCIP_DIDNOTFIND;
    5084
    5085 /* start separation */
    5086 SCIP_CALL( separatePerspective(scip, conshdlr, sol, nconss, conss, maxsepacuts, &ncuts) );
    5087 SCIPdebugMsg(scip, "Separated %d cuts from perspective formulation.\n", ncuts - noldcuts);
    5088
    5089 if ( ncuts > noldcuts )
    5090 {
    5091 conshdlrdata->nperspcutsgen += ncuts;
    5092
    5093 /* possibly overwrite result from separation above */
    5094 *result = SCIP_SEPARATED;
    5095 }
    5096 }
    5097
    5098 return SCIP_OKAY;
    5099}
    5100
    5101
    5102/** initializes the constraint handler data */
    5103static
    5105 SCIP* scip, /**< SCIP pointer */
    5106 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
    5107 )
    5108{
    5109 assert( conshdlrdata != NULL );
    5110
    5111 conshdlrdata->linconsevents = FALSE;
    5112 conshdlrdata->linconsboundschanged = TRUE;
    5113 conshdlrdata->boundhaschanged = TRUE;
    5114 conshdlrdata->removable = TRUE;
    5115 conshdlrdata->scaled = FALSE;
    5116 conshdlrdata->altlp = NULL;
    5117 conshdlrdata->nrows = 0;
    5118 conshdlrdata->varhash = NULL;
    5119 conshdlrdata->slackhash = NULL;
    5120 conshdlrdata->lbhash = NULL;
    5121 conshdlrdata->ubhash = NULL;
    5122 conshdlrdata->nlbbounds = 0;
    5123 conshdlrdata->nubbounds = 0;
    5124 conshdlrdata->nslackvars = 0;
    5125 conshdlrdata->objcutindex = -1;
    5126 conshdlrdata->objupperbound = SCIPinfinity(scip);
    5127 conshdlrdata->objaltlpbound = SCIPinfinity(scip);
    5128 conshdlrdata->roundingminthres = 0.1;
    5129 conshdlrdata->roundingmaxthres = 0.6;
    5130 conshdlrdata->maxroundingrounds = MAXROUNDINGROUNDS;
    5131 conshdlrdata->roundingoffset = 0.1;
    5132 conshdlrdata->addedcouplingcons = FALSE;
    5133 conshdlrdata->ninitconss = 0;
    5134 conshdlrdata->nbinvarszero = 0;
    5135 conshdlrdata->performedrestart = FALSE;
    5136 conshdlrdata->objindicatoronly = FALSE;
    5137 conshdlrdata->objothervarsonly = FALSE;
    5138 conshdlrdata->minabsobj = 0.0;
    5139 conshdlrdata->normtype = 'e';
    5140 conshdlrdata->niiscutsgen = 0;
    5141 conshdlrdata->nperspcutsgen = 0;
    5142}
    5143
    5144
    5145/* ---------------------------- upgrading methods -----------------------------------*/
    5146
    5147/** tries to upgrade a linear constraint into an indicator constraint
    5148 *
    5149 * 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
    5150 * it to an indicator constraint if for the residual value \f$a^T x \geq \gamma\f$, we have \f$\alpha + \gamma \geq
    5151 * \beta\f$: in this case, the constraint is always satisfied if \f$y = 1\f$.
    5152 *
    5153 * 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
    5154 * upgrade it to an indicator constraint if for the residual value \f$a^T x \leq \gamma\f$, we have \f$\alpha + \gamma
    5155 * \leq \beta\f$.
    5156 */
    5157static
    5158SCIP_DECL_LINCONSUPGD(linconsUpgdIndicator)
    5159{ /*lint --e{715}*/
    5160 SCIP_CONSHDLRDATA* conshdlrdata;
    5161 SCIP_CONSHDLR* conshdlr;
    5162 SCIP_Real minactivity = 0.0;
    5163 SCIP_Real maxactivity = 0.0;
    5164 SCIP_Real maxabsval = -1.0;
    5165 SCIP_Real secabsval = -1.0;
    5166 int maxabsvalidx = -1;
    5167 int j;
    5168
    5169 assert( scip != NULL );
    5170 assert( upgdcons != NULL );
    5171 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0 );
    5172 assert( ! SCIPconsIsModifiable(cons) );
    5173
    5174 /* do not upgrade if there are at most 2 variables (2 variables should be upgraded to a varbound constraint) */
    5175 if ( nvars <= 2 )
    5176 return SCIP_OKAY;
    5177
    5178 /* cannot currently ranged constraints, since we can only return one constraint (and we would need one for each side each) */
    5179 if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
    5180 return SCIP_OKAY;
    5181
    5182 /* check whether upgrading is turned on */
    5183 conshdlr = SCIPfindConshdlr(scip, "indicator");
    5184 assert( conshdlr != NULL );
    5185 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5186 assert( conshdlrdata != NULL );
    5187
    5188 if ( ! conshdlrdata->upgradelinear )
    5189 return SCIP_OKAY;
    5190
    5191 /* calculate activities */
    5192 for (j = 0; j < nvars; ++j)
    5193 {
    5194 SCIP_VAR* var;
    5195 SCIP_Real val;
    5196 SCIP_Real lb;
    5197 SCIP_Real ub;
    5198
    5199 val = vals[j];
    5200 assert( ! SCIPisZero(scip, val) );
    5201
    5202 var = vars[j];
    5203 assert( var != NULL );
    5204
    5205 /* store maximal (and second to largest) value of coefficients */
    5206 if ( SCIPisGE(scip, REALABS(val), maxabsval) )
    5207 {
    5208 secabsval = maxabsval;
    5209 maxabsval = REALABS(val);
    5210 maxabsvalidx = j;
    5211 }
    5212
    5213 if ( ! SCIPvarIsBinary(var) )
    5214 {
    5215 if ( val > 0.0 )
    5216 {
    5217 lb = SCIPvarGetLbGlobal(var);
    5218 ub = SCIPvarGetUbGlobal(var);
    5219 }
    5220 else
    5221 {
    5222 ub = SCIPvarGetLbGlobal(var);
    5223 lb = SCIPvarGetUbGlobal(var);
    5224 }
    5225
    5226 /* compute minimal activity */
    5227 if ( SCIPisInfinity(scip, -lb) )
    5228 minactivity = -SCIPinfinity(scip);
    5229 else
    5230 {
    5231 if ( ! SCIPisInfinity(scip, -minactivity) )
    5232 minactivity += val * lb;
    5233 }
    5234
    5235 /* compute maximal activity */
    5236 if ( SCIPisInfinity(scip, ub) )
    5237 maxactivity = SCIPinfinity(scip);
    5238 else
    5239 {
    5240 if ( ! SCIPisInfinity(scip, maxactivity) )
    5241 maxactivity += val * ub;
    5242 }
    5243 }
    5244 }
    5245 assert( maxabsval >= 0.0 );
    5246 assert( 0 <= maxabsvalidx && maxabsvalidx < nvars );
    5247
    5248 /* exit if largest coefficient does not belong to binary variable */
    5249 if ( ! SCIPvarIsBinary(vars[maxabsvalidx]) )
    5250 return SCIP_OKAY;
    5251
    5252 /* exit if the second largest coefficient is as large as largest */
    5253 if ( SCIPisEQ(scip, secabsval, maxabsval) )
    5254 return SCIP_OKAY;
    5255
    5256 /* cannot upgrade if all activities are infinity */
    5257 if ( SCIPisInfinity(scip, -minactivity) && SCIPisInfinity(scip, maxactivity) )
    5258 return SCIP_OKAY;
    5259
    5260 /* check each variable as indicator variable */
    5261 for (j = 0; j < nvars; ++j)
    5262 {
    5263 SCIP_VAR** indconsvars;
    5264 SCIP_Real* indconsvals;
    5265 SCIP_Bool upgdlhs = FALSE;
    5266 SCIP_Bool upgdrhs = FALSE;
    5267 SCIP_Bool indneglhs = FALSE;
    5268 SCIP_Bool indnegrhs = FALSE;
    5269 SCIP_VAR* indvar;
    5270 SCIP_Real indval;
    5271 int l;
    5272
    5273 indvar = vars[j];
    5274 indval = vals[j];
    5275 assert( ! SCIPisZero(scip, indval) );
    5276
    5277 if ( ! SCIPvarIsBinary(indvar) )
    5278 continue;
    5279
    5280 /* check for upgrading of lhs */
    5281 if ( ! SCIPisInfinity(scip, -minactivity) && ! SCIPisInfinity(scip, -lhs) )
    5282 {
    5283 /* upgrading is possible with binary variable */
    5284 if ( SCIPisGE(scip, minactivity, lhs) )
    5285 upgdlhs = TRUE;
    5286
    5287 /* upgrading is possible with negated binary variable */
    5288 if ( SCIPisGE(scip, minactivity + indval, lhs) )
    5289 {
    5290 upgdlhs = TRUE;
    5291 indneglhs = TRUE;
    5292 }
    5293 }
    5294
    5295 /* check for upgrading of rhs */
    5296 if ( ! SCIPisInfinity(scip, maxactivity) && ! SCIPisInfinity(scip, rhs) )
    5297 {
    5298 /* upgrading is possible with binary variable */
    5299 if ( SCIPisLE(scip, maxactivity, rhs) )
    5300 upgdrhs = TRUE;
    5301
    5302 /* upgrading is possible with negated binary variable */
    5303 if ( SCIPisLE(scip, maxactivity + indval, rhs) )
    5304 {
    5305 upgdrhs = TRUE;
    5306 indnegrhs = TRUE;
    5307 }
    5308 }
    5309
    5310 /* upgrade constraint */
    5311 if ( upgdlhs || upgdrhs )
    5312 {
    5313 SCIP_VAR* indvar2;
    5314 SCIP_Real bnd;
    5315 int cnt = 0;
    5316
    5317 assert( ! upgdlhs || ! upgdrhs ); /* cannot treat ranged rows */
    5318 SCIPdebugMsg(scip, "upgrading constraint <%s> to an indicator constraint.\n", SCIPconsGetName(cons));
    5319
    5320 SCIP_CALL( SCIPallocBufferArray(scip, &indconsvars, nvars - 1) );
    5321 SCIP_CALL( SCIPallocBufferArray(scip, &indconsvals, nvars - 1) );
    5322
    5323 /* create constraint */
    5324 for (l = 0; l < nvars; ++l)
    5325 {
    5326 if ( vars[l] == indvar )
    5327 continue;
    5328 indconsvars[cnt] = vars[l];
    5329 if ( upgdlhs )
    5330 indconsvals[cnt] = -vals[l];
    5331 else
    5332 indconsvals[cnt] = vals[l];
    5333 ++cnt;
    5334 }
    5335
    5336 if ( indneglhs || indnegrhs )
    5337 {
    5338 SCIP_CALL( SCIPgetNegatedVar(scip, indvar, &indvar2) );
    5339 }
    5340 else
    5341 indvar2 = indvar;
    5342
    5343 if ( upgdlhs )
    5344 {
    5345 bnd = -lhs;
    5346 if ( ! indneglhs )
    5347 bnd -= indval;
    5348 SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
    5351 }
    5352 else
    5353 {
    5354 bnd = rhs;
    5355 if ( ! indnegrhs )
    5356 bnd -= indval;
    5357 SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
    5360 }
    5361
    5362#ifdef SCIP_DEBUG
    5363 SCIPinfoMessage(scip, NULL, "upgrade: \n");
    5364 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
    5365 SCIPinfoMessage(scip, NULL, "\n");
    5366 SCIP_CALL( SCIPprintCons(scip, *upgdcons, NULL) );
    5367 SCIPinfoMessage(scip, NULL, "\n");
    5369 SCIPinfoMessage(scip, NULL, " (minact: %f, maxact: %f)\n", minactivity, maxactivity);
    5370#endif
    5371
    5372 SCIPfreeBufferArray(scip, &indconsvars);
    5373 SCIPfreeBufferArray(scip, &indconsvals);
    5374
    5375 return SCIP_OKAY;
    5376 }
    5377 }
    5378
    5379 return SCIP_OKAY;
    5380}
    5381
    5382
    5383/* ---------------------------- constraint handler callback methods ----------------------*/
    5384
    5385/** copy method for constraint handler plugins (called when SCIP copies plugins) */
    5386static
    5387SCIP_DECL_CONSHDLRCOPY(conshdlrCopyIndicator)
    5388{ /*lint --e{715}*/
    5389 assert( scip != NULL );
    5390 assert( conshdlr != NULL );
    5391 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    5392 assert( valid != NULL );
    5393
    5394 /* call inclusion method of constraint handler */
    5396
    5397 *valid = TRUE;
    5398
    5399 return SCIP_OKAY;
    5400}
    5401
    5402
    5403/** initialization method of constraint handler (called after problem was transformed) */
    5404static
    5405SCIP_DECL_CONSINIT(consInitIndicator)
    5406{ /*lint --e{715}*/
    5407 SCIP_CONSHDLRDATA* conshdlrdata;
    5408
    5409 assert( scip != NULL );
    5410 assert( conshdlr != NULL );
    5411 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    5412
    5413 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5414 assert( conshdlrdata != NULL );
    5415
    5416 initConshdlrData(scip, conshdlrdata);
    5417
    5418 /* find trysol heuristic */
    5419 if ( conshdlrdata->trysolutions && conshdlrdata->heurtrysol == NULL )
    5420 {
    5421 conshdlrdata->heurtrysol = SCIPfindHeur(scip, "trysol");
    5422 }
    5423
    5424 return SCIP_OKAY;
    5425}
    5426
    5427
    5428/** deinitialization method of constraint handler (called before transformed problem is freed) */
    5429static
    5430SCIP_DECL_CONSEXIT(consExitIndicator)
    5431{ /*lint --e{715}*/
    5432 SCIP_CONSHDLRDATA* conshdlrdata;
    5433 SCIP_CONSDATA* consdata;
    5434 int i;
    5435 int j;
    5436
    5437 assert( scip != NULL );
    5438 assert( conshdlr != NULL );
    5439 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    5440
    5441 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5442
    5443 if ( conshdlrdata->binvarhash != NULL )
    5444 SCIPhashmapFree(&conshdlrdata->binvarhash);
    5445
    5446 if ( conshdlrdata->binslackvarhash != NULL )
    5447 SCIPhashmapFree(&conshdlrdata->binslackvarhash);
    5448
    5449 /* drop bound change events on variables of linear constraints */
    5450 for (i = 0; i < nconss; i++)
    5451 {
    5452 consdata = SCIPconsGetData(conss[i]);
    5453 assert( consdata != NULL );
    5454
    5455 if ( consdata->varswithevents != NULL )
    5456 {
    5457 assert( consdata->eventtypes != NULL );
    5458 assert( consdata->lincons != NULL );
    5459
    5460 for (j = 0; j < consdata->nevents; ++j)
    5461 {
    5462 SCIP_CALL( SCIPdropVarEvent(scip, consdata->varswithevents[j], consdata->eventtypes[j], conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, -1) );
    5463 }
    5464 SCIPfreeBlockMemoryArray(scip, &consdata->varswithevents, consdata->nevents);
    5465 SCIPfreeBlockMemoryArray(scip, &consdata->eventtypes, consdata->nevents);
    5466
    5467 consdata->nevents = 0;
    5468 assert( consdata->varswithevents == NULL );
    5469 assert( consdata->eventtypes == NULL );
    5470 }
    5471 }
    5472
    5473 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
    5474 conshdlrdata->maxaddlincons = 0;
    5475 conshdlrdata->naddlincons = 0;
    5476 conshdlrdata->nrows = 0;
    5477
    5478 return SCIP_OKAY;
    5479}
    5480
    5481
    5482/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
    5483static
    5484SCIP_DECL_CONSFREE(consFreeIndicator)
    5485{
    5486 SCIP_CONSHDLRDATA* conshdlrdata;
    5487
    5488 assert( scip != NULL );
    5489 assert( conshdlr != NULL );
    5490 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    5491
    5492 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5493 assert( conshdlrdata != NULL );
    5494 assert( conshdlrdata->altlp == NULL );
    5495 assert( conshdlrdata->varhash == NULL );
    5496 assert( conshdlrdata->lbhash == NULL );
    5497 assert( conshdlrdata->ubhash == NULL );
    5498 assert( conshdlrdata->slackhash == NULL );
    5499
    5500 if ( conshdlrdata->maxaddlincons > 0 )
    5501 {
    5502 /* if problem was not yet transformed the array may need to be freed, because we did not call the EXIT callback */
    5503 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
    5504 }
    5505 assert( conshdlrdata->addlincons == NULL );
    5506 conshdlrdata->naddlincons = 0;
    5507 conshdlrdata->maxaddlincons = 0;
    5508
    5509 SCIPfreeBlockMemory(scip, &conshdlrdata);
    5510
    5511 return SCIP_OKAY;
    5512}
    5513
    5514
    5515/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
    5516static
    5517SCIP_DECL_CONSINITSOL(consInitsolIndicator)
    5518{
    5519 SCIP_CONSHDLRDATA* conshdlrdata;
    5520 int c;
    5521
    5522 assert( scip != NULL );
    5523 assert( conshdlr != NULL );
    5524 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    5525
    5528 return SCIP_OKAY;
    5529
    5530 SCIPdebugMsg(scip, "Initsol for indicator constraints.\n");
    5531
    5532 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5533 assert( conshdlrdata != NULL );
    5534 assert( conshdlrdata->slackhash == NULL );
    5535
    5536 conshdlrdata->boundhaschanged = TRUE; /* make sure that we propagate at the beginning */
    5537
    5538 SCIP_CALL( SCIPgetCharParam(scip, "separating/efficacynorm", &conshdlrdata->normtype) );
    5539
    5540 if ( conshdlrdata->sepaalternativelp )
    5541 {
    5542 /* generate hash for storing all slack variables (size is just a guess) */
    5543 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->slackhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
    5544 assert( conshdlrdata->slackhash != NULL );
    5545
    5546 /* first initialize slack hash */
    5547 for (c = 0; c < nconss; ++c)
    5548 {
    5549 SCIP_CONSDATA* consdata;
    5550
    5551 assert( conss != NULL );
    5552 assert( conss[c] != NULL );
    5553 assert( SCIPconsIsTransformed(conss[c]) );
    5554
    5555 consdata = SCIPconsGetData(conss[c]);
    5556 assert( consdata != NULL );
    5557
    5558 assert( consdata->slackvar != NULL );
    5559
    5560 /* insert slack variable into hash */
    5561 SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->slackhash, consdata->slackvar, INT_MAX) );
    5562 assert( SCIPhashmapExists(conshdlrdata->slackhash, consdata->slackvar) );
    5563 ++conshdlrdata->nslackvars;
    5564 }
    5565
    5566 if ( conshdlrdata->genlogicor )
    5567 {
    5568 SCIP_CONSHDLR* logicorconshdlr;
    5569 int logicorsepafreq;
    5570 int sepafreq;
    5571
    5572 /* If we generate logicor constraints, but the separation frequency is not 1, output warning */
    5573 logicorconshdlr = SCIPfindConshdlr(scip, "logicor");
    5574 if ( logicorconshdlr == NULL )
    5575 {
    5576 SCIPerrorMessage("Logicor constraint handler not included, cannot generate constraints.\n");
    5577 return SCIP_ERROR;
    5578 }
    5579 logicorsepafreq = SCIPconshdlrGetSepaFreq(logicorconshdlr);
    5580 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
    5581 if ( (sepafreq != -1 || conshdlrdata->enforcecuts) && logicorsepafreq != 1 )
    5582 {
    5583 SCIPwarningMessage(scip, "For better performance set parameter 'constraints/logicor/sepafreq' to 1 if 'constraints/included/genlogicor' is true.\n");
    5584 }
    5585 }
    5586 }
    5587
    5588 /* check each constraint */
    5589 conshdlrdata->objothervarsonly = TRUE;
    5590 for (c = 0; c < nconss; ++c)
    5591 {
    5592 SCIP_CONSDATA* consdata;
    5593
    5594 assert( conss != NULL );
    5595 assert( conss[c] != NULL );
    5596 assert( SCIPconsIsTransformed(conss[c]) );
    5597
    5598 consdata = SCIPconsGetData(conss[c]);
    5599 assert( consdata != NULL );
    5600 assert( consdata->binvar != NULL );
    5601 assert( consdata->slackvar != NULL );
    5602
    5603 /* Presolving might replace a slack variable by an active variable. Thus, the objective of a slack variables might
    5604 * be nonzero. However, we do not need to check slack variables here. */
    5605 if ( ! SCIPisZero(scip, varGetObjDelta(consdata->binvar)) )
    5606 conshdlrdata->objothervarsonly = FALSE;
    5607
    5608 /* deactivate */
    5609 if ( ! consdata->linconsactive )
    5610 {
    5611 SCIP_CALL( SCIPdisableCons(scip, consdata->lincons) );
    5612 }
    5613 else
    5614 {
    5615 /* add constraint to alternative LP if not already done */
    5616 if ( conshdlrdata->sepaalternativelp && consdata->colindex < 0 )
    5617 {
    5618 SCIP_CALL( addAltLPConstraint(scip, conshdlr, consdata->lincons, consdata->slackvar, 1.0, &consdata->colindex) );
    5619 SCIPdebugMsg(scip, "Added column for <%s> to alternative LP with column index %d.\n", SCIPconsGetName(conss[c]),consdata->colindex);
    5620#ifdef SCIP_OUTPUT
    5621 SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
    5622 SCIPinfoMessage(scip, NULL, ";\n");
    5623#endif
    5624 }
    5625 }
    5626
    5627 /* add nlrow representation to NLP, if NLP had been constructed
    5628 *
    5629 * Note, that we did not tell SCIP in exitpre that we have something to add to the NLP, thus
    5630 * indicators are only available in the NLP for MINLPs, but not for MIPs with indicators.
    5631 */
    5632 if ( SCIPisNLPConstructed(scip) && SCIPconsIsChecked(conss[c]) )
    5633 {
    5634 /* create nonlinear row binary variable * slack variable = 0 */
    5635 SCIP_NLROW* nlrow;
    5636 SCIP_EXPR* quadexpr;
    5637 SCIP_EXPR* varexprs[2];
    5638
    5639 SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[0], consdata->binvar, NULL, NULL) );
    5640 SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[1], consdata->slackvar, NULL, NULL) );
    5641 SCIP_CALL( SCIPcreateExprProduct(scip, &quadexpr, 2, varexprs, 1.0, NULL, NULL) );
    5642
    5643 SCIP_CALL( SCIPcreateNlRow(scip, &nlrow, SCIPconsGetName(conss[c]), 0.0, 0, NULL, NULL, quadexpr, 0.0, 0.0, SCIP_EXPRCURV_UNKNOWN) );
    5644
    5645 SCIP_CALL( SCIPreleaseExpr(scip, &quadexpr) );
    5646 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[1]) );
    5647 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[0]) );
    5648
    5649 /* add row to NLP and forget about it */
    5650 SCIP_CALL( SCIPaddNlRow(scip, nlrow) );
    5651 SCIP_CALL( SCIPreleaseNlRow(scip, &nlrow) );
    5652 }
    5653 }
    5654
    5655 SCIPdebugMsg(scip, "Initialized %d indicator constraints.\n", nconss);
    5656
    5657 /* check additional constraints */
    5658 if ( conshdlrdata->sepaalternativelp )
    5659 {
    5660 SCIP_CONS* cons;
    5661 int colindex;
    5662 int cnt = 0;
    5663
    5664 /* add stored linear constraints if they exist */
    5665 if ( conshdlrdata->naddlincons > 0 )
    5666 {
    5667 for (c = 0; c < conshdlrdata->naddlincons; ++c)
    5668 {
    5669 cons = conshdlrdata->addlincons[c];
    5670
    5671 /* get transformed constraint - since it is needed only here, we do not store the information */
    5672 if ( ! SCIPconsIsTransformed(cons) )
    5673 {
    5674 SCIP_CALL( SCIPgetTransformedCons(scip, conshdlrdata->addlincons[c], &cons) );
    5675
    5676 /* @todo check when exactly the transformed constraint does not exist - SCIPisActive() does not suffice */
    5677 if ( cons == NULL )
    5678 continue;
    5679 }
    5680 SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
    5681 ++cnt;
    5682
    5683#ifdef SCIP_OUTPUT
    5684 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
    5685 SCIPinfoMessage(scip, NULL, ";\n");
    5686#endif
    5687 }
    5688 SCIPdebugMsg(scip, "Added %d additional columns to alternative LP.\n", cnt);
    5689 }
    5690 else
    5691 {
    5692 /* if no stored linear constraints are available, possibly collect other linear constraints; we only use linear
    5693 * constraints, since most other constraints involve integral variables, and in this context we will likely
    5694 * benefit much more from continuous variables. */
    5695 if ( conshdlrdata->useotherconss )
    5696 {
    5697 const char* conshdlrname;
    5698 SCIP_CONS** allconss;
    5699 int nallconss;
    5700
    5701 nallconss = SCIPgetNConss(scip);
    5702 allconss = SCIPgetConss(scip);
    5703
    5704 /* loop through all constraints */
    5705 for (c = 0; c < nallconss; ++c)
    5706 {
    5707 /* get constraint */
    5708 cons = allconss[c];
    5709 assert( cons != NULL );
    5710 assert( SCIPconsIsTransformed(cons) );
    5711
    5712 /* get constraint handler name */
    5713 conshdlrname = SCIPconshdlrGetName(SCIPconsGetHdlr(cons));
    5714
    5715 /* check type of constraint (only take modifiable linear constraints) */
    5716 if ( strcmp(conshdlrname, "linear") == 0 && ! SCIPconsIsModifiable(cons) )
    5717 {
    5718 /* avoid adding linear constraints that correspond to indicator constraints */
    5719 if ( strncmp(SCIPconsGetName(cons), "indlin", 6) != 0 )
    5720 {
    5721 SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
    5722 SCIPdebugMsg(scip, "Added column for linear constraint <%s> to alternative LP with column index %d.\n", SCIPconsGetName(cons), colindex);
    5723 ++cnt;
    5724 }
    5725 }
    5726 }
    5727 SCIPdebugMsg(scip, "Added %d additional columns from linear constraints to alternative LP.\n", cnt);
    5728 }
    5729 }
    5730 }
    5731
    5732 /* initialize event handler if restart should be forced */
    5733 if ( conshdlrdata->forcerestart )
    5734 {
    5735 SCIP_Bool* covered;
    5736 SCIP_VAR** vars;
    5737 int nvars;
    5738 int j;
    5739
    5740 assert( conshdlrdata->eventhdlrrestart != NULL );
    5741
    5742 /* store number of initial constraints */
    5743 conshdlrdata->ninitconss = SCIPconshdlrGetNActiveConss(conshdlr);
    5744
    5745 /* reset number of fixed binary variables */
    5746 conshdlrdata->nbinvarszero = 0;
    5747
    5748 /* loop through variables */
    5749 nvars = SCIPgetNVars(scip);
    5750 vars = SCIPgetVars(scip);
    5751
    5752 conshdlrdata->objindicatoronly = FALSE;
    5753 conshdlrdata->minabsobj = SCIP_REAL_MAX;
    5754
    5755 /* unmark all variables */
    5756 SCIP_CALL( SCIPallocBufferArray(scip, &covered, nvars) );
    5757 for (j = 0; j < nvars; ++j)
    5758 covered[j] = FALSE;
    5759
    5760 /* mark indicator variables */
    5761 for (c = 0; c < nconss; ++c)
    5762 {
    5763 SCIP_CONSDATA* consdata;
    5764 int probindex;
    5765
    5766 assert( conss != NULL );
    5767 assert( conss[c] != NULL );
    5768
    5769 /* avoid non-active indicator constraints */
    5770 if ( ! SCIPconsIsActive(conss[c]) )
    5771 continue;
    5772
    5773 consdata = SCIPconsGetData(conss[c]);
    5774 assert( consdata != NULL );
    5775 assert( consdata->binvar != NULL );
    5776
    5777 if ( SCIPvarIsNegated(consdata->binvar) )
    5778 {
    5779 assert( SCIPvarGetNegatedVar(consdata->binvar) != NULL );
    5780 probindex = SCIPvarGetProbindex(SCIPvarGetNegatedVar(consdata->binvar));
    5781 }
    5782 else
    5783 probindex = SCIPvarGetProbindex(consdata->binvar);
    5784
    5785 /* if presolving detected infeasibility it might be that the binary variables are not active */
    5786 if ( probindex < 0 )
    5787 continue;
    5788
    5789 assert( 0 <= probindex && probindex < nvars );
    5790 covered[probindex] = TRUE;
    5791 }
    5792
    5793 /* check all variables */
    5794 for (j = 0; j < nvars; ++j)
    5795 {
    5796 SCIP_Real obj;
    5797
    5798 obj = SCIPvarGetObj(vars[j]);
    5799 if ( ! SCIPisZero(scip, obj) )
    5800 {
    5801 if ( ! covered[j] )
    5802 break;
    5803 if ( ! SCIPisIntegral(scip, obj) )
    5804 break;
    5805 if ( REALABS(obj) < conshdlrdata->minabsobj )
    5806 conshdlrdata->minabsobj = REALABS(obj);
    5807 }
    5808 }
    5809
    5810 /* if all variables have integral objective and only indicator variables have nonzero objective */
    5811 if ( j >= nvars )
    5812 {
    5813 /* if there are variables with nonzero objective */
    5814 if ( conshdlrdata->minabsobj < SCIP_REAL_MAX )
    5815 {
    5816 assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
    5817 assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0) );
    5818
    5819 conshdlrdata->objindicatoronly = TRUE;
    5820
    5821 assert( conshdlrdata->eventhdlrrestart != NULL );
    5822 SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
    5823 }
    5824 }
    5825
    5826 SCIPfreeBufferArray(scip, &covered);
    5827 }
    5828
    5829 return SCIP_OKAY;
    5830}
    5831
    5832
    5833/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
    5834static
    5835SCIP_DECL_CONSEXITSOL(consExitsolIndicator)
    5836{ /*lint --e{715}*/
    5837 SCIP_CONSHDLRDATA* conshdlrdata;
    5838 int c;
    5839
    5840 assert( scip != NULL );
    5841 assert( conshdlr != NULL );
    5842 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    5843
    5844 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5845 assert( conshdlrdata != NULL );
    5846
    5847 if ( conshdlrdata->sepaalternativelp )
    5848 {
    5849 if ( conshdlrdata->slackhash != NULL )
    5850 {
    5851#ifdef SCIP_DEBUG
    5852 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator slack hash:\n");
    5853 SCIPhashmapPrintStatistics(conshdlrdata->slackhash, SCIPgetMessagehdlr(scip));
    5854#endif
    5855 SCIPhashmapFree(&conshdlrdata->slackhash);
    5856 }
    5857
    5858 if ( conshdlrdata->altlp != NULL )
    5859 {
    5860 assert( conshdlrdata->varhash != NULL );
    5861 assert( conshdlrdata->lbhash != NULL );
    5862 assert( conshdlrdata->ubhash != NULL );
    5863
    5864#ifdef SCIP_DEBUG
    5865 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator var hash:\n");
    5866 SCIPhashmapPrintStatistics(conshdlrdata->varhash, SCIPgetMessagehdlr(scip));
    5867 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator lower bound hash:\n");
    5868 SCIPhashmapPrintStatistics(conshdlrdata->lbhash, SCIPgetMessagehdlr(scip));
    5869 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator upper bound hash:\n");
    5870 SCIPhashmapPrintStatistics(conshdlrdata->ubhash, SCIPgetMessagehdlr(scip));
    5871#endif
    5872
    5873 SCIPhashmapFree(&conshdlrdata->varhash);
    5874 SCIPhashmapFree(&conshdlrdata->lbhash);
    5875 SCIPhashmapFree(&conshdlrdata->ubhash);
    5876
    5877 SCIP_CALL( SCIPlpiFree(&conshdlrdata->altlp) );
    5878
    5879 /* save the information that the columns have been deleted */
    5880 for (c = 0; c < nconss; ++c)
    5881 {
    5882 SCIP_CONSDATA* consdata;
    5883
    5884 assert( conss != NULL );
    5885 assert( conss[c] != NULL );
    5886
    5887 consdata = SCIPconsGetData(conss[c]);
    5888 assert( consdata != NULL );
    5889 consdata->colindex = -1;
    5890 }
    5891 }
    5892 }
    5893 else
    5894 {
    5895 assert( conshdlrdata->slackhash == NULL );
    5896 assert( conshdlrdata->varhash == NULL );
    5897 assert( conshdlrdata->lbhash == NULL );
    5898 assert( conshdlrdata->ubhash == NULL );
    5899 }
    5900
    5901 return SCIP_OKAY;
    5902}
    5903
    5904
    5905/** frees specific constraint data */
    5906static
    5907SCIP_DECL_CONSDELETE(consDeleteIndicator)
    5908{
    5909 assert( scip != NULL );
    5910 assert( conshdlr != NULL );
    5911 assert( cons != NULL );
    5912 assert( consdata != NULL );
    5913 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    5914
    5915#ifdef SCIP_MORE_DEBUG
    5916 SCIPdebugMsg(scip, "Deleting indicator constraint <%s>.\n", SCIPconsGetName(cons) );
    5917#endif
    5918
    5919 /* Make sure that the hash for binary variables is freed. If we read a problem and then another problem without
    5920 * solving (transforming) between, then no callback of constraint handlers are called. Thus, we cannot easily free the
    5921 * hash map there. */
    5922 if ( SCIPconshdlrGetNConss(conshdlr) == 0 )
    5923 {
    5924 SCIP_CONSHDLRDATA* conshdlrdata;
    5925
    5926 /* get constraint handler data */
    5927 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5928 assert( conshdlrdata != NULL );
    5929
    5930 if ( conshdlrdata->binslackvarhash != NULL )
    5931 SCIPhashmapFree(&conshdlrdata->binslackvarhash);
    5932 }
    5933
    5934 /* drop events on transformed variables */
    5935 if ( SCIPconsIsTransformed(cons) )
    5936 {
    5937 SCIP_CONSHDLRDATA* conshdlrdata;
    5938
    5939 /* get constraint handler data */
    5940 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5941 assert( conshdlrdata != NULL );
    5942
    5943 if ( conshdlrdata->sepaalternativelp )
    5944 {
    5945 SCIP_CALL( deleteAltLPConstraint(scip, conshdlr, cons) );
    5946 }
    5947
    5948 assert( (*consdata)->slackvar != NULL );
    5949 assert( (*consdata)->binvar != NULL );
    5950
    5951 /* free events only in correct stages */
    5953 {
    5954 if ( (*consdata)->linconsactive )
    5955 {
    5956 assert( conshdlrdata->eventhdlrbound != NULL );
    5957 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
    5958 (SCIP_EVENTDATA*) cons, -1) );
    5959 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
    5960 (SCIP_EVENTDATA*) cons, -1) );
    5961 }
    5962 if ( conshdlrdata->forcerestart )
    5963 {
    5964 assert( conshdlrdata->eventhdlrrestart != NULL );
    5965 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
    5966 (SCIP_EVENTDATA*) conshdlrdata, -1) );
    5967 }
    5968
    5969 /* drop bound change events on variables of linear constraints */
    5970 if ( conshdlrdata->linconsevents && (*consdata)->linconsactive && (*consdata)->varswithevents != NULL )
    5971 {
    5972 int j;
    5973 assert( cons != NULL );
    5974 assert( (*consdata)->eventtypes != NULL );
    5975 assert( (*consdata)->lincons != NULL );
    5976
    5977 for (j = 0; j < (*consdata)->nevents; ++j)
    5978 {
    5979 assert( !SCIPvarIsDeleted((*consdata)->varswithevents[j]) );
    5980 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->varswithevents[j], (*consdata)->eventtypes[j], conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, -1) );
    5981 }
    5982 SCIPfreeBlockMemoryArray(scip, &(*consdata)->varswithevents, (*consdata)->nevents);
    5983 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventtypes, (*consdata)->nevents);
    5984
    5985 (*consdata)->nevents = 0;
    5986 assert( (*consdata)->varswithevents == NULL );
    5987 assert( (*consdata)->eventtypes == NULL );
    5988 }
    5989 }
    5990 }
    5991
    5992 /* Can there be cases where lincons is NULL, e.g., if presolve found the problem infeasible? */
    5993 assert( (*consdata)->lincons != NULL );
    5994
    5995 /* mark linear constraint to be upgrade-able */
    5996 if ( SCIPconsIsActive((*consdata)->lincons) )
    5997 {
    5998 SCIPconsAddUpgradeLocks((*consdata)->lincons, -1);
    5999 assert( SCIPconsGetNUpgradeLocks((*consdata)->lincons) == 0 );
    6000 }
    6001
    6002 /* release linear constraint and slack variable */
    6003 SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->slackvar) );
    6004 SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->lincons) );
    6005
    6006 SCIPfreeBlockMemory(scip, consdata);
    6007
    6008 return SCIP_OKAY;
    6009}
    6010
    6011
    6012/** transforms constraint data into data belonging to the transformed problem */
    6013static
    6014SCIP_DECL_CONSTRANS(consTransIndicator)
    6015{
    6016 SCIP_CONSDATA* consdata;
    6017 SCIP_CONSHDLRDATA* conshdlrdata;
    6018 SCIP_CONSDATA* sourcedata;
    6019 char s[SCIP_MAXSTRLEN];
    6020
    6021 assert( scip != NULL );
    6022 assert( conshdlr != NULL );
    6023 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6024 assert( sourcecons != NULL );
    6025 assert( targetcons != NULL );
    6026
    6027 /* get constraint handler data */
    6028 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6029 assert( conshdlrdata != NULL );
    6030 assert( conshdlrdata->eventhdlrbound != NULL );
    6031
    6032#ifdef SCIP_MORE_DEBUG
    6033 SCIPdebugMsg(scip, "Transforming indicator constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
    6034#endif
    6035
    6036 /* get data of original constraint */
    6037 sourcedata = SCIPconsGetData(sourcecons);
    6038 assert( sourcedata != NULL );
    6039 assert( sourcedata->binvar != NULL );
    6040
    6041 /* check for slackvar */
    6042 if ( sourcedata->slackvar == NULL )
    6043 {
    6044 SCIPerrorMessage("The indicator constraint <%s> needs a slack variable.\n", SCIPconsGetName(sourcecons));
    6045 return SCIP_INVALIDDATA;
    6046 }
    6047
    6048 /* check for linear constraint */
    6049 if ( sourcedata->lincons == NULL )
    6050 {
    6051 SCIPerrorMessage("The indicator constraint <%s> needs a linear constraint.\n", SCIPconsGetName(sourcecons));
    6052 return SCIP_INVALIDDATA;
    6053 }
    6054 assert( sourcedata->lincons != NULL );
    6055 assert( sourcedata->slackvar != NULL );
    6056
    6057 /* create constraint data */
    6058 consdata = NULL;
    6059 /* Note that the constraint has activeone = TRUE, since the binary variable has been negated already if needed. */
    6060 SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, SCIPconsGetName(sourcecons), &consdata, conshdlrdata->eventhdlrrestart,
    6061 sourcedata->binvar, TRUE, sourcedata->lessthanineq, sourcedata->slackvar, sourcedata->lincons, sourcedata->linconsactive) );
    6062 consdata->activeone = sourcedata->activeone;
    6063 assert( consdata != NULL );
    6064
    6065 /* capture slack variable and linear constraint */
    6066 SCIP_CALL( SCIPcaptureVar(scip, consdata->slackvar) );
    6067 SCIP_CALL( SCIPcaptureCons(scip, consdata->lincons) );
    6068
    6069 /* create transformed constraint with the same flags */
    6070 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
    6071 SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
    6072 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
    6073 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
    6074 SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
    6075 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
    6076 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
    6077
    6078 /* catch local bound change events on binary variable */
    6079 if ( sourcedata->linconsactive )
    6080 {
    6081 assert( SCIPisTransformed(scip) );
    6082 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *targetcons, NULL) );
    6083 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *targetcons, NULL) );
    6084 }
    6085
    6086 /* make sure that binary variable hash exists */
    6087 if ( conshdlrdata->sepaalternativelp )
    6088 {
    6089 if ( conshdlrdata->binvarhash == NULL )
    6090 {
    6091 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
    6092 }
    6093
    6094 /* check whether binary variable is present: note that a binary variable might appear several times, but this seldomly happens. */
    6095 assert( conshdlrdata->binvarhash != NULL );
    6096 if ( ! SCIPhashmapExists(conshdlrdata->binvarhash, (void*) consdata->binvar) )
    6097 {
    6098 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binvarhash, (void*) consdata->binvar, (void*) (*targetcons)) );
    6099 }
    6100 }
    6101
    6102 return SCIP_OKAY;
    6103}
    6104
    6105
    6106/** presolving initialization method of constraint handler (called when presolving is about to begin) */
    6107static
    6108SCIP_DECL_CONSINITPRE(consInitpreIndicator)
    6109{ /*lint --e{715}*/
    6110 SCIP_CONSHDLRDATA* conshdlrdata;
    6111 int c;
    6112
    6113 assert( scip != NULL );
    6114 assert( conshdlr != NULL );
    6115 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6116
    6118 return SCIP_OKAY;
    6119
    6120 SCIPdebugMsg(scip, "Initpre method for indicator constraints.\n");
    6121
    6122 /* check each constraint and get transformed linear constraint */
    6123 for (c = 0; c < nconss; ++c)
    6124 {
    6125 SCIP_CONSDATA* consdata;
    6126
    6127 assert( conss != NULL );
    6128 assert( conss[c] != NULL );
    6129 assert( SCIPconsIsTransformed(conss[c]) );
    6130
    6131 consdata = SCIPconsGetData(conss[c]);
    6132 assert( consdata != NULL );
    6133
    6134 /* if not happened already, get transformed linear constraint */
    6135 assert( consdata->lincons != NULL );
    6136 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear") == 0 );
    6137
    6138 /* in a restart the linear constraint might already be transformed */
    6139 if ( ! SCIPconsIsTransformed(consdata->lincons) )
    6140 {
    6141 SCIP_CONS* translincons;
    6142
    6143 SCIP_CALL( SCIPgetTransformedCons(scip, consdata->lincons, &translincons) );
    6144 assert( translincons != NULL );
    6145
    6146 SCIP_CALL( SCIPreleaseCons(scip, &consdata->lincons) );
    6147 SCIP_CALL( SCIPcaptureCons(scip, translincons) );
    6148 consdata->lincons = translincons;
    6149 }
    6150 }
    6151
    6152 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6153 assert( conshdlrdata != NULL );
    6154
    6155 /* reset flag, in case presolve was called for some problem before */
    6156 conshdlrdata->addedcouplingcons = FALSE;
    6157
    6158 return SCIP_OKAY;
    6159}
    6160
    6161
    6162/** presolving method of constraint handler
    6163 *
    6164 * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
    6165 * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
    6166 * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not
    6167 * inserted. Depending on the parameter @a addcouplingcons we add a variable upper bound or a row
    6168 * (in consInitlpIndicator()).
    6169 *
    6170 * @warning We can never delete linear constraints, because we need them to get the right values
    6171 * for the slack variables!
    6172 */
    6173static
    6174SCIP_DECL_CONSPRESOL(consPresolIndicator)
    6175{ /*lint --e{715}*/
    6176 SCIP_CONSHDLRDATA* conshdlrdata;
    6177 SCIP_Bool noReductions;
    6178 SCIPdebug( int oldnfixedvars = *nfixedvars; )
    6179 SCIPdebug( int oldndelconss = *ndelconss; )
    6180 int c;
    6181
    6182 assert( scip != NULL );
    6183 assert( conshdlr != NULL );
    6184 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6185 assert( result != NULL );
    6186
    6187 *result = SCIP_DIDNOTRUN;
    6188
    6189 /* get constraint handler data */
    6190 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6191 assert( conshdlrdata != NULL );
    6192
    6193 SCIPdebugMsg(scip, "Presolving indicator constraints.\n");
    6194
    6195 /* only run if success is possible */
    6196 if ( nrounds == 0 || nnewfixedvars > 0 || nnewchgbds > 0 || nnewaggrvars > 0 )
    6197 {
    6198 *result = SCIP_DIDNOTFIND;
    6199
    6200 /* check each constraint */
    6201 for (c = 0; c < nconss; ++c)
    6202 {
    6203 SCIP_CONSDATA* consdata;
    6204 SCIP_CONS* cons;
    6205 SCIP_Bool success;
    6206 SCIP_Bool cutoff;
    6207
    6208 assert( conss != NULL );
    6209 assert( conss[c] != NULL );
    6210 cons = conss[c];
    6211 consdata = SCIPconsGetData(cons);
    6212 assert( consdata != NULL );
    6213 assert( consdata->binvar != NULL );
    6214 assert( ! SCIPconsIsModifiable(cons) );
    6215
    6216#ifdef SCIP_MORE_DEBUG
    6217 SCIPdebugMsg(scip, "Presolving indicator constraint <%s>.\n", SCIPconsGetName(cons) );
    6218#endif
    6219
    6220 /* do nothing if the linear constraint is not active */
    6221 if ( ! consdata->linconsactive )
    6222 continue;
    6223
    6224 assert( consdata->lincons != NULL );
    6225 assert( consdata->slackvar != NULL );
    6226 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear") == 0 );
    6227 assert( SCIPconsIsTransformed(consdata->lincons) );
    6228
    6229 /* add implications if not yet done */
    6230 if ( ! consdata->implicationadded )
    6231 {
    6232 int nbnds = 0;
    6233 SCIP_CALL( SCIPaddVarImplication(scip, consdata->binvar, TRUE, consdata->slackvar, SCIP_BOUNDTYPE_UPPER, 0.0,
    6234 &cutoff, &nbnds) );
    6235 *nchgbds += nbnds;
    6236
    6237 /* cutoff/infeasible might be true if preprocessing was truncated */
    6238 /* note: nbdchgs == 0 is not necessarily true, because preprocessing might be truncated. */
    6239 consdata->implicationadded = TRUE;
    6240 if ( cutoff )
    6241 {
    6242 *result = SCIP_CUTOFF;
    6243 return SCIP_OKAY;
    6244 }
    6245 }
    6246
    6247 /* determine integrality of slack variable if not yet done */
    6248 if ( !consdata->slacktypechecked )
    6249 {
    6250 consdata->slacktypechecked = TRUE;
    6251 if ( !SCIPvarIsImpliedIntegral(consdata->slackvar) )
    6252 {
    6253 SCIP_Real* vals;
    6254 SCIP_VAR** vars;
    6255 SCIP_VAR* slackvar;
    6256 SCIP_Bool foundslackvar = FALSE;
    6257 int nvars;
    6258 int j;
    6259
    6260 assert( consdata->lincons != NULL );
    6261 vars = SCIPgetVarsLinear(scip, consdata->lincons);
    6262 vals = SCIPgetValsLinear(scip, consdata->lincons);
    6263 nvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    6264 slackvar = consdata->slackvar;
    6265 assert( slackvar != NULL );
    6266
    6267 for (j = 0; j < nvars; ++j)
    6268 {
    6269 if ( vars[j] == slackvar )
    6270 foundslackvar = TRUE;
    6271 else
    6272 {
    6273 if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, vals[j]))
    6274 break;
    6275 }
    6276 }
    6277 /* something is strange if the slack variable does not appear in the linear constraint (possibly because it is an artificial constraint) */
    6278 if ( j == nvars && foundslackvar )
    6279 {
    6280 SCIP_Real lb;
    6281 SCIP_Real ub;
    6282
    6283 lb = SCIPvarGetLbGlobal(consdata->slackvar);
    6284 ub = SCIPvarGetUbGlobal(consdata->slackvar);
    6285 if ( (SCIPisInfinity(scip, -lb) || SCIPisIntegral(scip, lb)) && (SCIPisInfinity(scip, ub) || SCIPisIntegral(scip, ub)) )
    6286 {
    6287 SCIP_Bool infeasible;
    6288
    6289 SCIP_CALL( SCIPchgVarImplType(scip, consdata->slackvar, SCIP_IMPLINTTYPE_WEAK, &infeasible) );
    6290 /* don't assert feasibility here because the presolver should detect infeasibility */
    6291 }
    6292 else
    6293 {
    6294 /* it can happen that the bounds of the slack variable have been changed to be non-integral in
    6295 * previous presolving steps. We then might get a problem with tightening the bounds. In this case,
    6296 * we just leave the slack variable to be continuous */
    6297 SCIPdebugMsg(scip, "Cannot declare slack variable (<%s>) weakly implied integral, since global bound is non-integral: (%g, %g).\n",
    6298 SCIPvarGetName(consdata->slackvar), SCIPvarGetLbGlobal(consdata->slackvar), SCIPvarGetUbGlobal(consdata->slackvar));
    6299 }
    6300 }
    6301 }
    6302 }
    6303
    6304 /* perform one presolving round */
    6305 SCIP_CALL( presolRoundIndicator(scip, conshdlrdata, cons, consdata,
    6306 conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip), &cutoff, &success, ndelconss, nfixedvars) );
    6307
    6308 if ( cutoff )
    6309 {
    6310 *result = SCIP_CUTOFF;
    6311 return SCIP_OKAY;
    6312 }
    6313 if ( success )
    6314 *result = SCIP_SUCCESS;
    6315 }
    6316 }
    6317
    6318 /* determine whether other methods have found reductions */
    6319 noReductions = nnewfixedvars == 0 && nnewaggrvars == 0 && nnewchgvartypes == 0 && nnewchgbds == 0
    6320 && nnewdelconss == 0 && nnewchgcoefs == 0 && nnewchgsides == 0;
    6321
    6322 /* add variable upper bounds after bounds are likely to be strengthened */
    6323 if ( noReductions && *result != SCIP_SUCCESS && conshdlrdata->addcouplingcons && ! conshdlrdata->addedcouplingcons )
    6324 {
    6325 int ngen;
    6326
    6327 /* create variable upper bounds, possibly removing indicator constraints */
    6328 SCIP_CALL( createVarUbs(scip, conshdlrdata, conss, nconss, &ngen) );
    6329
    6330 if ( ngen > 0 )
    6331 {
    6332 *result = SCIP_SUCCESS;
    6333 *nupgdconss += ngen;
    6334 if ( conshdlrdata->removeindicators )
    6335 *ndelconss += ngen;
    6336 }
    6337 conshdlrdata->addedcouplingcons = TRUE;
    6338 }
    6339
    6340 SCIPdebug( SCIPdebugMsg(scip, "Presolved %d constraints (fixed %d variables, removed 0 variables, and deleted %d constraints).\n",
    6341 nconss, *nfixedvars - oldnfixedvars, *ndelconss - oldndelconss); )
    6342
    6343 return SCIP_OKAY; /*lint !e438*/
    6344}
    6345
    6346
    6347/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved)
    6348 *
    6349 * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
    6350 * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
    6351 * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not inserted.
    6352 */
    6353static
    6354SCIP_DECL_CONSINITLP(consInitlpIndicator)
    6355{
    6356 int c;
    6357 SCIP_CONSHDLRDATA* conshdlrdata;
    6358
    6359 assert( scip != NULL );
    6360 assert( conshdlr != NULL );
    6361 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6362
    6363 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6364 assert( conshdlrdata != NULL );
    6365
    6366 *infeasible = FALSE;
    6367
    6368 /* check whether coupling constraints should be added */
    6369 if ( ! conshdlrdata->addcoupling )
    6370 return SCIP_OKAY;
    6371
    6372 /* check whether coupling constraints have been added already */
    6373 if ( conshdlrdata->addcouplingcons && conshdlrdata->addedcouplingcons )
    6374 return SCIP_OKAY;
    6375
    6376 SCIPdebugMsg(scip, "Handle initial rows for %d indicator constraints.\n", nconss);
    6377
    6378 /* check each constraint */
    6379 for (c = 0; c < nconss && !(*infeasible); ++c)
    6380 {
    6381 SCIP_CONSDATA* consdata;
    6382 SCIP_Real ub;
    6383
    6384 assert( conss != NULL );
    6385 assert( conss[c] != NULL );
    6386 consdata = SCIPconsGetData(conss[c]);
    6387 assert( consdata != NULL );
    6388
    6389 /* do not add inequalities if there are no linear constraints (no slack variable available) */
    6390 if ( ! consdata->linconsactive )
    6391 continue;
    6392
    6393 /* get upper bound for slack variable in linear constraint */
    6394 ub = SCIPvarGetUbGlobal(consdata->slackvar);
    6395 assert( ! SCIPisNegative(scip, ub) );
    6396
    6397 /* insert corresponding row if helpful and coefficient is not too large */
    6398 if ( ub <= conshdlrdata->maxcouplingvalue )
    6399 {
    6400 char name[50];
    6401
    6402#ifndef NDEBUG
    6403 (void) SCIPsnprintf(name, 50, "couple%d", c);
    6404#else
    6405 name[0] = '\0';
    6406#endif
    6407
    6408 /* add variable upper bound if required */
    6409 if ( conshdlrdata->addcouplingcons )
    6410 {
    6411 SCIP_CONS* cons;
    6412
    6413 assert( ! conshdlrdata->addedcouplingcons );
    6414
    6415 SCIPdebugMsg(scip, "Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
    6416
    6417 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
    6419
    6420 SCIP_CALL( SCIPaddCons(scip, cons) );
    6421 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    6422 }
    6423 else
    6424 {
    6425 SCIP_ROW* row;
    6426
    6427 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, FALSE, FALSE, FALSE) );
    6429
    6430 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
    6431 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
    6433
    6434 SCIPdebugMsg(scip, "Insert coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
    6435#ifdef SCIP_OUTPUT
    6436 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
    6437#endif
    6438 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
    6439 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    6440 }
    6441 }
    6442 }
    6443
    6444 return SCIP_OKAY;
    6445}
    6446
    6447
    6448/** separation method of constraint handler for LP solutions */
    6449static
    6450SCIP_DECL_CONSSEPALP(consSepalpIndicator)
    6451{ /*lint --e{715}*/
    6452 assert( scip != NULL );
    6453 assert( conshdlr != NULL );
    6454 assert( conss != NULL );
    6455 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6456 assert( result != NULL );
    6457
    6458 /* perform separation */
    6459 SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, NULL, SCIP_TYPE_SEPALP, result) );
    6460
    6461 return SCIP_OKAY;
    6462}
    6463
    6464
    6465/** separation method of constraint handler for arbitrary primal solutions */
    6466static
    6467SCIP_DECL_CONSSEPASOL(consSepasolIndicator)
    6468{ /*lint --e{715}*/
    6469 assert( scip != NULL );
    6470 assert( conshdlr != NULL );
    6471 assert( conss != NULL );
    6472 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6473 assert( result != NULL );
    6474
    6475 /* perform separation */
    6476 SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, sol, SCIP_TYPE_SEPASOL, result) );
    6477
    6478 return SCIP_OKAY;
    6479}
    6480
    6481
    6482/** constraint enforcing method of constraint handler for LP solutions */
    6483static
    6484SCIP_DECL_CONSENFOLP(consEnfolpIndicator)
    6485{ /*lint --e{715}*/
    6486 SCIP_CONSHDLRDATA* conshdlrdata;
    6487
    6488 assert( scip != NULL );
    6489 assert( conshdlr != NULL );
    6490 assert( conss != NULL );
    6491 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6492 assert( result != NULL );
    6493
    6494 if ( solinfeasible )
    6495 {
    6496 *result = SCIP_FEASIBLE;
    6497 return SCIP_OKAY;
    6498 }
    6499
    6500 /* get constraint handler data */
    6501 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6502 assert( conshdlrdata != NULL );
    6503
    6504 SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, NULL, SCIP_TYPE_ENFOLP, conshdlrdata->genlogicor, result) );
    6505
    6506 return SCIP_OKAY;
    6507}
    6508
    6509
    6510/** constraint enforcing method of constraint handler for relaxation solutions */
    6511static
    6512SCIP_DECL_CONSENFORELAX(consEnforelaxIndicator)
    6513{ /*lint --e{715}*/
    6514 SCIP_CONSHDLRDATA* conshdlrdata;
    6515
    6516 assert( scip != NULL );
    6517 assert( conshdlr != NULL );
    6518 assert( conss != NULL );
    6519 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6520 assert( result != NULL );
    6521
    6522 if ( solinfeasible )
    6523 {
    6524 *result = SCIP_FEASIBLE;
    6525 return SCIP_OKAY;
    6526 }
    6527
    6528 /* get constraint handler data */
    6529 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6530 assert( conshdlrdata != NULL );
    6531
    6532 SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, sol, SCIP_TYPE_ENFORELAX, conshdlrdata->genlogicor, result) );
    6533
    6534 return SCIP_OKAY;
    6535}
    6536
    6537
    6538/** constraint enforcing method of constraint handler for pseudo solutions */
    6539static
    6540SCIP_DECL_CONSENFOPS(consEnfopsIndicator)
    6541{ /*lint --e{715}*/
    6542 assert( scip != NULL );
    6543 assert( conshdlr != NULL );
    6544 assert( conss != NULL );
    6545 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6546 assert( result != NULL );
    6547
    6548 if ( solinfeasible )
    6549 {
    6550 *result = SCIP_FEASIBLE;
    6551 return SCIP_OKAY;
    6552 }
    6553
    6554 if ( objinfeasible )
    6555 {
    6556 *result = SCIP_DIDNOTRUN;
    6557 return SCIP_OKAY;
    6558 }
    6559
    6560 SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, NULL, SCIP_TYPE_ENFOPS, TRUE, result) );
    6561
    6562 return SCIP_OKAY;
    6563}
    6564
    6565
    6566/** feasibility check method of constraint handler for integral solutions */
    6567static
    6568SCIP_DECL_CONSCHECK(consCheckIndicator)
    6569{ /*lint --e{715}*/
    6570 SCIP_SOL* trysol = NULL;
    6571 SCIP_CONSHDLRDATA* conshdlrdata;
    6572 SCIP_Bool someLinconsNotActive;
    6573 SCIP_Bool changedSol;
    6574 int c;
    6575
    6576 assert( scip != NULL );
    6577 assert( conshdlr != NULL );
    6578 assert( conss != NULL );
    6579 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6580 assert( result != NULL );
    6581
    6582 SCIPdebugMsg(scip, "Checking %d indicator constraints <%s>.\n", nconss, SCIPconshdlrGetName(conshdlr) );
    6583
    6584 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6585 assert( conshdlrdata != NULL );
    6586
    6587 /* try to repair solution below, if it makes sense (will send solution to trysol heuristic in any case (see below) */
    6588 if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM && SCIPgetStage(scip) < SCIP_STAGE_SOLVED && conshdlrdata->trysolutions && conshdlrdata->heurtrysol != NULL )
    6589 {
    6590 SCIP_CALL( SCIPcreateSolCopy(scip, &trysol, sol) );
    6591 assert( trysol != NULL );
    6592 }
    6593
    6594 /* check each constraint */
    6595 *result = SCIP_FEASIBLE;
    6596 changedSol = FALSE;
    6597 someLinconsNotActive = FALSE;
    6598 for (c = 0; c < nconss; ++c)
    6599 {
    6600 SCIP_CONSDATA* consdata;
    6601
    6602 assert( conss[c] != NULL );
    6603 consdata = SCIPconsGetData(conss[c]);
    6604 assert( consdata != NULL );
    6605 assert( consdata->binvar != NULL );
    6606
    6607 /* if the linear constraint has not been generated, we do nothing */
    6608 if ( ! consdata->linconsactive )
    6609 {
    6610 someLinconsNotActive = TRUE;
    6611 continue;
    6612 }
    6613
    6614 assert( consdata->slackvar != NULL );
    6615 /* if printreason is true it can happen that non-integral solutions are checked */
    6616 assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
    6617
    6618 /* if constraint is infeasible */
    6619 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) &&
    6620 ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) )
    6621 {
    6622 SCIP_Real absviol = REALABS(SCIPgetSolVal(scip, sol, consdata->slackvar));
    6623 SCIP_Real relviol = SCIPrelDiff(absviol, 0.0);
    6624
    6625 if( sol != NULL )
    6626 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
    6627
    6628 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
    6629 *result = SCIP_INFEASIBLE;
    6630
    6631 if ( printreason )
    6632 {
    6633 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
    6634 SCIPinfoMessage(scip, NULL, ";\nviolation: <%s> = %g and <%s> = %.15g\n",
    6635 SCIPvarGetName(consdata->binvar), SCIPgetSolVal(scip, sol, consdata->binvar),
    6636 SCIPvarGetName(consdata->slackvar), SCIPgetSolVal(scip, sol, consdata->slackvar));
    6637 }
    6638
    6639 /* try to make solution feasible if it makes sense - otherwise exit */
    6640 if ( trysol != NULL )
    6641 {
    6642 SCIP_Bool changed;
    6643 SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
    6644 changedSol = changedSol || changed;
    6645 }
    6646 else
    6647 {
    6648 SCIPdebugMsg(scip, "Indicator constraint %s is not feasible.\n", SCIPconsGetName(conss[c]));
    6649
    6650 if ( ! completely )
    6651 return SCIP_OKAY;
    6652 }
    6653 }
    6654 else
    6655 {
    6656 if ( trysol != NULL )
    6657 {
    6658 SCIP_Bool changed;
    6659 SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
    6660 changedSol = changedSol || changed;
    6661 }
    6662 }
    6663 }
    6664
    6665 /* if some linear constraints are not active, we need to check feasibility via the alternative polyhedron */
    6666 if ( someLinconsNotActive )
    6667 {
    6668 SCIP_LPI* lp;
    6669 SCIP_Bool infeasible;
    6670 SCIP_Bool error;
    6671 SCIP_Bool* S;
    6672
    6673 lp = conshdlrdata->altlp;
    6674 assert( conshdlrdata->sepaalternativelp );
    6675
    6676 /* the check maybe called before we have build the alternative polyhedron -> return SCIP_INFEASIBLE */
    6677 if ( lp != NULL )
    6678 {
    6679#ifndef NDEBUG
    6680 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    6681#endif
    6682
    6683 /* change coefficients of bounds in alternative LP */
    6684 if ( conshdlrdata->updatebounds )
    6685 {
    6686 SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
    6687 }
    6688
    6689 /* scale first row if necessary */
    6690 SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
    6691
    6692 /* set objective function to current solution */
    6693 SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
    6694
    6695 SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
    6696
    6697 /* set up variables fixed to 1 */
    6698 for (c = 0; c < nconss; ++c)
    6699 {
    6700 SCIP_CONSDATA* consdata;
    6701
    6702 assert( conss[c] != NULL );
    6703 consdata = SCIPconsGetData(conss[c]);
    6704 assert( consdata != NULL );
    6705
    6706 /* if printreason is true it can happen that non-integral solutions are checked */
    6707 assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
    6708 if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
    6709 S[c] = TRUE;
    6710 else
    6711 S[c] = FALSE;
    6712 }
    6713
    6714 /* fix the variables in S */
    6715 SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
    6716
    6717 /* check feasibility */
    6719 SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, TRUE, &infeasible, &error) );
    6721
    6722 if ( error )
    6723 return SCIP_LPERROR;
    6724
    6725 if ( ! infeasible )
    6726 *result = SCIP_INFEASIBLE;
    6727
    6728 /* reset bounds */
    6729 SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
    6730
    6731#ifndef NDEBUG
    6732 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
    6733#endif
    6734
    6736 }
    6737 else
    6738 *result = SCIP_INFEASIBLE;
    6739 }
    6740 else
    6741 {
    6742 /* tell heur_trysol about solution - it will pass it to SCIP */
    6743 if ( trysol != NULL && changedSol )
    6744 {
    6745 assert( conshdlrdata->heurtrysol != NULL );
    6746 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->heurtrysol, trysol) );
    6747 }
    6748 }
    6749
    6750 if ( trysol != NULL )
    6751 SCIP_CALL( SCIPfreeSol(scip, &trysol) );
    6752
    6753 if ( *result == SCIP_INFEASIBLE )
    6754 {
    6755 SCIPdebugMsg(scip, "Indicator constraints are not feasible.\n");
    6756 return SCIP_OKAY;
    6757 }
    6758
    6759 /* at this point we are feasible */
    6760 SCIPdebugMsg(scip, "Indicator constraints are feasible.\n");
    6761
    6762 return SCIP_OKAY;
    6763}
    6764
    6765
    6766/** domain propagation method of constraint handler */
    6767static
    6768SCIP_DECL_CONSPROP(consPropIndicator)
    6769{ /*lint --e{715}*/
    6770 SCIP_CONSHDLRDATA* conshdlrdata;
    6771 SCIP_Bool dualreductions;
    6772 int ngen = 0;
    6773 int c;
    6774
    6775 assert( scip != NULL );
    6776 assert( conshdlr != NULL );
    6777 assert( conss != NULL );
    6778 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6779 assert( result != NULL );
    6780
    6781 *result = SCIP_DIDNOTRUN;
    6782
    6783 assert( SCIPisTransformed(scip) );
    6784
    6785 SCIPdebugMsg(scip, "Start propagation of constraint handler <%s>.\n", SCIPconshdlrGetName(conshdlr));
    6786
    6787 /* get constraint handler data */
    6788 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6789 assert( conshdlrdata != NULL );
    6790
    6791 /* avoid propagation if no bound has changed */
    6792 if ( ! conshdlrdata->boundhaschanged && ! SCIPinRepropagation(scip) && ! conshdlrdata->linconsboundschanged )
    6793 {
    6794 *result = SCIP_DIDNOTFIND;
    6795 return SCIP_OKAY;
    6796 }
    6797
    6798 /* if first time called, add events on variables of linear constraint */
    6799 if ( !conshdlrdata->linconsevents )
    6800 {
    6801 for (c = 0; c < nconss; ++c)
    6802 {
    6803 SCIP_CONSDATA* consdata;
    6804 SCIP_VAR** vars;
    6805 SCIP_Real* vals;
    6806 int nvars;
    6807 int j;
    6808 assert( conss[c] != NULL );
    6809
    6810 consdata = SCIPconsGetData(conss[c]);
    6811 assert( consdata != NULL );
    6812
    6813 /* if the linear constraint is not present, we continue */
    6814 if ( ! consdata->linconsactive )
    6815 continue;
    6816
    6817 /* do not add events if upper bound of slackvar is already small */
    6818 if ( SCIPvarGetUbLocal(consdata->slackvar) <= conshdlrdata->maxcouplingvalue )
    6819 continue;
    6820
    6821 /* do not add events if it is not a <= inequality; we do not propagate in this case */
    6822 if ( SCIPisInfinity(scip, SCIPgetRhsLinear(scip, consdata->lincons) ) )
    6823 continue;
    6824
    6825 assert( consdata->lincons != NULL );
    6826 vars = SCIPgetVarsLinear(scip, consdata->lincons);
    6827 vals = SCIPgetValsLinear(scip, consdata->lincons);
    6828 nvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    6829 assert( consdata->slackvar != NULL );
    6830 assert( nvars != 0 );
    6831
    6832 /* alloc memory to store events on variables of linear constraint; otherwise we can not drop the events when the cons is deleted */
    6833 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varswithevents, nvars - 1) );
    6834 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventtypes, nvars - 1) );
    6835
    6836 for (j = 0; j < nvars; ++j)
    6837 {
    6838 if ( vars[j] == consdata->slackvar )
    6839 continue;
    6840
    6841 /* catch only bound changes which are important for propagation of max activity to upper bound of slackvar */
    6842 if ( vals[j] > 0.0 )
    6843 {
    6844 SCIP_CALL( SCIPcatchVarEvent(scip, vars[j], SCIP_EVENTTYPE_UBTIGHTENED, conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
    6845 consdata->varswithevents[consdata->nevents] = vars[j];
    6846 consdata->eventtypes[consdata->nevents] = SCIP_EVENTTYPE_UBTIGHTENED;
    6847 consdata->nevents++;
    6848 }
    6849 else
    6850 {
    6851 SCIP_CALL( SCIPcatchVarEvent(scip, vars[j], SCIP_EVENTTYPE_LBTIGHTENED, conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
    6852 consdata->varswithevents[consdata->nevents] = vars[j];
    6853 consdata->eventtypes[consdata->nevents] = SCIP_EVENTTYPE_LBTIGHTENED;
    6854 consdata->nevents++;
    6855 }
    6856 }
    6857 assert( consdata->nevents == nvars - 1 );
    6858 }
    6859 conshdlrdata->linconsevents = TRUE;
    6860 }
    6861
    6862 /* already mark that no bound has changed */
    6863 conshdlrdata->boundhaschanged = FALSE;
    6864 conshdlrdata->linconsboundschanged = FALSE;
    6865
    6866 dualreductions = conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip);
    6867
    6868 /* check each constraint */
    6869 for (c = 0; c < nconss; ++c)
    6870 {
    6871 SCIP_CONS* cons;
    6872 SCIP_CONSDATA* consdata;
    6873 SCIP_Bool cutoff;
    6874 int cnt;
    6875
    6876 *result = SCIP_DIDNOTFIND;
    6877
    6878 assert( conss[c] != NULL );
    6879 cons = conss[c];
    6880 consdata = SCIPconsGetData(cons);
    6881 assert( consdata != NULL );
    6882
    6883#ifdef SCIP_MORE_DEBUG
    6884 SCIPdebugMsg(scip, "Propagating indicator constraint <%s>.\n", SCIPconsGetName(cons) );
    6885#endif
    6886
    6887 SCIP_CALL( propIndicator(scip, cons, consdata, conshdlrdata, dualreductions, conshdlrdata->addopposite, &cutoff, &cnt) );
    6888
    6889 if ( cutoff )
    6890 {
    6891 *result = SCIP_CUTOFF;
    6892 return SCIP_OKAY;
    6893 }
    6894 ngen += cnt;
    6895 }
    6896
    6897 SCIPdebugMsg(scip, "Propagated %d domains in constraint handler <%s>.\n", ngen, SCIPconshdlrGetName(conshdlr));
    6898 if ( ngen > 0 )
    6899 *result = SCIP_REDUCEDDOM;
    6900
    6901 return SCIP_OKAY;
    6902}
    6903
    6904
    6905/** propagation conflict resolving method of constraint handler
    6906 *
    6907 * We check which bound changes were the reason for infeasibility. We use that @a inferinfo is 0 if
    6908 * the binary variable has bounds that fix it to be nonzero (these bounds are the reason). Likewise
    6909 * @a inferinfo is 1 if the slack variable has bounds that fix it to be nonzero.
    6910 */
    6911static
    6912SCIP_DECL_CONSRESPROP(consRespropIndicator)
    6913{ /*lint --e{715}*/
    6914 SCIP_CONSDATA* consdata;
    6915
    6916 assert( scip != NULL );
    6917 assert( cons != NULL );
    6918 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    6919 assert( infervar != NULL );
    6920 assert( bdchgidx != NULL );
    6921 assert( result != NULL );
    6922
    6923 *result = SCIP_DIDNOTFIND;
    6924 SCIPdebugMsg(scip, "Propagation resolution method of indicator constraint <%s>.\n", SCIPconsGetName(cons));
    6925
    6926 consdata = SCIPconsGetData(cons);
    6927 assert( consdata != NULL );
    6928 assert( inferinfo == 0 || inferinfo == 1 || inferinfo == 2 || inferinfo == 3 );
    6929 assert( consdata->linconsactive );
    6930
    6931 /* if the binary variable was the reason */
    6932 if ( inferinfo == 0 )
    6933 {
    6934 assert( SCIPgetVarLbAtIndex(scip, consdata->binvar, bdchgidx, FALSE) > 0.5 );
    6935 assert( infervar != consdata->binvar );
    6936
    6937 SCIP_CALL( SCIPaddConflictLb(scip, consdata->binvar, bdchgidx) );
    6938 }
    6939 else if ( inferinfo == 1 )
    6940 {
    6941 /* if the slack variable fixed to a positive value was the reason */
    6942 assert( infervar != consdata->slackvar );
    6943 /* Use a weaker comparison to SCIPgetVarLbAtIndex here (i.e., SCIPisPositive instead of SCIPisFeasPositive),
    6944 * because SCIPgetVarLbAtIndex might differ from the local bound at time bdchgidx by epsilon. */
    6945 assert( SCIPisPositive(scip, SCIPgetVarLbAtIndex(scip, consdata->slackvar, bdchgidx, FALSE)) );
    6946 SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, bdchgidx) );
    6947 }
    6948 else if ( inferinfo == 2 )
    6949 {
    6950 assert( SCIPisFeasZero(scip, SCIPgetVarUbAtIndex(scip, consdata->slackvar, bdchgidx, FALSE)) );
    6951 assert( SCIPconshdlrGetData(conshdlr)->dualreductions && SCIPallowStrongDualReds(scip) && SCIPallowWeakDualReds(scip) );
    6952 SCIP_CALL( SCIPaddConflictUb(scip, consdata->slackvar, bdchgidx) );
    6953 }
    6954 else
    6955 {
    6956 SCIP_VAR** linconsvars;
    6957 SCIP_Real* linconsvals;
    6958 int nlinconsvars;
    6959 int j;
    6960
    6961 assert( inferinfo == 3 );
    6962
    6963 /* mark variables in linear constraint */
    6964 nlinconsvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    6965 linconsvars = SCIPgetVarsLinear(scip, consdata->lincons);
    6966 linconsvals = SCIPgetValsLinear(scip, consdata->lincons);
    6967
    6968 for (j = 0; j < nlinconsvars; ++j)
    6969 {
    6970 if ( linconsvals[j] > 0.0 )
    6971 {
    6972 assert( ! SCIPisInfinity(scip, SCIPgetVarUbAtIndex(scip, linconsvars[j], bdchgidx, FALSE)) );
    6973 SCIP_CALL( SCIPaddConflictUb(scip, linconsvars[j], bdchgidx) );
    6974 }
    6975 else
    6976 {
    6977 assert( ! SCIPisInfinity(scip, -SCIPgetVarLbAtIndex(scip, linconsvars[j], bdchgidx, FALSE)) );
    6978 SCIP_CALL( SCIPaddConflictLb(scip, linconsvars[j], bdchgidx) );
    6979 }
    6980 }
    6981 }
    6982
    6983 *result = SCIP_SUCCESS;
    6984
    6985 return SCIP_OKAY;
    6986}
    6987
    6988
    6989/** variable rounding lock method of constraint handler
    6990 *
    6991 * The up-rounding of the binary and slack variable may violate the constraint. If the linear
    6992 * constraint is not active, we lock all variables in the depending constraint - otherwise they
    6993 * will be fixed by dual presolving methods.
    6994 */
    6995static
    6996SCIP_DECL_CONSLOCK(consLockIndicator)
    6997{
    6998 SCIP_CONSDATA* consdata;
    6999
    7000 assert( scip != NULL );
    7001 assert( conshdlr != NULL );
    7002 assert( cons != NULL );
    7003 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    7004 consdata = SCIPconsGetData(cons);
    7005 assert( consdata != NULL );
    7006 assert( consdata->binvar != NULL );
    7007
    7008#ifdef SCIP_MORE_DEBUG
    7009 SCIPdebugMsg(scip, "%socking constraint <%s>.\n", (nlocksneg < 0) || (nlockspos < 0) ? "Unl" : "L", SCIPconsGetName(cons));
    7010#endif
    7011
    7012 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->binvar, locktype, nlocksneg, nlockspos) );
    7013
    7014 if ( consdata->linconsactive )
    7015 {
    7016 assert( consdata->slackvar != NULL );
    7017
    7018 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->slackvar, locktype, nlocksneg, nlockspos) );
    7019 }
    7020 else
    7021 {
    7022 SCIP_VAR** linvars;
    7023 SCIP_Real* linvals;
    7024 SCIP_Bool haslhs;
    7025 SCIP_Bool hasrhs;
    7026 int nlinvars;
    7027 int j;
    7028
    7029 assert( consdata->lincons != NULL );
    7030 assert( consdata->slackvar == NULL );
    7031
    7032 nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
    7033 linvars = SCIPgetVarsLinear(scip, consdata->lincons);
    7034 linvals = SCIPgetValsLinear(scip, consdata->lincons);
    7035 haslhs = ! SCIPisInfinity(scip, REALABS(SCIPgetLhsLinear(scip, consdata->lincons)));
    7036 hasrhs = ! SCIPisInfinity(scip, REALABS(SCIPgetRhsLinear(scip, consdata->lincons)));
    7037
    7038 for (j = 0; j < nlinvars; ++j)
    7039 {
    7040 assert( ! SCIPisZero(scip, linvals[j]) );
    7041 if ( SCIPisPositive(scip, linvals[j]) )
    7042 {
    7043 if ( haslhs )
    7044 {
    7045 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlockspos, nlocksneg) );
    7046 }
    7047 if ( hasrhs )
    7048 {
    7049 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlocksneg, nlockspos) );
    7050 }
    7051 }
    7052 else
    7053 {
    7054 if ( haslhs )
    7055 {
    7056 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlocksneg, nlockspos) );
    7057 }
    7058 if ( hasrhs )
    7059 {
    7060 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlockspos, nlocksneg) );
    7061 }
    7062 }
    7063 }
    7064 }
    7065
    7066 return SCIP_OKAY;
    7067}
    7068
    7069
    7070/** constraint display method of constraint handler */
    7071static
    7072SCIP_DECL_CONSPRINT(consPrintIndicator)
    7073{
    7074 SCIP_CONSDATA* consdata;
    7075 SCIP_VAR* binvar;
    7076 int rhs;
    7077
    7078 assert( scip != NULL );
    7079 assert( conshdlr != NULL );
    7080 assert( cons != NULL );
    7081 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    7082
    7083 consdata = SCIPconsGetData(cons);
    7084 assert( consdata != NULL );
    7085 assert( consdata->binvar != NULL );
    7086
    7087 binvar = consdata->binvar;
    7088 rhs = 1;
    7090 {
    7091 rhs = 0;
    7092 binvar = SCIPvarGetNegatedVar(binvar);
    7093 }
    7094 SCIPinfoMessage(scip, file, "<%s> = %d", SCIPvarGetName(binvar), rhs);
    7095
    7096 assert( consdata->slackvar != NULL );
    7097 assert( consdata->lincons != NULL );
    7098 SCIPinfoMessage(scip, file, " -> <%s> = 0", SCIPvarGetName(consdata->slackvar));
    7099 SCIPinfoMessage(scip, file, " (<%s>)", SCIPconsGetName(consdata->lincons));
    7100
    7101 return SCIP_OKAY;
    7102}
    7103
    7104
    7105/** constraint copying method of constraint handler */
    7106static
    7107SCIP_DECL_CONSCOPY(consCopyIndicator)
    7108{ /*lint --e{715}*/
    7109 SCIP_CONSDATA* sourceconsdata;
    7110 SCIP_CONS* targetlincons = NULL;
    7111 SCIP_VAR* targetbinvar = NULL;
    7112 SCIP_VAR* targetslackvar = NULL;
    7113 SCIP_CONS* sourcelincons;
    7114 SCIP_CONSHDLR* conshdlrlinear;
    7115 const char* consname;
    7116
    7117 assert( scip != NULL );
    7118 assert( sourcescip != NULL );
    7119 assert( sourcecons != NULL );
    7120 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 );
    7121
    7122 *valid = TRUE;
    7123
    7124 if ( name != NULL )
    7125 consname = name;
    7126 else
    7127 consname = SCIPconsGetName(sourcecons);
    7128
    7129#ifdef SCIP_MORE_DEBUG
    7130 SCIPdebugMsg(scip, "Copying indicator constraint <%s> ...\n", consname);
    7131#endif
    7132
    7133 if ( modifiable )
    7134 {
    7135 SCIPwarningMessage(scip, "cannot create modifiable indicator constraint when trying to copy constraint <%s>,\n", SCIPconsGetName(sourcecons));
    7136 *valid = FALSE;
    7137 return SCIP_OKAY;
    7138 }
    7139
    7140 sourceconsdata = SCIPconsGetData(sourcecons);
    7141 assert( sourceconsdata != NULL );
    7142
    7143 /* get linear constraint */
    7144 sourcelincons = sourceconsdata->lincons;
    7145
    7146 /* if the constraint has been deleted -> create empty constraint (multi-aggregation might still contain slack variable, so indicator is valid) */
    7147 if ( SCIPconsIsDeleted(sourcelincons) )
    7148 {
    7149 SCIPdebugMsg(scip, "Linear constraint <%s> deleted! Create empty linear constraint.\n", SCIPconsGetName(sourceconsdata->lincons));
    7150
    7151 SCIP_CALL( SCIPcreateConsLinear(scip, &targetlincons, "dummy", 0, NULL, NULL, 0.0, SCIPinfinity(scip),
    7153 SCIP_CALL( SCIPaddCons(scip, targetlincons) );
    7154 }
    7155 else
    7156 {
    7157 /* get copied version of linear constraint */
    7158 assert( sourcelincons != NULL );
    7159 conshdlrlinear = SCIPfindConshdlr(sourcescip, "linear");
    7160 assert( conshdlrlinear != NULL );
    7161
    7162 /* if copying scip after transforming the original instance before presolving, we need to correct the linear
    7163 * constraint pointer */
    7164 if ( SCIPconsIsTransformed(sourcecons) && ! SCIPconsIsTransformed(sourcelincons) )
    7165 {
    7166 SCIP_CONS* translincons;
    7167
    7168 /* adjust the linear constraint in the original constraint (no need to release translincons) */
    7169 SCIP_CALL( SCIPgetTransformedCons(sourcescip, sourcelincons, &translincons) );
    7170 assert( translincons != NULL );
    7171 SCIP_CALL( SCIPreleaseCons(sourcescip, &sourceconsdata->lincons) );
    7172 SCIP_CALL( SCIPcaptureCons(sourcescip, translincons) );
    7173 sourceconsdata->lincons = translincons;
    7174 sourcelincons = translincons;
    7175 }
    7176
    7177 SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, sourcelincons, &targetlincons, conshdlrlinear, varmap, consmap, SCIPconsGetName(sourcelincons),
    7178 SCIPconsIsInitial(sourcelincons), SCIPconsIsSeparated(sourcelincons), SCIPconsIsEnforced(sourcelincons), SCIPconsIsChecked(sourcelincons),
    7179 SCIPconsIsPropagated(sourcelincons), SCIPconsIsLocal(sourcelincons), SCIPconsIsModifiable(sourcelincons), SCIPconsIsDynamic(sourcelincons),
    7180 SCIPconsIsRemovable(sourcelincons), SCIPconsIsStickingAtNode(sourcelincons), global, valid) );
    7181 }
    7182
    7183 /* find copied variable corresponding to binvar */
    7184 if ( *valid )
    7185 {
    7186 SCIP_VAR* sourcebinvar;
    7187
    7188 sourcebinvar = sourceconsdata->binvar;
    7189 assert( sourcebinvar != NULL );
    7190
    7191 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcebinvar, &targetbinvar, varmap, consmap, global, valid) );
    7192 }
    7193
    7194 /* find copied variable corresponding to slackvar */
    7195 if ( *valid )
    7196 {
    7197 SCIP_VAR* sourceslackvar;
    7198
    7199 sourceslackvar = sourceconsdata->slackvar;
    7200 assert( sourceslackvar != NULL );
    7201
    7202 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourceslackvar, &targetslackvar, varmap, consmap, global, valid) );
    7203 }
    7204
    7205 /* create indicator constraint */
    7206 if ( *valid )
    7207 {
    7208 assert( targetlincons != NULL );
    7209 assert( targetbinvar != NULL );
    7210 assert( targetslackvar != NULL );
    7211
    7212 /* creates indicator constraint (and captures the linear constraint) */
    7213 /* Note that the copied constraint has activeone = TRUE, since the target binary variable already was negated if needed. */
    7214 SCIP_CALL( SCIPcreateConsIndicatorGenericLinCons(scip, cons, consname, targetbinvar, targetlincons, targetslackvar, TRUE,
    7215 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
    7216 }
    7217 else
    7218 {
    7219 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "could not copy linear constraint <%s>\n", SCIPconsGetName(sourcelincons));
    7220 }
    7221
    7222 /* release copied linear constraint */
    7223 if ( targetlincons != NULL )
    7224 {
    7225 SCIP_CALL( SCIPreleaseCons(scip, &targetlincons) );
    7226 }
    7227
    7228 return SCIP_OKAY;
    7229}
    7230
    7231
    7232/** constraint parsing method of constraint handler */
    7233static
    7234SCIP_DECL_CONSPARSE(consParseIndicator)
    7235{ /*lint --e{715}*/
    7236 char binvarname[1024];
    7237 char slackvarname[1024];
    7238 char linconsname[1024];
    7239 SCIP_VAR* binvar;
    7240 SCIP_VAR* slackvar;
    7241 SCIP_CONS* lincons;
    7242 int zeroone;
    7243 int nargs;
    7244
    7245 *success = TRUE;
    7246
    7247 /* read indicator constraint */
    7248 /* coverity[secure_coding] */
    7249 nargs = sscanf(str, " <%1023[^>]> = %d -> <%1023[^>]> = 0 (<%1023[^>]>)", binvarname, &zeroone, slackvarname, linconsname);
    7250
    7251 /* downward compatible: accept missing linear constraint at end */
    7252 if ( nargs != 3 && nargs != 4 )
    7253 {
    7254 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0 (<lincons>).\n%s\n", str);
    7255 *success = FALSE;
    7256 return SCIP_OKAY;
    7257 }
    7258
    7259 if ( zeroone != 0 && zeroone != 1 )
    7260 {
    7261 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0.\n%s\n", str);
    7262 *success = FALSE;
    7263 return SCIP_OKAY;
    7264 }
    7265
    7266 /* get binary variable */
    7267 binvar = SCIPfindVar(scip, binvarname);
    7268 if ( binvar == NULL )
    7269 {
    7270 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", binvarname);
    7271 *success = FALSE;
    7272 return SCIP_OKAY;
    7273 }
    7274 /* check whether we need the complemented variable */
    7275 if ( zeroone == 0 )
    7276 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
    7277
    7278 /* get slack variable */
    7279 slackvar = SCIPfindVar(scip, slackvarname);
    7280 if ( slackvar == NULL )
    7281 {
    7282 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", slackvarname);
    7283 *success = FALSE;
    7284 return SCIP_OKAY;
    7285 }
    7286
    7287 /* determine linear constraint */
    7288 if ( nargs == 4 )
    7289 {
    7290 lincons = SCIPfindCons(scip, linconsname);
    7291 if ( lincons == NULL )
    7292 {
    7293 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown constraint <%s>\n", linconsname);
    7294 *success = FALSE;
    7295 return SCIP_OKAY;
    7296 }
    7297 if ( strncmp(SCIPconshdlrGetName(SCIPconsGetHdlr(lincons)), "linear", 6) != 0 )
    7298 {
    7299 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "constraint <%s> is not linear\n", linconsname);
    7300 *success = FALSE;
    7301 return SCIP_OKAY;
    7302 }
    7303 }
    7304 else
    7305 {
    7306 const char* posstr;
    7307
    7308 /* for backward compability try to determine name of linear constraint from variables names */
    7309 assert( nargs == 3 );
    7310
    7311 /* find matching linear constraint */
    7312 posstr = strstr(slackvarname, "indslack");
    7313 if ( posstr == NULL )
    7314 {
    7315 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "strange slack variable name: <%s>\n", slackvarname);
    7316 *success = FALSE;
    7317 return SCIP_OKAY;
    7318 }
    7319
    7320 /* overwrite binvarname: set up name for linear constraint */
    7321 (void) SCIPsnprintf(binvarname, 1023, "indlin%s", posstr+8);
    7322
    7323 lincons = SCIPfindCons(scip, binvarname);
    7324 if ( lincons == NULL )
    7325 {
    7326 /* if not found - check without indlin */
    7327 (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+9);
    7328 lincons = SCIPfindCons(scip, binvarname);
    7329
    7330 if ( lincons == NULL )
    7331 {
    7332 /* if not found - check without indrhs or indlhs */
    7333 (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+16);
    7334 lincons = SCIPfindCons(scip, binvarname);
    7335
    7336 if( lincons == NULL )
    7337 {
    7338 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: unknown linear constraint <indlin%s>, <%s> or <%s>.\n",
    7339 name, posstr+8, posstr+9, posstr+16);
    7340 *success = FALSE;
    7341 return SCIP_OKAY;
    7342 }
    7343 }
    7344 }
    7345 }
    7346 assert( lincons != NULL );
    7347
    7348 /* check correct linear constraint */
    7349 if ( ! SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, lincons)) && ! SCIPisInfinity(scip, SCIPgetRhsLinear(scip, lincons)) )
    7350 {
    7351 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: linear constraint is ranged or equation.\n", name);
    7352 *success = FALSE;
    7353 return SCIP_OKAY;
    7354 }
    7355
    7356 /* create indicator constraint */
    7357 SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
    7358 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
    7359
    7360 return SCIP_OKAY;
    7361}
    7362
    7363
    7364/** constraint enabling notification method of constraint handler */
    7365static
    7366SCIP_DECL_CONSENABLE(consEnableIndicator)
    7367{
    7368 SCIP_CONSHDLRDATA* conshdlrdata;
    7369 SCIP_CONSDATA* consdata;
    7370
    7371 assert( scip != NULL );
    7372 assert( conshdlr != NULL );
    7373 assert( cons != NULL );
    7374 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    7375
    7376#ifdef SCIP_MORE_DEBUG
    7377 SCIPdebugMsg(scip, "Enabling constraint <%s>.\n", SCIPconsGetName(cons));
    7378#endif
    7379
    7380 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7381 assert( conshdlrdata != NULL );
    7382
    7383 consdata = SCIPconsGetData(cons);
    7384 assert( consdata != NULL );
    7385
    7386 if ( conshdlrdata->altlp != NULL )
    7387 {
    7388 assert( conshdlrdata->sepaalternativelp );
    7389
    7390 if ( consdata->colindex >= 0 )
    7391 {
    7392 SCIP_CALL( unfixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
    7393 }
    7394 }
    7395
    7396 return SCIP_OKAY;
    7397}
    7398
    7399
    7400/** constraint disabling notification method of constraint handler */
    7401static
    7402SCIP_DECL_CONSDISABLE(consDisableIndicator)
    7403{
    7404 SCIP_CONSHDLRDATA* conshdlrdata;
    7405
    7406 assert( scip != NULL );
    7407 assert( conshdlr != NULL );
    7408 assert( cons != NULL );
    7409 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    7410
    7411#ifdef SCIP_MORE_DEBUG
    7412 SCIPdebugMsg(scip, "Disabling constraint <%s>.\n", SCIPconsGetName(cons));
    7413#endif
    7414
    7415 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7416 assert( conshdlrdata != NULL );
    7417
    7418 if ( conshdlrdata->altlp != NULL )
    7419 {
    7420 SCIP_CONSDATA* consdata;
    7421
    7422 consdata = SCIPconsGetData(cons);
    7423 assert( consdata != NULL );
    7424 assert( conshdlrdata->sepaalternativelp );
    7425
    7426 if ( consdata->colindex >= 0 )
    7427 {
    7428 SCIP_CALL( fixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
    7429 }
    7430 }
    7431
    7432 return SCIP_OKAY;
    7433}
    7434
    7435
    7436/** constraint method of constraint handler which returns the variables (if possible) */
    7437static
    7438SCIP_DECL_CONSGETVARS(consGetVarsIndicator)
    7439{ /*lint --e{715}*/
    7440 SCIP_CONSDATA* consdata;
    7441 int nvars = 0;
    7442
    7443 assert( scip != NULL );
    7444 assert( cons != NULL );
    7445 assert( vars != NULL );
    7446 assert( success != NULL );
    7447
    7448 if ( varssize < 0 )
    7449 return SCIP_INVALIDDATA;
    7450 assert( varssize >= 0 );
    7451
    7452 (*success) = TRUE;
    7453
    7454 /* if indicator constraint is already deleted */
    7455 if ( SCIPconsIsDeleted(cons) )
    7456 return SCIP_OKAY;
    7457
    7458 consdata = SCIPconsGetData(cons);
    7459 assert( consdata != NULL );
    7460 assert( consdata->lincons != NULL );
    7461
    7462 if ( consdata->binvar != NULL )
    7463 {
    7464 assert( varssize > 0 );
    7465 vars[nvars++] = consdata->binvar;
    7466 }
    7467 if ( consdata->slackvar != NULL )
    7468 {
    7469 assert( varssize > nvars );
    7470 vars[nvars++] = consdata->slackvar;
    7471 }
    7472
    7473 /* if linear constraint of indicator is already deleted */
    7474 if ( SCIPconsIsDeleted(consdata->lincons) )
    7475 return SCIP_OKAY;
    7476
    7477 SCIP_CALL( SCIPgetConsVars(scip, consdata->lincons, &(vars[nvars]), varssize - nvars, success) );
    7478
    7479 return SCIP_OKAY;
    7480}
    7481
    7482
    7483/** constraint method of constraint handler which returns the number of variables (if possible) */
    7484static
    7485SCIP_DECL_CONSGETNVARS(consGetNVarsIndicator)
    7486{ /*lint --e{715}*/
    7487 SCIP_CONSDATA* consdata;
    7488 int nlinvars;
    7489
    7490 assert( scip != NULL );
    7491 assert( cons != NULL );
    7492 assert( nvars != NULL );
    7493 assert( success != NULL );
    7494
    7495 *success = TRUE;
    7496 *nvars = 0;
    7497
    7498 /* if indicator constraint is already deleted */
    7499 if ( SCIPconsIsDeleted(cons) )
    7500 return SCIP_OKAY;
    7501
    7502 consdata = SCIPconsGetData(cons);
    7503 assert( consdata != NULL );
    7504 assert( consdata->lincons != NULL );
    7505
    7506 if ( consdata->binvar != NULL )
    7507 ++(*nvars);
    7508 if ( consdata->slackvar != NULL )
    7509 ++(*nvars);
    7510
    7511 /* if linear constraint of indicator is already deleted */
    7512 if ( SCIPconsIsDeleted(consdata->lincons) )
    7513 return SCIP_OKAY;
    7514
    7515 SCIP_CALL( SCIPgetConsNVars(scip, consdata->lincons, &nlinvars, success) );
    7516
    7517 if ( *success )
    7518 {
    7519 assert( nlinvars >= 0 );
    7520 *nvars += nlinvars;
    7521 }
    7522
    7523 return SCIP_OKAY;
    7524}
    7525
    7526
    7527/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
    7528static
    7529SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsIndicator)
    7530{
    7531 SCIP_CONS** indconss;
    7532 int nindconss;
    7533 int c;
    7534 SCIP_VAR* bestvar = NULL;
    7535 SCIP_Bool bestvarroundup = FALSE;
    7536 SCIP_Real bestscore = SCIP_REAL_MIN;
    7537
    7538 assert(scip != NULL);
    7539 assert(conshdlr != NULL);
    7540 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    7541 assert(diveset != NULL);
    7542 assert(success != NULL);
    7543 assert(infeasible != NULL);
    7544
    7545 *success = FALSE;
    7546 *infeasible = FALSE;
    7547
    7548 indconss = SCIPconshdlrGetConss(conshdlr);
    7549 nindconss = SCIPconshdlrGetNConss(conshdlr);
    7550
    7551 /* loop over indicator constraints and score indicator variables with already integral solution value */
    7552 for (c = 0; c < nindconss; ++c)
    7553 {
    7554 /* check whether constraint is violated */
    7555 if ( SCIPisViolatedIndicator(scip, indconss[c], sol) )
    7556 {
    7557 SCIP_VAR* binvar;
    7558 SCIP_Real solval;
    7559
    7560 binvar = SCIPgetBinaryVarIndicator(indconss[c]);
    7561 solval = SCIPgetSolVal(scip, sol, binvar);
    7562
    7563 /* we only treat indicator variables with integral solution values that are not yet fixed */
    7564 if ( SCIPisFeasIntegral(scip, solval) && SCIPvarGetLbLocal(binvar) < SCIPvarGetUbLocal(binvar) - 0.5 )
    7565 {
    7566 SCIP_Real score;
    7567 SCIP_Bool roundup;
    7568
    7569 SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_INTEGRALITY, binvar, solval, 0.0,
    7570 &score, &roundup) );
    7571
    7572 /* best candidate maximizes the score */
    7573 if ( score > bestscore )
    7574 {
    7575 bestscore = score;
    7576 *success = TRUE;
    7577 bestvar = binvar;
    7578 bestvarroundup = roundup;
    7579 }
    7580 }
    7581 }
    7582 }
    7583
    7584 assert(! *success || bestvar != NULL);
    7585
    7586 if ( *success )
    7587 {
    7588 /* if the diving score voted for fixing the best variable to 1.0, we add this as the preferred bound change */
    7589 SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_UPWARDS, 1.0, bestvarroundup) );
    7590 SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_DOWNWARDS, 0.0, ! bestvarroundup) );
    7591 }
    7592
    7593 return SCIP_OKAY;
    7594}
    7595
    7596/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
    7597static
    7598SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphIndicator)
    7599{ /*lint --e{715}*/
    7600 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
    7601
    7602 return SCIP_OKAY;
    7603}
    7604
    7605/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
    7606static
    7607SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphIndicator)
    7608{ /*lint --e{715}*/
    7609 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
    7610
    7611 return SCIP_OKAY;
    7612}
    7613
    7614/* ---------------- Constraint specific interface methods ---------------- */
    7615
    7616/** creates the handler for indicator constraints and includes it in SCIP */
    7618 SCIP* scip /**< SCIP data structure */
    7619 )
    7620{
    7621 SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
    7622 SCIP_CONFLICTHDLR* conflicthdlr;
    7623 SCIP_CONSHDLRDATA* conshdlrdata;
    7624 SCIP_CONSHDLR* conshdlr;
    7625
    7626 /* create constraint handler data (used in conflicthdlrdata) */
    7627 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
    7628
    7629 /* create event handler for bound change events */
    7630 conshdlrdata->eventhdlrbound = NULL;
    7632 eventExecIndicatorBound, NULL) );
    7633 assert(conshdlrdata->eventhdlrbound != NULL);
    7634
    7635 /* create event handler for bound change events on linear constraint */
    7636 conshdlrdata->eventhdlrlinconsbound = NULL;
    7638 eventExecIndicatorLinconsBound, NULL) );
    7639 assert(conshdlrdata->eventhdlrlinconsbound != NULL);
    7640
    7641 /* create event handler for restart events */
    7642 conshdlrdata->eventhdlrrestart = NULL;
    7644 eventExecIndicatorRestart, NULL) );
    7645 assert( conshdlrdata->eventhdlrrestart != NULL );
    7646
    7647 conshdlrdata->heurtrysol = NULL;
    7648 conshdlrdata->sepaalternativelp = DEFAULT_SEPAALTERNATIVELP;
    7649 conshdlrdata->nolinconscont = DEFAULT_NOLINCONSCONT;
    7650 conshdlrdata->forcerestart = DEFAULT_FORCERESTART;
    7651 conshdlrdata->binvarhash = NULL;
    7652 conshdlrdata->binslackvarhash = NULL;
    7653
    7654 /* initialize constraint handler data */
    7655 initConshdlrData(scip, conshdlrdata);
    7656
    7657 /* the following three variables cannot be initialized in the above method, because initConshdlrData() is also called
    7658 * in the CONSINIT callback, but these variables might be used even before the is ccallback is called, so we would
    7659 * lose the data added before calling this callback */
    7660 conshdlrdata->addlincons = NULL;
    7661 conshdlrdata->naddlincons = 0;
    7662 conshdlrdata->maxaddlincons = 0;
    7663
    7664 /* include constraint handler */
    7667 consEnfolpIndicator, consEnfopsIndicator, consCheckIndicator, consLockIndicator,
    7668 conshdlrdata) );
    7669
    7670 assert( conshdlr != NULL );
    7671
    7672 /* set non-fundamental callbacks via specific setter functions */
    7673 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyIndicator, consCopyIndicator) );
    7674 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteIndicator) );
    7675 SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableIndicator) );
    7676 SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableIndicator) );
    7677 SCIP_CALL( SCIPsetConshdlrGetDiveBdChgs(scip, conshdlr, consGetDiveBdChgsIndicator) );
    7678 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitIndicator) );
    7679 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolIndicator) );
    7680 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeIndicator) );
    7681 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsIndicator) );
    7682 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsIndicator) );
    7683 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitIndicator) );
    7684 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreIndicator) );
    7685 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolIndicator) );
    7686 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpIndicator) );
    7687 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseIndicator) );
    7689 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintIndicator) );
    7692 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropIndicator) );
    7693 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpIndicator, consSepasolIndicator, CONSHDLR_SEPAFREQ,
    7695 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransIndicator) );
    7696 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxIndicator) );
    7697 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphIndicator) );
    7698 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphIndicator) );
    7699
    7700 /* add upgrading method */
    7701 if ( SCIPfindConshdlr(scip, "linear") != NULL )
    7702 {
    7703 /* include the linear constraint upgrade in the linear constraint handler */
    7705 }
    7706
    7707 /* create conflict handler data */
    7708 SCIP_CALL( SCIPallocBlockMemory(scip, &conflicthdlrdata) );
    7709 conflicthdlrdata->conshdlrdata = conshdlrdata;
    7710 conflicthdlrdata->conshdlr = conshdlr;
    7711 assert( conflicthdlrdata->conshdlr != NULL );
    7712
    7713 /* create conflict handler for indicator constraints */
    7715 conflictExecIndicator, conflicthdlrdata) );
    7716
    7717 SCIP_CALL( SCIPsetConflicthdlrFree(scip, conflicthdlr, conflictFreeIndicator) );
    7718
    7719 /* add indicator constraint handler parameters */
    7721 "constraints/indicator/branchindicators",
    7722 "Branch on indicator constraints in enforcing?",
    7723 &conshdlrdata->branchindicators, TRUE, DEFAULT_BRANCHINDICATORS, NULL, NULL) );
    7724
    7726 "constraints/indicator/genlogicor",
    7727 "Generate logicor constraints instead of cuts?",
    7728 &conshdlrdata->genlogicor, TRUE, DEFAULT_GENLOGICOR, NULL, NULL) );
    7729
    7731 "constraints/indicator/addcoupling",
    7732 "Add coupling constraints or rows if big-M is small enough?",
    7733 &conshdlrdata->addcoupling, TRUE, DEFAULT_ADDCOUPLING, NULL, NULL) );
    7734
    7736 "constraints/indicator/maxcouplingvalue",
    7737 "maximum coefficient for binary variable in coupling constraint",
    7738 &conshdlrdata->maxcouplingvalue, TRUE, DEFAULT_MAXCOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
    7739
    7741 "constraints/indicator/addcouplingcons",
    7742 "Add initial variable upper bound constraints, if 'addcoupling' is true?",
    7743 &conshdlrdata->addcouplingcons, TRUE, DEFAULT_ADDCOUPLINGCONS, NULL, NULL) );
    7744
    7746 "constraints/indicator/sepacouplingcuts",
    7747 "Should the coupling inequalities be separated dynamically?",
    7748 &conshdlrdata->sepacouplingcuts, TRUE, DEFAULT_SEPACOUPLINGCUTS, NULL, NULL) );
    7749
    7751 "constraints/indicator/sepacouplinglocal",
    7752 "Allow to use local bounds in order to separate coupling inequalities?",
    7753 &conshdlrdata->sepacouplinglocal, TRUE, DEFAULT_SEPACOUPLINGLOCAL, NULL, NULL) );
    7754
    7756 "constraints/indicator/sepacouplingvalue",
    7757 "maximum coefficient for binary variable in separated coupling constraint",
    7758 &conshdlrdata->sepacouplingvalue, TRUE, DEFAULT_SEPACOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
    7759
    7761 "constraints/indicator/sepaperspective",
    7762 "Separate cuts based on perspective formulation?",
    7763 &conshdlrdata->sepaperspective, TRUE, DEFAULT_SEPAPERSPECTIVE, NULL, NULL) );
    7764
    7766 "constraints/indicator/sepapersplocal",
    7767 "Allow to use local bounds in order to separate perspective cuts?",
    7768 &conshdlrdata->sepapersplocal, TRUE, DEFAULT_SEPAPERSPLOCAL, NULL, NULL) );
    7769
    7771 "constraints/indicator/maxsepanonviolated",
    7772 "maximal number of separated non violated IISs, before separation is stopped",
    7773 &conshdlrdata->maxsepanonviolated, FALSE, DEFAULT_MAXSEPANONVIOLATED, 0, INT_MAX, NULL, NULL) );
    7774
    7776 "constraints/indicator/updatebounds",
    7777 "Update bounds of original variables for separation?",
    7778 &conshdlrdata->updatebounds, TRUE, DEFAULT_UPDATEBOUNDS, NULL, NULL) );
    7779
    7781 "constraints/indicator/maxconditionaltlp",
    7782 "maximum estimated condition of the solution basis matrix of the alternative LP to be trustworthy (0.0 to disable check)",
    7783 &conshdlrdata->maxconditionaltlp, TRUE, DEFAULT_MAXCONDITIONALTLP, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    7784
    7786 "constraints/indicator/maxsepacuts",
    7787 "maximal number of cuts separated per separation round",
    7788 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
    7789
    7791 "constraints/indicator/maxsepacutsroot",
    7792 "maximal number of cuts separated per separation round in the root node",
    7793 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
    7794
    7796 "constraints/indicator/removeindicators",
    7797 "Remove indicator constraint if corresponding variable bound constraint has been added?",
    7798 &conshdlrdata->removeindicators, TRUE, DEFAULT_REMOVEINDICATORS, NULL, NULL) );
    7799
    7801 "constraints/indicator/generatebilinear",
    7802 "Do not generate indicator constraint, but a bilinear constraint instead?",
    7803 &conshdlrdata->generatebilinear, TRUE, DEFAULT_GENERATEBILINEAR, NULL, NULL) );
    7804
    7806 "constraints/indicator/scaleslackvar",
    7807 "Scale slack variable coefficient at construction time?",
    7808 &conshdlrdata->scaleslackvar, TRUE, DEFAULT_SCALESLACKVAR, NULL, NULL) );
    7809
    7811 "constraints/indicator/trysolutions",
    7812 "Try to make solutions feasible by setting indicator variables?",
    7813 &conshdlrdata->trysolutions, TRUE, DEFAULT_TRYSOLUTIONS, NULL, NULL) );
    7814
    7816 "constraints/indicator/enforcecuts",
    7817 "In enforcing try to generate cuts (only if sepaalternativelp is true)?",
    7818 &conshdlrdata->enforcecuts, TRUE, DEFAULT_ENFORCECUTS, NULL, NULL) );
    7819
    7821 "constraints/indicator/dualreductions",
    7822 "Should dual reduction steps be performed?",
    7823 &conshdlrdata->dualreductions, TRUE, DEFAULT_DUALREDUCTIONS, NULL, NULL) );
    7824
    7826 "constraints/indicator/addopposite",
    7827 "Add opposite inequality in nodes in which the binary variable has been fixed to 0?",
    7828 &conshdlrdata->addopposite, TRUE, DEFAULT_ADDOPPOSITE, NULL, NULL) );
    7829
    7831 "constraints/indicator/conflictsupgrade",
    7832 "Try to upgrade bounddisjunction conflicts by replacing slack variables?",
    7833 &conshdlrdata->conflictsupgrade, TRUE, DEFAULT_CONFLICTSUPGRADE, NULL, NULL) );
    7834
    7836 "constraints/indicator/restartfrac",
    7837 "fraction of binary variables that need to be fixed before restart occurs (in forcerestart)",
    7838 &conshdlrdata->restartfrac, TRUE, DEFAULT_RESTARTFRAC, 0.0, 1.0, NULL, NULL) );
    7839
    7841 "constraints/indicator/useotherconss",
    7842 "Collect other constraints to alternative LP?",
    7843 &conshdlrdata->useotherconss, TRUE, DEFAULT_USEOTHERCONSS, NULL, NULL) );
    7844
    7846 "constraints/indicator/useobjectivecut",
    7847 "Use objective cut with current best solution to alternative LP?",
    7848 &conshdlrdata->useobjectivecut, TRUE, DEFAULT_USEOBJECTIVECUT, NULL, NULL) );
    7849
    7851 "constraints/indicator/trysolfromcover",
    7852 "Try to construct a feasible solution from a cover?",
    7853 &conshdlrdata->trysolfromcover, TRUE, DEFAULT_TRYSOLFROMCOVER, NULL, NULL) );
    7854
    7856 "constraints/indicator/upgradelinear",
    7857 "Try to upgrade linear constraints to indicator constraints?",
    7858 &conshdlrdata->upgradelinear, TRUE, DEFAULT_UPGRADELINEAR, NULL, NULL) );
    7859
    7861 "constraints/indicator/usesameslackvar",
    7862 "Use same slack variable for indicator constraints with common binary variable?",
    7863 &conshdlrdata->usesameslackvar, TRUE, DEFAULT_USESAMESLACKVAR, NULL, NULL) );
    7864
    7865 /* parameters that should not be changed after problem stage: */
    7867 "constraints/indicator/sepaalternativelp",
    7868 "Separate using the alternative LP?",
    7869 &conshdlrdata->sepaalternativelp_, TRUE, DEFAULT_SEPAALTERNATIVELP, paramChangedIndicator, NULL) );
    7870
    7872 "constraints/indicator/forcerestart",
    7873 "Force restart if absolute gap is 1 or enough binary variables have been fixed?",
    7874 &conshdlrdata->forcerestart_, TRUE, DEFAULT_FORCERESTART, paramChangedIndicator, NULL) );
    7875
    7877 "constraints/indicator/nolinconscont",
    7878 "Decompose problem (do not generate linear constraint if all variables are continuous)?",
    7879 &conshdlrdata->nolinconscont_, TRUE, DEFAULT_NOLINCONSCONT, paramChangedIndicator, NULL) );
    7880
    7881 return SCIP_OKAY;
    7882}
    7883
    7884/** creates and captures an indicator constraint
    7885 *
    7886 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    7887 * procedures reading an instance.
    7888 *
    7889 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    7890 */
    7892 SCIP* scip, /**< SCIP data structure */
    7893 SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
    7894 const char* name, /**< name of constraint */
    7895 SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
    7896 int nvars, /**< number of variables in the inequality */
    7897 SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
    7898 SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
    7899 SCIP_Real rhs, /**< rhs of the inequality */
    7900 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    7901 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    7902 * Usually set to TRUE. */
    7903 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    7904 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    7905 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    7906 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    7907 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    7908 * Usually set to TRUE. */
    7909 SCIP_Bool local, /**< is constraint only valid locally?
    7910 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    7911 SCIP_Bool dynamic, /**< is constraint subject to aging?
    7912 * Usually set to FALSE. Set to TRUE for own cuts which
    7913 * are separated as constraints. */
    7914 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    7915 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    7916 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    7917 * if it may be moved to a more global node?
    7918 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    7919 )
    7920{
    7921 return SCIPcreateConsIndicatorGeneric(scip, cons, name, binvar, nvars, vars, vals, rhs, TRUE, TRUE, initial,
    7922 separate, enforce, check, propagate, local, dynamic, removable, stickingatnode);
    7923}
    7924
    7925/** creates and captures a indicator constraint in a more generic version.
    7926 *
    7927 * The key difference from SCIPcreateConsIndicator() is the activeone and lessthanineq Booleans.
    7928 * If \f$z = o\f$, with \f$o\f$ the activeone flag, then:
    7929 * 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$.
    7930 * The underlying linear constraint is always created as a less-than inequality.
    7931 */
    7933 SCIP* scip, /**< SCIP data structure */
    7934 SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
    7935 const char* name, /**< name of constraint */
    7936 SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
    7937 int nvars, /**< number of variables in the inequality */
    7938 SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
    7939 SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
    7940 SCIP_Real rhs, /**< rhs of the inequality */
    7941 SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
    7942 SCIP_Bool lessthanineq, /**< is the linear constraint a less than RHS (TRUE) or greater than RHS (FALSE)? */
    7943 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    7944 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    7945 * Usually set to TRUE. */
    7946 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    7947 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    7948 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    7949 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    7950 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    7951 * Usually set to TRUE. */
    7952 SCIP_Bool local, /**< is constraint only valid locally?
    7953 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    7954 SCIP_Bool dynamic, /**< is constraint subject to aging?
    7955 * Usually set to FALSE. Set to TRUE for own cuts which
    7956 * are separated as constraints. */
    7957 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    7958 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    7959 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    7960 * if it may be moved to a more global node?
    7961 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    7962 )
    7963{
    7964 SCIP_CONSHDLR* conshdlr;
    7965 SCIP_CONSHDLRDATA* conshdlrdata;
    7966 SCIP_CONSDATA* consdata = NULL;
    7967 SCIP_CONS* lincons;
    7968 SCIP_VAR* slackvar = NULL;
    7969 SCIP_VAR* binvarinternal;
    7970 SCIP_Bool modifiable = FALSE;
    7971 SCIP_Bool linconsactive;
    7972 SCIP_Bool integral = TRUE;
    7973 SCIP_Real* valscopy;
    7974 SCIP_Real absvalsum = 0.0;
    7975 char s[SCIP_MAXSTRLEN];
    7976 int v;
    7977
    7978 if ( nvars < 0 )
    7979 {
    7980 SCIPerrorMessage("Indicator constraint <%s> needs nonnegative number of variables in linear constraint.\n", name);
    7981 return SCIP_INVALIDDATA;
    7982 }
    7983
    7984 /* find the indicator constraint handler */
    7985 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    7986 if ( conshdlr == NULL )
    7987 {
    7988 SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
    7989 return SCIP_PLUGINNOTFOUND;
    7990 }
    7991
    7992 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7993 assert( conshdlrdata != NULL );
    7994
    7995 if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
    7996 {
    7997 SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
    7998 return SCIP_INVALIDDATA;
    7999 }
    8000
    8001 if ( conshdlrdata->nolinconscont && conshdlrdata->generatebilinear )
    8002 {
    8003 SCIPerrorMessage("constraint handler <%s>: parameters <nolinconscont> and <generatebilinear> cannot both be true.\n", CONSHDLR_NAME);
    8004 return SCIP_INVALIDDATA;
    8005 }
    8006
    8007 valscopy = NULL;
    8008 if ( lessthanineq )
    8009 valscopy = vals;
    8010 else
    8011 {
    8012 /* flip coefficients and RHS of indicator */
    8013 SCIP_CALL( SCIPallocBufferArray(scip, &valscopy, nvars) );
    8014 for ( v = 0; v < nvars; ++v )
    8015 valscopy[v] = -vals[v];
    8016 rhs = -rhs;
    8017 }
    8018 assert( nvars == 0 || valscopy != NULL );
    8019
    8020 /* determine integrality of slack variable and whether problem is decomposed if no variables are integral */
    8021 linconsactive = !conshdlrdata->nolinconscont;
    8022 for ( v = 0; v < nvars; ++v )
    8023 {
    8024 if ( conshdlrdata->scaleslackvar )
    8025 absvalsum += REALABS(valscopy[v]);
    8026 if ( SCIPvarIsIntegral(vars[v]) )
    8027 {
    8028 linconsactive = TRUE;
    8029 if ( !conshdlrdata->scaleslackvar && !integral )
    8030 break;
    8031 if ( !SCIPisIntegral(scip, valscopy[v]) )
    8032 {
    8033 integral = FALSE;
    8034 if ( !conshdlrdata->scaleslackvar )
    8035 break;
    8036 }
    8037 }
    8038 else
    8039 {
    8040 integral = FALSE;
    8041 if ( !conshdlrdata->scaleslackvar && linconsactive )
    8042 break;
    8043 }
    8044 }
    8045
    8046 /* if active on 0, a provided binary variable is negated */
    8047 if ( activeone || binvar == NULL )
    8048 binvarinternal = binvar;
    8049 else
    8050 {
    8051 assert( SCIPvarIsBinary(binvar) );
    8052 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
    8053 }
    8054
    8055 /* Check whether the same slack variable should be use for constraints with a common binary variable. This can
    8056 * reduce the size of the problem, because only one coupling constraint is needed. However, it is less tight. */
    8057 if ( binvarinternal != NULL )
    8058 {
    8059 /* make sure that the hashmap exists if we want to use the same slack variable */
    8060 if ( conshdlrdata->usesameslackvar && conshdlrdata->binslackvarhash == NULL )
    8061 {
    8062 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binslackvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
    8063 }
    8064
    8065 if ( conshdlrdata->binslackvarhash != NULL && SCIPhashmapExists(conshdlrdata->binslackvarhash, (void*) binvarinternal) )
    8066 {
    8067 slackvar = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->binslackvarhash, (void*) binvarinternal);
    8068
    8069 /* make sure that the type of the slack is as general as necessary */
    8070 if ( !integral && SCIPvarIsIntegral(slackvar) )
    8071 {
    8072 SCIP_Bool infeasible;
    8073
    8074 SCIP_CALL( SCIPchgVarType(scip, slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
    8075 assert( !infeasible );
    8076 SCIP_CALL( SCIPchgVarImplType(scip, slackvar, SCIP_IMPLINTTYPE_NONE, &infeasible) );
    8077 assert( !infeasible );
    8078 }
    8079
    8080 SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
    8081 }
    8082 else
    8083 {
    8084 /* create slack variable */
    8085 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
    8086 SCIP_CALL( SCIPcreateVarImpl(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0,
    8088 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    8089
    8090 SCIP_CALL( SCIPaddVar(scip, slackvar) );
    8091
    8092 /* mark slack variable not to be multi-aggregated */
    8094
    8095 if ( conshdlrdata->binslackvarhash != NULL )
    8096 {
    8097 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binslackvarhash, (void*) binvarinternal, (void*) slackvar) );
    8098 }
    8099 }
    8100 }
    8101 else
    8102 {
    8103 /* create slack variable */
    8104 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
    8105 SCIP_CALL( SCIPcreateVarImpl(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0,
    8107 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    8108
    8109 SCIP_CALL( SCIPaddVar(scip, slackvar) );
    8110
    8111 /* mark slack variable not to be multi-aggregated */
    8113 }
    8114 assert( slackvar != NULL );
    8115
    8116 /* create linear constraint */
    8117 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indlin_%s", name);
    8118
    8119 /* if the linear constraint should be activated (lincons is captured) */
    8120 if ( linconsactive )
    8121 {
    8122 /* the constraint is initial if initial is true, enforced, separated, and checked */
    8123 SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, s, nvars, vars, valscopy, -SCIPinfinity(scip), rhs,
    8124 initial, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
    8125 }
    8126 else
    8127 {
    8128 /* create non-active linear constraint, which is neither initial, nor enforced, nor separated, nor checked */
    8129 SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, s, nvars, vars, valscopy, -SCIPinfinity(scip), rhs,
    8131 }
    8132
    8133 if ( ! lessthanineq )
    8134 SCIPfreeBufferArray(scip, &valscopy);
    8135
    8136 /* mark linear constraint not to be upgraded - otherwise we loose control over it */
    8137 SCIPconsAddUpgradeLocks(lincons, 1);
    8138 assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
    8139
    8140 /* add slack variable */
    8141 if ( conshdlrdata->scaleslackvar && nvars > 0 )
    8142 {
    8143 absvalsum = absvalsum/((SCIP_Real) nvars);
    8144 if ( integral )
    8145 absvalsum = SCIPceil(scip, absvalsum);
    8146 if ( SCIPisZero(scip, absvalsum) )
    8147 absvalsum = 1.0;
    8148 SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, -absvalsum) );
    8149 }
    8150 else
    8151 {
    8152 SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, -1.0) );
    8153 }
    8154 SCIP_CALL( SCIPaddCons(scip, lincons) );
    8155
    8156 /* check whether we should generate a bilinear constraint instead of an indicator constraint */
    8157 if ( conshdlrdata->generatebilinear )
    8158 {
    8159 assert( linconsactive );
    8160
    8161 SCIP_Real val = 1.0;
    8162
    8163 /* create a quadratic constraint with a single bilinear term - note that cons is used */
    8164 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
    8166 }
    8167 else
    8168 {
    8169 /* create constraint data */
    8170 SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrrestart,
    8171 binvar, activeone, lessthanineq, slackvar, lincons, linconsactive) );
    8172 assert( consdata != NULL );
    8173 /* do not need to capture slack variable and linear constraint here */
    8174
    8175 /* create constraint */
    8176 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    8177 local, modifiable, dynamic, removable, stickingatnode) );
    8178
    8179 if ( SCIPisTransformed(scip) )
    8180 {
    8181 /* catch local bound change events on binary variable */
    8182 if ( linconsactive )
    8183 {
    8184 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8185 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8186 }
    8187
    8188 /* make sure that binary variable hash exists */
    8189 if ( conshdlrdata->sepaalternativelp )
    8190 {
    8191 if ( conshdlrdata->binvarhash == NULL )
    8192 {
    8193 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
    8194 }
    8195
    8196 /* check whether binary variable is present: note that a binary variable might appear several times, but this seldomly happens. */
    8197 assert( conshdlrdata->binvarhash != NULL );
    8198 if ( ! SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarinternal) )
    8199 {
    8200 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binvarhash, (void*) binvarinternal, (void*) (*cons)) );
    8201 }
    8202 }
    8203 }
    8204 }
    8205
    8206 return SCIP_OKAY;
    8207}
    8208
    8209/** creates and captures an indicator constraint in its most basic version, i. e., all constraint flags are set to their
    8210 * basic value as explained for the method SCIPcreateConsIndicator(); all flags can be set via
    8211 * SCIPsetConsFLAGNAME-methods in scip.h
    8212 *
    8213 * @see SCIPcreateConsIndicator() for information about the basic constraint flag configuration
    8214 *
    8215 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8216 */
    8218 SCIP* scip, /**< SCIP data structure */
    8219 SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
    8220 const char* name, /**< name of constraint */
    8221 SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
    8222 int nvars, /**< number of variables in the inequality */
    8223 SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
    8224 SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
    8225 SCIP_Real rhs /**< rhs of the inequality */
    8226 )
    8227{
    8228 assert( scip != NULL );
    8229
    8230 SCIP_CALL( SCIPcreateConsIndicator(scip, cons, name, binvar, nvars, vars, vals, rhs,
    8232
    8233 return SCIP_OKAY;
    8234}
    8235
    8236/** creates and captures an indicator constraint with given linear constraint and slack variable
    8237 * in a generic version, i. e., with a flag activeone indicating whether the constraint is active on
    8238 * value 1 or 0 of the binary variable.
    8239
    8240 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    8241 * procedures reading an instance.
    8242 *
    8243 * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
    8244 * the role of a slack variable!
    8245 *
    8246 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8247 *
    8248 * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
    8249 */
    8251 SCIP* scip, /**< SCIP data structure */
    8252 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    8253 const char* name, /**< name of constraint */
    8254 SCIP_VAR* binvar, /**< binary indicator variable */
    8255 SCIP_CONS* lincons, /**< linear constraint */
    8256 SCIP_VAR* slackvar, /**< slack variable */
    8257 SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
    8258 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    8259 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    8260 * Usually set to TRUE. */
    8261 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    8262 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8263 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    8264 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8265 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    8266 * Usually set to TRUE. */
    8267 SCIP_Bool local, /**< is constraint only valid locally?
    8268 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    8269 SCIP_Bool dynamic, /**< is constraint subject to aging?
    8270 * Usually set to FALSE. Set to TRUE for own cuts which
    8271 * are separated as constraints. */
    8272 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    8273 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    8274 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    8275 * if it may be moved to a more global node?
    8276 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    8277 )
    8278{
    8279 SCIP_CONSHDLR* conshdlr;
    8280 SCIP_CONSHDLRDATA* conshdlrdata;
    8281 SCIP_CONSDATA* consdata = NULL;
    8282 SCIP_VAR** vars;
    8283 SCIP_Real* vals;
    8284 SCIP_Bool modifiable = FALSE;
    8285 SCIP_Bool linconsactive;
    8286 SCIP_Bool integral = TRUE;
    8287 int nvars;
    8288 int v;
    8289
    8290 assert( scip != NULL );
    8291 assert( lincons != NULL );
    8292 assert( binvar != NULL );
    8293 assert( slackvar != NULL );
    8294
    8295 /* check whether lincons is really a linear constraint */
    8296 conshdlr = SCIPconsGetHdlr(lincons);
    8297 if ( strcmp(SCIPconshdlrGetName(conshdlr), "linear") != 0 )
    8298 {
    8299 SCIPerrorMessage("Lincons constraint is not linear.\n");
    8300 return SCIP_INVALIDDATA;
    8301 }
    8302
    8303 /* find the indicator constraint handler */
    8304 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    8305 if ( conshdlr == NULL )
    8306 {
    8307 SCIPerrorMessage("<%s> constraint handler not found.\n", CONSHDLR_NAME);
    8308 return SCIP_PLUGINNOTFOUND;
    8309 }
    8310
    8311 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8312 assert( conshdlrdata != NULL );
    8313
    8314 if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
    8315 {
    8316 SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
    8317 return SCIP_INVALIDDATA;
    8318 }
    8319
    8320 /* determine integrality of slack variable and whether problem is decomposed if no variables are integral */
    8321 nvars = SCIPgetNVarsLinear(scip, lincons);
    8322 vars = SCIPgetVarsLinear(scip, lincons);
    8323 vals = SCIPgetValsLinear(scip, lincons);
    8324 linconsactive = !conshdlrdata->nolinconscont;
    8325 for ( v = 0; v < nvars; ++v )
    8326 {
    8327 if ( vars[v] == slackvar )
    8328 continue;
    8329
    8330 if ( SCIPvarIsIntegral(vars[v]) )
    8331 {
    8332 linconsactive = TRUE;
    8333 if ( !integral )
    8334 break;
    8335 if ( !SCIPisIntegral(scip, vals[v]) )
    8336 {
    8337 integral = FALSE;
    8338 break;
    8339 }
    8340 }
    8341 else
    8342 {
    8343 integral = FALSE;
    8344 if ( linconsactive )
    8345 break;
    8346 }
    8347 }
    8348
    8349 /* make sure that the type of the slack is as general as necessary */
    8350 if ( !integral && SCIPvarIsIntegral(slackvar) )
    8351 {
    8352 SCIP_Bool infeasible;
    8353
    8354 SCIP_CALL( SCIPchgVarType(scip, slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
    8355 assert( !infeasible );
    8356 SCIP_CALL( SCIPchgVarImplType(scip, slackvar, SCIP_IMPLINTTYPE_NONE, &infeasible) );
    8357 assert( !infeasible );
    8358 }
    8359
    8360 /* mark slack variable not to be multi-aggregated */
    8362
    8363 /* mark linear constraint not to be upgraded - otherwise we loose control over it */
    8364 SCIPconsAddUpgradeLocks(lincons, 1);
    8365 assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
    8366
    8367 /* check whether we should generate a bilinear constraint instead of an indicator constraint */
    8368 if ( conshdlrdata->generatebilinear )
    8369 {
    8370 assert( linconsactive );
    8371
    8372 SCIP_Real val = 1.0;
    8373
    8374 /* if active on 0, the binary variable is negated */
    8375 SCIP_VAR* binvarinternal;
    8376 if ( activeone )
    8377 binvarinternal = binvar;
    8378 else
    8379 {
    8380 assert( SCIPvarIsBinary(binvar) );
    8381 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
    8382 }
    8383
    8384 /* create a quadratic constraint with a single bilinear term - note that cons is used */
    8385 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
    8387 }
    8388 else
    8389 {
    8390 /* create constraint data */
    8391 SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrrestart,
    8392 binvar, activeone, TRUE, slackvar, lincons, linconsactive) );
    8393 assert( consdata != NULL );
    8394
    8395 /* create constraint */
    8396 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    8397 local, modifiable, dynamic, removable, stickingatnode) );
    8398
    8399 /* catch local bound change events on binary variable */
    8400 if ( consdata->linconsactive && SCIPisTransformed(scip) )
    8401 {
    8402 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8403 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8404 }
    8405 }
    8406
    8407 /* capture slack variable and linear constraint */
    8408 SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
    8409 SCIP_CALL( SCIPcaptureCons(scip, lincons) );
    8410
    8411 return SCIP_OKAY;
    8412}
    8413
    8414/** creates and captures an indicator constraint with given linear constraint and slack variable
    8415 *
    8416 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    8417 * procedures reading an instance.
    8418 *
    8419 * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
    8420 * the role of a slack variable!
    8421 *
    8422 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8423 */
    8425 SCIP* scip, /**< SCIP data structure */
    8426 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    8427 const char* name, /**< name of constraint */
    8428 SCIP_VAR* binvar, /**< binary indicator variable */
    8429 SCIP_CONS* lincons, /**< linear constraint */
    8430 SCIP_VAR* slackvar, /**< slack variable */
    8431 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    8432 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    8433 * Usually set to TRUE. */
    8434 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    8435 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8436 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    8437 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8438 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    8439 * Usually set to TRUE. */
    8440 SCIP_Bool local, /**< is constraint only valid locally?
    8441 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    8442 SCIP_Bool dynamic, /**< is constraint subject to aging?
    8443 * Usually set to FALSE. Set to TRUE for own cuts which
    8444 * are separated as constraints. */
    8445 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    8446 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    8447 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    8448 * if it may be moved to a more global node?
    8449 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    8450 )
    8451{
    8452 return SCIPcreateConsIndicatorGenericLinCons(scip, cons, name, binvar, lincons, slackvar, TRUE, initial, separate,
    8453 enforce, check, propagate, local, dynamic, removable, stickingatnode);
    8454}
    8455
    8456
    8457/** creates and captures an indicator constraint with given linear constraint and slack variable
    8458 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
    8459 * method SCIPcreateConsIndicator(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
    8460 *
    8461 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    8462 * procedures reading an instance.
    8463 *
    8464 * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
    8465 * the role of a slack variable!
    8466 *
    8467 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8468 *
    8469 * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
    8470 *
    8471 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8472 */
    8474 SCIP* scip, /**< SCIP data structure */
    8475 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    8476 const char* name, /**< name of constraint */
    8477 SCIP_VAR* binvar, /**< binary indicator variable */
    8478 SCIP_CONS* lincons, /**< linear constraint */
    8479 SCIP_VAR* slackvar /**< slack variable */
    8480 )
    8481{
    8482 assert( scip != NULL );
    8483
    8484 SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
    8486
    8487 return SCIP_OKAY;
    8488}
    8489
    8490
    8491/** creates and captures an indicator constraint with given linear constraint in a generic version, i. e., with a flag
    8492 * activeone indicating whether the constraint is active on value 1 or 0 of the binary variable; no slack variable is
    8493 * given
    8494
    8495 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    8496 * procedures reading an instance.
    8497 *
    8498 * @note The linear constraint must be single-sided, i.e., either rhs or lhs have to be infinite.
    8499 *
    8500 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8501 *
    8502 * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
    8503 */
    8505 SCIP* scip, /**< SCIP data structure */
    8506 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    8507 const char* name, /**< name of constraint */
    8508 SCIP_VAR* binvar, /**< binary indicator variable */
    8509 SCIP_CONS* lincons, /**< linear constraint */
    8510 SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
    8511 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    8512 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    8513 * Usually set to TRUE. */
    8514 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    8515 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8516 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    8517 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8518 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    8519 * Usually set to TRUE. */
    8520 SCIP_Bool local, /**< is constraint only valid locally?
    8521 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    8522 SCIP_Bool dynamic, /**< is constraint subject to aging?
    8523 * Usually set to FALSE. Set to TRUE for own cuts which
    8524 * are separated as constraints. */
    8525 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    8526 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    8527 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    8528 * if it may be moved to a more global node?
    8529 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    8530 )
    8531{
    8532 char s[SCIP_MAXSTRLEN];
    8533 SCIP_CONSHDLR* conshdlr;
    8534 SCIP_CONSHDLRDATA* conshdlrdata;
    8535 SCIP_CONSDATA* consdata = NULL;
    8536 SCIP_VAR** vars;
    8537 SCIP_VAR* binvarinternal;
    8538 SCIP_VAR* slackvar = NULL;
    8539 SCIP_Bool modifiable = FALSE;
    8540 SCIP_Bool linconsactive;
    8541 SCIP_Bool integral = TRUE;
    8542 SCIP_Real* vals;
    8543 SCIP_Real sign;
    8544 SCIP_Real lhs;
    8545 SCIP_Real rhs;
    8546 int nvars;
    8547 int v;
    8548
    8549 assert( scip != NULL );
    8550 assert( lincons != NULL );
    8551 assert( binvar != NULL );
    8552
    8553 /* check whether lincons is really a linear constraint */
    8554 conshdlr = SCIPconsGetHdlr(lincons);
    8555 if ( strcmp(SCIPconshdlrGetName(conshdlr), "linear") != 0 )
    8556 {
    8557 SCIPerrorMessage("Lincons constraint is not linear.\n");
    8558 return SCIP_INVALIDDATA;
    8559 }
    8560
    8561 /* find the indicator constraint handler */
    8562 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    8563 if ( conshdlr == NULL )
    8564 {
    8565 SCIPerrorMessage("<%s> constraint handler not found.\n", CONSHDLR_NAME);
    8566 return SCIP_PLUGINNOTFOUND;
    8567 }
    8568
    8569 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8570 assert( conshdlrdata != NULL );
    8571
    8572 if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
    8573 {
    8574 SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
    8575 return SCIP_INVALIDDATA;
    8576 }
    8577
    8578 lhs = SCIPgetLhsLinear(scip, lincons);
    8579 rhs = SCIPgetRhsLinear(scip, lincons);
    8580 if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
    8581 {
    8582 SCIPerrorMessage("Lincons constraint has finite lhs and rhs.\n");
    8583 return SCIP_INVALIDDATA;
    8584 }
    8585
    8586 /* determine integrality of slack variable and whether problem is decomposed if no variables are integral */
    8587 nvars = SCIPgetNVarsLinear(scip, lincons);
    8588 vars = SCIPgetVarsLinear(scip, lincons);
    8589 vals = SCIPgetValsLinear(scip, lincons);
    8590 linconsactive = !conshdlrdata->nolinconscont;
    8591 for ( v = 0; v < nvars; ++v )
    8592 {
    8593 if ( SCIPvarIsIntegral(vars[v]) )
    8594 {
    8595 linconsactive = TRUE;
    8596 if ( !SCIPisIntegral(scip, vals[v]) )
    8597 integral = FALSE;
    8598 }
    8599 else
    8600 integral = FALSE;
    8601
    8602 /* check whether variable is marked to not be multi-aggregated: this should only be the case for slack variables
    8603 * added by the indicator constraint handler */
    8604 if ( SCIPdoNotMultaggrVar(scip, vars[v]) )
    8605 {
    8606 /* double check name */
    8607 if ( strncmp(SCIPvarGetName(vars[v]), "indslack", 8) == 0 )
    8608 {
    8609 SCIPerrorMessage("Linear constraint <%s> already used in an indicator constraint.\n", SCIPconsGetName(lincons));
    8610 return SCIP_INVALIDDATA;
    8611 }
    8612 }
    8613 }
    8614
    8615 /* if active on 0, the binary variable is negated */
    8616 if ( activeone )
    8617 binvarinternal = binvar;
    8618 else
    8619 {
    8620 assert( SCIPvarIsBinary(binvar) );
    8621 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
    8622 }
    8623
    8624 /* Check whether the same slack variable should be use for constraints with a common binary variable. This can
    8625 * reduce the size of the problem, because only one coupling constraint is needed. However, it is less tight. */
    8626 if ( conshdlrdata->usesameslackvar && conshdlrdata->binslackvarhash == NULL )
    8627 {
    8628 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binslackvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
    8629 }
    8630
    8631 if ( conshdlrdata->binslackvarhash != NULL && SCIPhashmapExists(conshdlrdata->binslackvarhash, (void*) binvarinternal) )
    8632 {
    8633 /* determine slack variable */
    8634 slackvar = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->binslackvarhash, (void*) binvarinternal);
    8635
    8636 /* make sure that the type of the slack is as general as necessary */
    8637 if ( !integral && SCIPvarIsIntegral(slackvar) )
    8638 {
    8639 SCIP_Bool infeasible;
    8640
    8641 SCIP_CALL( SCIPchgVarType(scip, slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
    8642 assert( !infeasible );
    8643 SCIP_CALL( SCIPchgVarImplType(scip, slackvar, SCIP_IMPLINTTYPE_NONE, &infeasible) );
    8644 assert( !infeasible );
    8645 }
    8646
    8647 SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
    8648 }
    8649 else
    8650 {
    8651 /* create slack variable */
    8652 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
    8653 SCIP_CALL( SCIPcreateVarImpl(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0,
    8655 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    8656
    8657 SCIP_CALL( SCIPaddVar(scip, slackvar) );
    8658
    8659 /* mark slack variable not to be multi-aggregated */
    8661
    8662 if ( conshdlrdata->binslackvarhash != NULL )
    8663 {
    8664 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binslackvarhash, (void*) binvarinternal, (void*) slackvar) );
    8665 }
    8666 }
    8667 assert( slackvar != NULL );
    8668
    8669 /* determine sign of slack variable */
    8670 sign = -1.0;
    8671 if ( SCIPisInfinity(scip, rhs) )
    8672 sign = 1.0;
    8673
    8674 /* add slack variable */
    8675 SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, sign) );
    8676
    8677 /* mark linear constraint not to be upgraded - otherwise we loose control over it */
    8678 SCIPconsAddUpgradeLocks(lincons, 1);
    8679 assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
    8680
    8681 /* check whether we should generate a bilinear constraint instead of an indicator constraint */
    8682 if ( conshdlrdata->generatebilinear )
    8683 {
    8684 assert( linconsactive );
    8685
    8686 SCIP_Real val = 1.0;
    8687
    8688 /* create a quadratic constraint with a single bilinear term - note that cons is used */
    8689 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
    8691 }
    8692 else
    8693 {
    8694 /* create constraint data */
    8695 SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrrestart,
    8696 binvar, activeone, TRUE, slackvar, lincons, linconsactive) );
    8697 assert( consdata != NULL );
    8698
    8699 /* create constraint */
    8700 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    8701 local, modifiable, dynamic, removable, stickingatnode) );
    8702
    8703 /* catch local bound change events on binary variable */
    8704 if ( consdata->linconsactive && SCIPisTransformed(scip) )
    8705 {
    8706 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8707 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
    8708 }
    8709 }
    8710
    8711 /* capture slack variable and linear constraint */
    8712 SCIP_CALL( SCIPcaptureCons(scip, lincons) );
    8713
    8714 return SCIP_OKAY;
    8715}
    8716
    8717
    8718/** creates and captures an indicator constraint with given linear constraint; no slack variable is specified
    8719 *
    8720 * @note @a binvar is checked to be binary only later. This enables a change of the type in
    8721 * procedures reading an instance.
    8722 *
    8723 * @note The linear constraint has to be single sided only, i.e., either rhs or lhs have to be infinite.
    8724 *
    8725 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    8726 */
    8728 SCIP* scip, /**< SCIP data structure */
    8729 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    8730 const char* name, /**< name of constraint */
    8731 SCIP_VAR* binvar, /**< binary indicator variable */
    8732 SCIP_CONS* lincons, /**< linear constraint */
    8733 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
    8734 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    8735 * Usually set to TRUE. */
    8736 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    8737 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8738 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    8739 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    8740 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    8741 * Usually set to TRUE. */
    8742 SCIP_Bool local, /**< is constraint only valid locally?
    8743 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    8744 SCIP_Bool dynamic, /**< is constraint subject to aging?
    8745 * Usually set to FALSE. Set to TRUE for own cuts which
    8746 * are separated as constraints. */
    8747 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    8748 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    8749 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    8750 * if it may be moved to a more global node?
    8751 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    8752 )
    8753{
    8754 return SCIPcreateConsIndicatorGenericLinConsPure(scip, cons, name, binvar, lincons, TRUE, initial, separate,
    8755 enforce, check, propagate, local, dynamic, removable, stickingatnode);
    8756}
    8757
    8758
    8759/** adds variable to the inequality of the indicator constraint */
    8761 SCIP* scip, /**< SCIP data structure */
    8762 SCIP_CONS* cons, /**< indicator constraint */
    8763 SCIP_VAR* var, /**< variable to add to the inequality */
    8764 SCIP_Real val /**< value of variable */
    8765 )
    8766{
    8767 SCIP_CONSDATA* consdata;
    8768
    8769 assert( cons != NULL );
    8770 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
    8771
    8772 consdata = SCIPconsGetData(cons);
    8773 assert( consdata != NULL );
    8774
    8775 /* if linear inequality is flipped, variable is added with negative coefficient */
    8776 if ( !consdata->lessthanineq )
    8777 val = -val;
    8778
    8779 SCIP_CALL( SCIPaddCoefLinear(scip, consdata->lincons, var, val) );
    8780
    8781 /* make sure that the type of the slack is as general as necessary */
    8782 if ( ( !SCIPvarIsIntegral(var) || !SCIPisIntegral(scip, val) ) && SCIPvarIsIntegral(consdata->slackvar) )
    8783 {
    8784 SCIP_Bool infeasible;
    8785
    8786 SCIP_CALL( SCIPchgVarType(scip, consdata->slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
    8787 assert( !infeasible );
    8788 SCIP_CALL( SCIPchgVarImplType(scip, consdata->slackvar, SCIP_IMPLINTTYPE_NONE, &infeasible) );
    8789 assert( !infeasible );
    8790 }
    8791
    8792 return SCIP_OKAY;
    8793}
    8794
    8795
    8796/** gets the linear constraint corresponding to the indicator constraint (may be NULL) */
    8798 SCIP_CONS* cons /**< indicator constraint */
    8799 )
    8800{
    8801 SCIP_CONSDATA* consdata;
    8802
    8803 assert( cons != NULL );
    8804 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
    8805
    8806 consdata = SCIPconsGetData(cons);
    8807 assert( consdata != NULL );
    8808
    8809 return consdata->lincons;
    8810}
    8811
    8812
    8813/** sets the linear constraint corresponding to the indicator constraint (may be NULL) */
    8815 SCIP* scip, /**< SCIP data structure */
    8816 SCIP_CONS* cons, /**< indicator constraint */
    8817 SCIP_CONS* lincons /**< linear constraint */
    8818 )
    8819{
    8820 SCIP_CONSHDLR* conshdlr;
    8821 SCIP_CONSHDLRDATA* conshdlrdata;
    8822 SCIP_CONSDATA* consdata;
    8823
    8825 {
    8826 SCIPerrorMessage("Cannot set linear constraint in SCIP stage <%d>\n", SCIPgetStage(scip) );
    8827 return SCIP_INVALIDCALL;
    8828 }
    8829
    8830 assert( cons != NULL );
    8831 conshdlr = SCIPconsGetHdlr(cons);
    8832
    8833 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    8834 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8835 assert( conshdlrdata != NULL );
    8836
    8837 consdata = SCIPconsGetData(cons);
    8838 assert( consdata != NULL );
    8839
    8840 /* free old linear constraint */
    8841 assert( consdata->lincons != NULL );
    8842 SCIP_CALL( SCIPdelCons(scip, consdata->lincons) );
    8843 SCIP_CALL( SCIPreleaseCons(scip, &(consdata->lincons) ) );
    8844
    8845 assert( lincons != NULL );
    8846 consdata->lincons = lincons;
    8847 consdata->linconsactive = !conshdlrdata->nolinconscont;
    8848 SCIP_CALL( SCIPcaptureCons(scip, lincons) );
    8849
    8850 /* determine whether problem is decomposed if no variables are integral */
    8851 if ( !consdata->linconsactive )
    8852 {
    8853 SCIP_VAR** vars = SCIPgetVarsLinear(scip, lincons);
    8854 int nvars = SCIPgetNVarsLinear(scip, lincons);
    8855 int v;
    8856
    8857 for ( v = 0; v < nvars; ++v )
    8858 {
    8859 if ( SCIPvarIsIntegral(vars[v]) )
    8860 {
    8861 consdata->linconsactive = TRUE;
    8862 break;
    8863 }
    8864 }
    8865 }
    8866
    8867 return SCIP_OKAY;
    8868}
    8869
    8870/** gets activation value of an indicator constraint, TRUE for active on 1, FALSE for active on 0 */
    8872 SCIP_CONS* cons /**< indicator constraint */
    8873 )
    8874{
    8875 SCIP_CONSDATA* consdata;
    8876
    8877 assert( cons != NULL );
    8878 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
    8879
    8880 consdata = SCIPconsGetData(cons);
    8881 assert( consdata != NULL );
    8882
    8883 return consdata->activeone;
    8884}
    8885
    8886
    8887/** gets binary variable corresponding to indicator constraint */
    8889 SCIP_CONS* cons /**< indicator constraint */
    8890 )
    8891{
    8892 SCIP_CONSDATA* consdata;
    8893
    8894 assert( cons != NULL );
    8895 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
    8896
    8897 consdata = SCIPconsGetData(cons);
    8898 assert( consdata != NULL );
    8899
    8900 return consdata->binvar;
    8901}
    8902
    8903/** similar to SCIPgetBinaryVarIndicator but returns the original binary variable passed by the user. */
    8905 SCIP_CONS* cons /**< indicator constraint */
    8906 )
    8907{
    8908 SCIP_CONSDATA* consdata;
    8909 SCIP_VAR* binvar;
    8910
    8911 assert(cons != NULL);
    8912 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    8913
    8914 consdata = SCIPconsGetData(cons);
    8915 assert(consdata != NULL);
    8916 binvar = consdata->binvar;
    8917
    8918 if ( ! consdata->activeone )
    8919 binvar = SCIPvarGetNegationVar(binvar);
    8920 assert(binvar != NULL);
    8921
    8922 return binvar;
    8923}
    8924
    8925/** sets binary indicator variable for indicator constraint */
    8927 SCIP* scip, /**< SCIP data structure */
    8928 SCIP_CONS* cons, /**< indicator constraint */
    8929 SCIP_VAR* binvar /**< binary variable to add to the inequality */
    8930 )
    8931{
    8932 SCIP_CONSDATA* consdata;
    8933
    8934 assert( cons != NULL );
    8935 assert( binvar != NULL );
    8936 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
    8937
    8938 consdata = SCIPconsGetData(cons);
    8939 assert( consdata != NULL );
    8940
    8941 /* check type */
    8942 if ( !SCIPvarIsBinary(binvar) || SCIPvarIsImpliedIntegral(binvar) )
    8943 {
    8944 SCIPerrorMessage("Indicator variable <%s> is not binary %d.\n", SCIPvarGetName(binvar), SCIPvarGetType(binvar));
    8945 return SCIP_ERROR;
    8946 }
    8947
    8948 /* check previous binary variable */
    8949 if ( consdata->binvar != NULL )
    8950 {
    8951 /* to allow replacement of binary variables, we would need to drop events etc. */
    8952 SCIPerrorMessage("Cannot replace binary variable <%s> for indicator constraint <%s>.\n", SCIPvarGetName(binvar), SCIPconsGetName(cons));
    8953 return SCIP_INVALIDCALL;
    8954 }
    8955
    8956 /* if we are transformed, obtain transformed variables and catch events */
    8957 if ( SCIPconsIsTransformed(cons) )
    8958 {
    8959 SCIP_VAR* var;
    8960 SCIP_CONSHDLR* conshdlr;
    8961 SCIP_CONSHDLRDATA* conshdlrdata;
    8962
    8963 /* make sure we have a transformed binary variable */
    8964 /* coverity[copy_paste_error] */
    8965 SCIP_CALL( SCIPgetTransformedVar(scip, binvar, &var) );
    8966 assert( var != NULL );
    8967 if ( ! consdata->activeone )
    8968 SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
    8969
    8970 consdata->binvar = var;
    8971
    8972 conshdlr = SCIPconsGetHdlr(cons);
    8973 assert( conshdlr != NULL );
    8974 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    8975 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8976 assert( conshdlrdata != NULL );
    8977 assert( conshdlrdata->eventhdlrbound != NULL );
    8978 assert( conshdlrdata->eventhdlrrestart != NULL );
    8979
    8980 /* catch local bound change events on binary variable */
    8981 if ( consdata->linconsactive )
    8982 {
    8983 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, NULL) );
    8984 }
    8985
    8986 /* catch global bound change events on binary variable */
    8987 if ( conshdlrdata->forcerestart )
    8988 {
    8989 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
    8990 }
    8991
    8992 /* if binary variable is fixed to be nonzero */
    8993 if ( SCIPvarGetLbLocal(var) > 0.5 )
    8994 ++(consdata->nfixednonzero);
    8995 }
    8996 else
    8997 {
    8998 if ( ! consdata->activeone )
    8999 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
    9000 consdata->binvar = binvar;
    9001 }
    9002
    9003 return SCIP_OKAY;
    9004}
    9005
    9006/** gets slack variable corresponding to indicator constraint */
    9008 SCIP_CONS* cons /**< indicator constraint */
    9009 )
    9010{
    9011 SCIP_CONSDATA* consdata;
    9012
    9013 assert( cons != NULL );
    9014 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
    9015
    9016 consdata = SCIPconsGetData(cons);
    9017 assert( consdata != NULL );
    9018
    9019 return consdata->slackvar;
    9020}
    9021
    9022
    9023/** sets upper bound for slack variable corresponding to indicator constraint
    9024 *
    9025 * Use with care if you know that the maximal violation of the corresponding constraint is at most @p ub. This bound
    9026 * might be improved automatically during the solution process.
    9027 *
    9028 * @pre This method should only be called if SCIP is in one of the following stages:
    9029 * - \ref SCIP_STAGE_INIT
    9030 * - \ref SCIP_STAGE_PROBLEM
    9031 */
    9033 SCIP* scip, /**< SCIP data structure */
    9034 SCIP_CONS* cons, /**< indicator constraint */
    9035 SCIP_Real ub /**< upper bound for slack variable */
    9036 )
    9037{
    9038 SCIP_CONSDATA* consdata;
    9039
    9040 assert( scip != NULL );
    9041 assert( cons != NULL );
    9042 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
    9043
    9044 consdata = SCIPconsGetData(cons);
    9045 assert( consdata != NULL );
    9046
    9048 return SCIP_OKAY;
    9049
    9050 assert( consdata->slackvar != NULL );
    9051 SCIP_CALL( SCIPchgVarUb(scip, consdata->slackvar, ub) );
    9052
    9053 return SCIP_OKAY;
    9054}
    9055
    9056
    9057/** checks whether indicator constraint is violated w.r.t. sol */
    9059 SCIP* scip, /**< SCIP data structure */
    9060 SCIP_CONS* cons, /**< indicator constraint */
    9061 SCIP_SOL* sol /**< solution, or NULL to use current node's solution */
    9062 )
    9063{
    9064 SCIP_CONSDATA* consdata;
    9065
    9066 assert( cons != NULL );
    9067
    9068 /* deleted constraints should always be satisfied */
    9069 if ( SCIPconsIsDeleted(cons) )
    9070 return FALSE;
    9071
    9072 consdata = SCIPconsGetData(cons);
    9073 assert( consdata != NULL );
    9074
    9075 if ( consdata->linconsactive )
    9076 {
    9077 assert( consdata->slackvar != NULL );
    9078 assert( consdata->binvar != NULL );
    9079 return(
    9080 SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) &&
    9081 SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
    9082 }
    9083
    9084 /* @todo: check how this can be decided for linconsactive == FALSE */
    9085 return TRUE;
    9086}
    9087
    9088
    9089/** based on values of other variables, computes slack and binary variable to turn constraint feasible
    9090 *
    9091 * It will also clean up the solution, i.e., shift slack variable, as follows:
    9092 *
    9093 * If the inequality is \f$a^T x + \gamma\, s \leq \beta\f$, the value of the slack variable
    9094 * \f$s\f$ to achieve equality is
    9095 * \f[
    9096 * s^* = \frac{\beta - a^T x^*}{\gamma},
    9097 * \f]
    9098 * where \f$x^*\f$ is the given solution. In case of \f$a^T x + \gamma\, s \geq \alpha\f$, we
    9099 * arrive at
    9100 * \f[
    9101 * s^* = \frac{\alpha - a^T x^*}{\gamma}.
    9102 * \f]
    9103 * The typical values of \f$\gamma\f$ in the first case is -1 and +1 in the second case.
    9104 *
    9105 * Now, let \f$\sigma\f$ be the sign of \f$\gamma\f$ in the first case and \f$-\gamma\f$ in the
    9106 * second case. Thus, if \f$\sigma > 0\f$ and \f$s^* < 0\f$, the inequality cannot be satisfied by
    9107 * a nonnegative value for the slack variable; in this case, we have to leave the values as they
    9108 * are. If \f$\sigma < 0\f$ and \f$s^* > 0\f$, the solution violates the indicator constraint (we
    9109 * can set the slack variable to value \f$s^*\f$). If \f$\sigma < 0\f$ and \f$s^* \leq 0\f$ or
    9110 * \f$\sigma > 0\f$ and \f$s^* \geq 0\f$, the constraint is satisfied, and we can set the slack
    9111 * variable to 0.
    9112 */
    9114 SCIP* scip, /**< SCIP data structure */
    9115 SCIP_CONS* cons, /**< indicator constraint */
    9116 SCIP_SOL* sol, /**< solution */
    9117 SCIP_Bool* changed /**< pointer to store whether the solution has been changed */
    9118 )
    9119{
    9120 SCIP_CONSDATA* consdata;
    9121 SCIP_CONS* lincons;
    9122 SCIP_VAR** linvars;
    9123 SCIP_Real* linvals;
    9124 SCIP_VAR* slackvar;
    9125 SCIP_VAR* binvar;
    9126 SCIP_Real slackcoef;
    9127 SCIP_Real sum;
    9128 SCIP_Real val;
    9129 int nlinvars;
    9130 int sigma;
    9131 int v;
    9132
    9133 assert( cons != NULL );
    9134 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
    9135 assert( sol != NULL );
    9136 assert( changed != NULL );
    9137
    9138 *changed = FALSE;
    9139
    9140 /* avoid deleted indicator constraints, e.g., due to preprocessing */
    9142 return SCIP_OKAY;
    9143
    9144 assert( cons != NULL );
    9145 consdata = SCIPconsGetData(cons);
    9146 assert( consdata != NULL );
    9147
    9148 /* if the linear constraint is not present, we cannot do anything */
    9149 if ( ! consdata->linconsactive )
    9150 return SCIP_OKAY;
    9151
    9152 lincons = consdata->lincons;
    9153 assert( lincons != NULL );
    9154
    9155 /* avoid non-active linear constraints, e.g., due to preprocessing */
    9157 {
    9158 slackvar = consdata->slackvar;
    9159 binvar = consdata->binvar;
    9160 assert( slackvar != NULL );
    9161 assert( binvar != NULL );
    9162
    9163 nlinvars = SCIPgetNVarsLinear(scip, lincons);
    9164 linvars = SCIPgetVarsLinear(scip, lincons);
    9165 linvals = SCIPgetValsLinear(scip, lincons);
    9166
    9167 /* compute value of regular variables */
    9168 sum = 0.0;
    9169 slackcoef = 0.0;
    9170 for (v = 0; v < nlinvars; ++v)
    9171 {
    9172 SCIP_VAR* var;
    9173 var = linvars[v];
    9174 if ( var != slackvar )
    9175 sum += linvals[v] * SCIPgetSolVal(scip, sol, var);
    9176 else
    9177 slackcoef = linvals[v];
    9178 }
    9179
    9180 /* do nothing if slack variable does not appear */
    9181 if ( SCIPisFeasZero(scip, slackcoef) )
    9182 return SCIP_OKAY;
    9183
    9184 assert( ! SCIPisZero(scip, slackcoef) );
    9185 assert( slackcoef != 0.0 ); /* to satisfy lint */
    9186 assert( SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, lincons)) || SCIPisInfinity(scip, SCIPgetRhsLinear(scip, lincons)) );
    9187 assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(slackvar), 0.0) );
    9188
    9189 val = SCIPgetRhsLinear(scip, lincons);
    9190 sigma = 1;
    9191 if ( SCIPisInfinity(scip, val) )
    9192 {
    9193 val = SCIPgetLhsLinear(scip, lincons);
    9194 assert( ! SCIPisInfinity(scip, REALABS(val)) );
    9195 sigma = -1;
    9196 }
    9197 /* compute value of slack that would achieve equality */
    9198 val = (val - sum)/slackcoef;
    9199
    9200 /* compute direction into which slack variable would be infeasible */
    9201 if ( slackcoef < 0 )
    9202 sigma *= -1;
    9203
    9204 /* filter out cases in which no sensible change is possible */
    9205 if ( sigma > 0 && SCIPisFeasNegative(scip, val) )
    9206 return SCIP_OKAY;
    9207
    9208 /* check if linear constraint w/o slack variable is violated */
    9209 if ( sigma < 0 && SCIPisFeasPositive(scip, val) )
    9210 {
    9211 /* the original constraint is violated */
    9212 if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, slackvar), val) )
    9213 {
    9214 SCIP_CALL( SCIPsetSolVal(scip, sol, slackvar, val) );
    9215 *changed = TRUE;
    9216 }
    9217 /* check whether binary variable is fixed or its negated variable is fixed */
    9218 if ( SCIPvarGetStatus(binvar) != SCIP_VARSTATUS_FIXED &&
    9220 {
    9221 if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 0.0) )
    9222 {
    9223 SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 0.0) );
    9224 *changed = TRUE;
    9225 }
    9226 }
    9227 }
    9228 else
    9229 {
    9230 assert( SCIPisFeasGE(scip, val * ((SCIP_Real) sigma), 0.0) );
    9231
    9232 /* the original constraint is satisfied - we can set the slack variable to 0 (slackvar
    9233 * should only occur in this indicator constraint) */
    9234 if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, slackvar), 0.0) && SCIPisFeasPositive(scip, SCIPvarGetLbLocal(slackvar)) )
    9235 {
    9236 SCIP_CALL( SCIPsetSolVal(scip, sol, slackvar, 0.0) );
    9237 *changed = TRUE;
    9238 }
    9239
    9240 /* check whether binary variable is fixed or its negated variable is fixed */
    9241 if ( SCIPvarGetStatus(binvar) != SCIP_VARSTATUS_FIXED &&
    9243 {
    9244 SCIP_Real obj;
    9245 obj = varGetObjDelta(binvar);
    9246
    9247 /* check objective for possibly setting binary variable */
    9248 if ( obj <= 0 )
    9249 {
    9250 /* setting variable to 1 does not increase objective - check whether we can set it to 1 */
    9251 if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 1.0) )
    9252 {
    9253 /* check whether variable only occurs in the current constraint */
    9254 if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
    9255 {
    9256 SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 1.0) );
    9257 *changed = TRUE;
    9258 /* make sure that the other case does not occur if obj = 0: prefer variables set to 1 */
    9259 obj = -1.0;
    9260 }
    9261 }
    9262 else
    9263 {
    9264 /* make sure that the other case does not occur if obj = 0: prefer variables set to 1 */
    9265 obj = -1.0;
    9266 }
    9267 }
    9268 if ( obj >= 0 )
    9269 {
    9270 /* setting variable to 0 does not increase objective -> check whether variable only occurs in the current constraint
    9271 * note: binary variables are only locked up */
    9273 && ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 0.0) )
    9274 {
    9275 SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 0.0) );
    9276 *changed = TRUE;
    9277 }
    9278 }
    9279 }
    9280 }
    9281 }
    9282
    9283 return SCIP_OKAY;
    9284}
    9285
    9286
    9287/** based on values of other variables, computes slack and binary variable to turn all constraints feasible */
    9289 SCIP* scip, /**< SCIP data structure */
    9290 SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
    9291 SCIP_SOL* sol, /**< solution */
    9292 SCIP_Bool* changed /**< pointer to store whether the solution has been changed */
    9293 )
    9294{
    9295 SCIP_CONS** conss;
    9296 int nconss;
    9297 int c;
    9298
    9299 assert( conshdlr != NULL );
    9300 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9301 assert( sol != NULL );
    9302 assert( changed != NULL );
    9303
    9304 *changed = FALSE;
    9305
    9306 /* only run after or in presolving */
    9308 return SCIP_OKAY;
    9309
    9310 conss = SCIPconshdlrGetConss(conshdlr);
    9311 nconss = SCIPconshdlrGetNConss(conshdlr);
    9312
    9313 for (c = 0; c < nconss; ++c)
    9314 {
    9315 SCIP_CONSDATA* consdata;
    9316 SCIP_Bool chg = FALSE;
    9317 assert( conss[c] != NULL );
    9318
    9319 consdata = SCIPconsGetData(conss[c]);
    9320 assert( consdata != NULL );
    9321
    9322 /* if the linear constraint is not present, we stop */
    9323 if ( ! consdata->linconsactive )
    9324 break;
    9325
    9326 SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], sol, &chg) );
    9327 *changed = *changed || chg;
    9328 }
    9329
    9330 return SCIP_OKAY;
    9331}
    9332
    9333
    9334/** adds additional linear constraint that is not connected with an indicator constraint, but can be used for separation */
    9336 SCIP* scip, /**< SCIP data structure */
    9337 SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
    9338 SCIP_CONS* lincons /**< linear constraint */
    9339 )
    9340{
    9341 assert( scip != NULL );
    9342 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9343 assert( lincons != NULL );
    9344
    9345 /* do not add locally valid constraints (this would require much more bookkeeping) */
    9346 if ( ! SCIPconsIsLocal(lincons) && ! SCIPconsIsModifiable(lincons) )
    9347 {
    9348 SCIP_CONSHDLRDATA* conshdlrdata;
    9349
    9350 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9351 assert( conshdlrdata != NULL );
    9352
    9353 SCIP_CALL( consdataEnsureAddLinConsSize(scip, conshdlr, conshdlrdata->naddlincons+1) );
    9354 assert( conshdlrdata->naddlincons+1 <= conshdlrdata->maxaddlincons );
    9355
    9356 conshdlrdata->addlincons[conshdlrdata->naddlincons++] = lincons;
    9357 }
    9358
    9359 return SCIP_OKAY;
    9360}
    9361
    9362
    9363/** adds additional row that is not connected with an indicator constraint, but can be used for separation
    9364 *
    9365 * @note The row is directly added to the alternative polyhedron and is not stored.
    9366 */
    9368 SCIP* scip, /**< SCIP data structure */
    9369 SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
    9370 SCIP_ROW* row /**< row to add */
    9371 )
    9372{
    9373 assert( scip != NULL );
    9374 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
    9375 assert( row != NULL );
    9376
    9377 /* skip local cuts (local cuts would require to dynamically add and remove columns from the alternative polyhedron */
    9378 if ( ! SCIProwIsLocal(row) )
    9379 {
    9380 int colindex;
    9381 SCIP_CONSHDLRDATA* conshdlrdata;
    9382
    9383 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9384 assert( conshdlrdata != NULL );
    9385
    9386 /* do not add rows if we do not separate */
    9387 if ( ! conshdlrdata->sepaalternativelp )
    9388 return SCIP_OKAY;
    9389
    9390 SCIPdebugMsg(scip, "Adding row <%s> to alternative LP.\n", SCIProwGetName(row));
    9391
    9392 /* add row directly to alternative polyhedron */
    9393 SCIP_CALL( addAltLPRow(scip, conshdlr, row, 0.0, &colindex) );
    9394 }
    9395
    9396 return SCIP_OKAY;
    9397}
    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:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define SCIP_REAL_MAX
    Definition: def.h:158
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_Bool
    Definition: def.h:91
    #define MAX3(x, y, z)
    Definition: def.h:228
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIPABORT()
    Definition: def.h:327
    #define SCIP_REAL_MIN
    Definition: def.h:159
    #define REALABS(x)
    Definition: def.h:182
    #define SCIP_CALL(x)
    Definition: def.h:355
    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:4778
    SCIP_RETCODE SCIPsetConshdlrGetDiveBdChgs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETDIVEBDCHGS((*consgetdivebdchgs)))
    Definition: scip_cons.c:877
    const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4316
    SCIP_RETCODE 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:4336
    SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
    Definition: scip_cons.c:601
    SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
    Definition: scip_cons.c:647
    int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4812
    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:5272
    SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4735
    SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
    Definition: scip_cons.c:785
    SCIP_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:8419
    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:8828
    SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
    Definition: cons.c:8648
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8409
    SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
    Definition: cons.c:8558
    SCIP_RETCODE 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:8841
    SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
    Definition: cons.c:8588
    SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
    Definition: cons.c:8518
    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:8698
    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:8578
    SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
    Definition: cons.c:8450
    SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    Definition: scip_cons.c:997
    SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
    Definition: cons.c:8608
    SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
    Definition: cons.c:8628
    SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
    Definition: cons.c:8486
    SCIP_RETCODE SCIPdisableCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1871
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8389
    SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1812
    SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
    Definition: cons.c:8638
    SCIP_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:8668
    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:8568
    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:8658
    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:3603
    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:17801
    SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
    Definition: var.c:23534
    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:23868
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23642
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23478
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23386
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4386
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23498
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    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:23900
    SCIP_Real SCIPvarGetAggrScalar(SCIP_VAR *var)
    Definition: var.c:23748
    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:23453
    SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
    Definition: scip_var.c:2499
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24142
    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:23662
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_VAR * SCIPbdchginfoGetVar(SCIP_BDCHGINFO *bdchginfo)
    Definition: var.c:24929
    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:23490
    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:24234
    SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
    Definition: var.c:23443
    SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
    Definition: var.c:23878
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24120
    SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:11057
    SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
    Definition: scip_var.c:10318
    SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6964
    SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
    Definition: scip_var.c:2736
    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:17642
    SCIP_BOUNDTYPE SCIPbdchginfoGetBoundtype(SCIP_BDCHGINFO *bdchginfo)
    Definition: var.c:24949
    SCIP_Real SCIPbdchginfoGetNewbound(SCIP_BDCHGINFO *bdchginfo)
    Definition: var.c:24919
    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:23736
    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