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-2022 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_indicator.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief constraint handler for indicator constraints
19  * @author Marc Pfetsch
20  *
21  * An indicator constraint is given by a binary variable \f$y\f$ and an inequality \f$ax \leq
22  * b\f$. It states that if \f$y = 1\f$ then \f$ax \leq b\f$ holds.
23  *
24  * This constraint is handled by adding a slack variable \f$s:\; ax - s \leq b\f$ with \f$s \geq
25  * 0\f$. The constraint is enforced by fixing \f$s\f$ to 0 if \f$y = 1\f$.
26  *
27  * @note The constraint only implements an implication not an equivalence, i.e., it does not ensure
28  * that \f$y = 1\f$ if \f$ax \leq b\f$ or equivalently if \f$s = 0\f$ holds.
29  *
30  * This constraint is equivalent to a linear constraint \f$ax - s \leq b\f$ and an SOS1 constraint on
31  * \f$y\f$ and \f$s\f$ (at most one should be nonzero). In the indicator context we can, however,
32  * separate more inequalities.
33  *
34  * The name indicator apparently comes from CPLEX.
35  *
36  *
37  * @section SEPARATION Separation Methods
38  *
39  * We now explain the handling of indicator constraints in more detail. The indicator constraint
40  * handler adds an inequality for each indicator constraint. We assume that this system (with added
41  * slack variables) is \f$ Ax - s \leq b \f$, where \f$ x \f$ are the original variables and \f$ s
42  * \f$ are the slack variables added by the indicator constraint. Variables \f$ y \f$ are the binary
43  * variables corresponding to the indicator constraints.
44  *
45  * @note In the implementation, we assume that bounds on the original variables \f$x\f$ cannot be
46  * influenced by the indicator constraint. If it should be possible to relax these constraints as
47  * well, then these constraints have to be added as indicator constraints.
48  *
49  * We separate inequalities by using the so-called alternative polyhedron.
50  *
51  *
52  * @section ALTERNATIVEPOLYHEDRON Separation via the Alternative Polyhedron
53  *
54  * We now describe the separation method of the first method in more detail.
55  *
56  * Consider the LP-relaxation of the current subproblem:
57  * \f[
58  * \begin{array}{ll}
59  * min & c^T x + d^T z\\
60  * & A x - s \leq b, \\
61  * & D x + C z \leq f, \\
62  * & l \leq x \leq u, \\
63  * & u \leq z \leq v, \\
64  * & 0 \leq s.
65  * \end{array}
66  * \f]
67  * As above \f$Ax - s \leq b\f$ contains all inequalities corresponding to indicator constraints,
68  * while the system \f$Dx + Cy \leq f\f$ contains all other inequalities (which are ignored in the
69  * following). Similarly, variables \f$z\f$ not appearing in indicator constraints are
70  * ignored. Bounds for the variables \f$x_j\f$ can be given, in particular, variables can be
71  * fixed. Note that \f$s \leq 0\f$ renders the system infeasible.
72  *
73  * To generate cuts, we construct the so-called @a alternative @a polyhedron:
74  * \f[
75  * \begin{array}{ll}
76  * P = \{ (w,r,t) : & A^T w - r + t = 0,\\
77  * & b^T w - l^T r + u^T t = -1,\\
78  * & w, r, t \geq 0 \}.
79  * \end{array}
80  * \f]
81  * Here, \f$r\f$ and \f$t\f$ correspond to the lower and upper bounds on \f$x\f$, respectively.
82  *
83  * It turns out that the vertices of \f$P\f$ correspond to minimal infeasible subsystems of \f$A x
84  * \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
85  * \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:
86  * \f[
87  * \sum_{i \in I} y_i \leq |I| - 1.
88  * \f]
89  *
90  *
91  * @subsection DETAIL Separation heuristic
92  *
93  * We separate the above inequalities by a heuristic described in
94  *
95  * Branch-And-Cut for the Maximum Feasible Subsystem Problem,@n
96  * Marc Pfetsch, SIAM Journal on Optimization 19, No.1, 21-38 (2008)
97  *
98  * The first step in the separation heuristic is to apply the transformation \f$\bar{y} = 1 - y\f$, which
99  * transforms the above inequality into the constraint
100  * \f[
101  * \sum_{i \in I} \bar{y}_i \geq 1,
102  * \f]
103  * that is, it is a set covering constraint on the negated variables.
104  *
105  * The basic idea is to use the current solution to the LP relaxation and use it as the objective,
106  * when optimizing of the alternative polyhedron. Since any vertex corresponds to such an
107  * inequality, we can check whether it is violated. To enlarge the chance that we find a @em
108  * violated inequality, we perform a fixing procedure, in which the variable corresponding to an
109  * arbitrary element of the last IIS \f$I\f$ is fixed to zero, i.e., cannot be used in the next
110  * IISs. This is repeated until the corresponding alternative polyhedron is infeasible, i.e., we
111  * have obtained an IIS-cover. For more details see the paper above.
112  *
113  *
114  * @subsection PREPROC Preprocessing
115  *
116  * Since each indicator constraint adds a linear constraint to the formulation, preprocessing of the
117  * linear constraints change the above approach as follows.
118  *
119  * The system as present in the formulation is the following (ignoring variables that are not
120  * contained in indicator constraints and the objective function):
121  * \f[
122  * \begin{array}{ll}
123  * & A x - s \leq b, \\
124  * & l \leq x \leq u, \\
125  * & s \leq 0.
126  * \end{array}
127  * \f]
128  * Note again that the requirement \f$s \leq 0\f$ leads to an infeasible system. Consider now the
129  * preprocessing of the linear constraint (aggregation, bound strengthening, etc.) and assume that
130  * this changes the above system to the following:
131  * \f[
132  * \begin{array}{ll}
133  * & \tilde{A} x - \tilde{B} s \leq \tilde{b}, \\
134  * & \tilde{l} \leq x \leq \tilde{u}, \\
135  * & s \leq 0. \\
136  * \end{array}
137  * \f]
138  * Note that we forbid multi-aggregation of the \f$s\f$ variables in order to be able to change their
139  * bounds in propagation/branching. The corresponding alternative system is the following:
140  * \f[
141  * \begin{array}{ll}
142  * & \tilde{A}^T w - r + t = 0,\\
143  * & - \tilde{B}^T w + v = 0,\\
144  * & b^T w - l^T r + u^T t = -1,\\
145  * & w, v, r, t \geq 0
146  * \end{array}
147  * \qquad \Leftrightarrow \qquad
148  * \begin{array}{ll}
149  * & \tilde{A}^T w - r + t = 0,\\
150  * & \tilde{B}^T w \geq 0,\\
151  * & b^T w - l^T r + u^T t = -1,\\
152  * & w, r, t \geq 0,
153  * \end{array}
154  * \f]
155  * where the second form arises by substituting \f$v \geq 0\f$. A closer look at this system reveals
156  * that it is not larger than the original one:
157  *
158  * - (Multi-)Aggregation of variables \f$x\f$ will remove these variables from the formulation, such that
159  * the corresponding column of \f$\tilde{A}\f$ (row of \f$\tilde{A}^T\f$) will be zero.
160  *
161  * - The rows of \f$\tilde{B}^T\f$ are not unit vectors, i.e., do not correspond to redundant
162  * nonnegativity constraints, only if the corresponding slack variables appear in an aggregation.
163  *
164  * Taken together, these two observations yield the conclusion that the new system is roughly as
165  * large as the original one.
166  *
167  * @note Because of possible (multi-)aggregation it might happen that the linear constraint
168  * corresponding to an indicator constraint becomes redundant and is deleted. From this we cannot
169  * conclude that the indicator constraint is redundant as well (i.e. always fulfilled), because the
170  * corresponding slack variable is still present and its setting to 0 might influence other
171  * (linear) constraints. Thus, we have to rely on the dual presolving of the linear constraints to
172  * detect this case: If the linear constraint is really redundant, i.e., is always fulfilled, it is
173  * deleted and the slack variable can be fixed to 0. In this case, the indicator constraint can be
174  * deleted as well.
175  *
176  * @todo Accept arbitrary ranged linear constraints as input (in particular: equations). Internally
177  * create two indicator constraints or correct alternative polyhedron accordingly (need to split the
178  * variables there, but not in original problem).
179  *
180  * @todo Treat variable upper bounds in a special way: Do not create the artificial slack variable,
181  * but directly enforce the propagations etc.
182  *
183  * @todo Turn off separation if the alternative polyhedron is infeasible and updateBounds is false.
184  *
185  * @todo Improve parsing of indicator constraint in CIP-format. Currently, we have to rely on a particular name, i.e.,
186  * the slack variable has to start with "indslack" and end with the name of the corresponding linear constraint.
187  *
188  * @todo Check whether one can further use the fact that the slack variable is aggregated.
189  */
190 
191 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
192 
193 #include "blockmemshell/memory.h"
194 #include "lpi/lpi.h"
195 #include "lpi/type_lpi.h"
196 #include "scip/expr_var.h"
197 #include "scip/expr_product.h"
198 #include "scip/cons_nonlinear.h"
199 #include "scip/cons_indicator.h"
200 #include "scip/cons_linear.h"
201 #include "scip/cons_logicor.h"
202 #include "scip/cons_varbound.h"
203 #include "scip/heur_indicator.h"
204 #include "scip/heur_trysol.h"
205 #include "scip/pub_conflict.h"
206 #include "scip/pub_cons.h"
207 #include "scip/pub_event.h"
208 #include "scip/pub_lp.h"
209 #include "scip/pub_message.h"
210 #include "scip/pub_misc.h"
211 #include "scip/pub_paramset.h"
212 #include "scip/pub_var.h"
213 #include "scip/scip_branch.h"
214 #include "scip/scip_conflict.h"
215 #include "scip/scip_cons.h"
216 #include "scip/scip_copy.h"
217 #include "scip/scip_cut.h"
218 #include "scip/scip_event.h"
219 #include "scip/scip_general.h"
220 #include "scip/scip_heur.h"
221 #include "scip/scip_lp.h"
222 #include "scip/scip_mem.h"
223 #include "scip/scip_message.h"
224 #include "scip/scip_nlp.h"
225 #include "scip/scip_numerics.h"
226 #include "scip/scip_param.h"
227 #include "scip/scip_prob.h"
228 #include "scip/scip_probing.h"
229 #include "scip/scip_sol.h"
230 #include "scip/scip_solve.h"
231 #include "scip/scip_solvingstats.h"
232 #include "scip/scip_tree.h"
233 #include "scip/scip_var.h"
234 #include <string.h>
235 
236 /* #define SCIP_OUTPUT */
237 /* #define SCIP_ENABLE_IISCHECK */
238 
239 /* constraint handler properties */
240 #define CONSHDLR_NAME "indicator"
241 #define CONSHDLR_DESC "indicator constraint handler"
242 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
243 #define CONSHDLR_ENFOPRIORITY -100 /**< priority of the constraint handler for constraint enforcing */
244 #define CONSHDLR_CHECKPRIORITY -6000000 /**< priority of the constraint handler for checking feasibility */
245 #define CONSHDLR_SEPAFREQ 10 /**< frequency for separating cuts; zero means to separate only in the root node */
246 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
247 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
248  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
249 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
250 #define CONSHDLR_DELAYSEPA FALSE /**< Should separation method be delayed, if other separators found cuts? */
251 #define CONSHDLR_DELAYPROP FALSE /**< Should propagation method be delayed, if other propagators found reductions? */
252 #define CONSHDLR_NEEDSCONS TRUE /**< Should the constraint handler be skipped, if no constraints are available? */
254 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_FAST
255 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
257 
258 /* event handler properties */
259 #define EVENTHDLR_BOUND_NAME "indicatorbound"
260 #define EVENTHDLR_BOUND_DESC "bound change event handler for indicator constraints"
262 #define EVENTHDLR_RESTART_NAME "indicatorrestart"
263 #define EVENTHDLR_RESTART_DESC "force restart if absolute gap is 1 or enough binary variables have been fixed"
265 
266 /* conflict handler properties */
267 #define CONFLICTHDLR_NAME "indicatorconflict"
268 #define CONFLICTHDLR_DESC "replace slack variables and generate logicor constraints"
269 #define CONFLICTHDLR_PRIORITY 200000
271 /* upgrade properties */
272 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
274 /* default values for parameters */
275 #define DEFAULT_BRANCHINDICATORS FALSE /**< Branch on indicator constraints in enforcing? */
276 #define DEFAULT_GENLOGICOR FALSE /**< Generate logicor constraints instead of cuts? */
277 #define DEFAULT_ADDCOUPLING TRUE /**< Add coupling constraints or rows if big-M is small enough? */
278 #define DEFAULT_MAXCOUPLINGVALUE 1e4 /**< maximum coefficient for binary variable in coupling constraint */
279 #define DEFAULT_ADDCOUPLINGCONS FALSE /**< Add initial variable upper bound constraints, if 'addcoupling' is true? */
280 #define DEFAULT_SEPACOUPLINGCUTS TRUE /**< Should the coupling inequalities be separated dynamically? */
281 #define DEFAULT_SEPACOUPLINGLOCAL FALSE /**< Allow to use local bounds in order to separate coupling inequalities? */
282 #define DEFAULT_SEPACOUPLINGVALUE 1e4 /**< maximum coefficient for binary variable in separated coupling constraint */
283 #define DEFAULT_SEPAALTERNATIVELP FALSE /**< Separate using the alternative LP? */
284 #define DEFAULT_SEPAPERSPECTIVE FALSE /**< Separate cuts based on perspective formulation? */
285 #define DEFAULT_SEPAPERSPLOCAL TRUE /**< Allow to use local bounds in order to separate perspectice cuts? */
286 #define DEFAULT_MAXSEPANONVIOLATED 3 /**< maximal number of separated non violated IISs, before separation is stopped */
287 #define DEFAULT_TRYSOLFROMCOVER FALSE /**< Try to construct a feasible solution from a cover? */
288 #define DEFAULT_UPGRADELINEAR FALSE /**< Try to upgrade linear constraints to indicator constraints? */
289 #define DEFAULT_USEOTHERCONSS FALSE /**< Collect other constraints to alternative LP? */
290 #define DEFAULT_USEOBJECTIVECUT FALSE /**< Use objective cut with current best solution to alternative LP? */
291 #define DEFAULT_UPDATEBOUNDS FALSE /**< Update bounds of original variables for separation? */
292 #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) */
293 #define DEFAULT_MAXSEPACUTS 100 /**< maximal number of cuts separated per separation round */
294 #define DEFAULT_MAXSEPACUTSROOT 2000 /**< maximal number of cuts separated per separation round in the root node */
295 #define DEFAULT_REMOVEINDICATORS FALSE /**< Remove indicator constraint if corresponding variable bound constraint has been added? */
296 #define DEFAULT_GENERATEBILINEAR FALSE /**< Do not generate indicator constraint, but a bilinear constraint instead? */
297 #define DEFAULT_SCALESLACKVAR FALSE /**< Scale slack variable coefficient at construction time? */
298 #define DEFAULT_NOLINCONSCONT FALSE /**< Decompose problem (do not generate linear constraint if all variables are continuous)? */
299 #define DEFAULT_TRYSOLUTIONS TRUE /**< Try to make solutions feasible by setting indicator variables? */
300 #define DEFAULT_ENFORCECUTS FALSE /**< In enforcing try to generate cuts (only if sepaalternativelp is true)? */
301 #define DEFAULT_DUALREDUCTIONS TRUE /**< Should dual reduction steps be performed? */
302 #define DEFAULT_ADDOPPOSITE FALSE /**< Add opposite inequality in nodes in which the binary variable has been fixed to 0? */
303 #define DEFAULT_CONFLICTSUPGRADE FALSE /**< Try to upgrade bounddisjunction conflicts by replacing slack variables? */
304 #define DEFAULT_FORCERESTART FALSE /**< Force restart if absolute gap is 1 or enough binary variables have been fixed? */
305 #define DEFAULT_RESTARTFRAC 0.9 /**< fraction of binary variables that need to be fixed before restart occurs (in forcerestart) */
307 
308 /* other values */
309 #define OBJEPSILON 0.001 /**< value to add to objective in alt. LP if the binary variable is 1 to get small IISs */
310 #define SEPAALTTHRESHOLD 10 /**< only separate IIS cuts if the number of separated coupling cuts is less than this value */
311 #define MAXROUNDINGROUNDS 1 /**< maximal number of rounds that produced cuts in separation */
313 
314 /** constraint data for indicator constraints */
315 struct SCIP_ConsData
316 {
317  SCIP_VAR* binvar; /**< binary variable for indicator constraint */
318  SCIP_VAR* slackvar; /**< slack variable of inequality of indicator constraint */
319  SCIP_CONS* lincons; /**< linear constraint corresponding to indicator constraint */
320  SCIP_Bool activeone; /**< whether the constraint is active on 1 or 0 */
321  SCIP_Bool lessthanineq; /**< whether the original linear constraint is less-than-rhs or greater-than-rhs */
322  int nfixednonzero; /**< number of variables among binvar and slackvar fixed to be nonzero */
323  int colindex; /**< column index in alternative LP */
324  unsigned int linconsactive:1; /**< whether linear constraint and slack variable are active */
325  unsigned int implicationadded:1; /**< whether corresponding implication has been added */
326  unsigned int slacktypechecked:1; /**< whether it has been checked to convert the slack variable to be implicit integer */
327 };
328 
329 
330 /** indicator constraint handler data */
331 struct SCIP_ConshdlrData
332 {
333  SCIP_EVENTHDLR* eventhdlrbound; /**< event handler for bound change events */
334  SCIP_EVENTHDLR* eventhdlrrestart; /**< event handler for performing restarts */
335  SCIP_Bool removable; /**< whether the separated cuts should be removable */
336  SCIP_Bool scaled; /**< if first row of alt. LP has been scaled */
337  SCIP_Bool objindicatoronly; /**< whether the objective is nonzero only for indicator variables */
338  SCIP_Bool objothervarsonly; /**< whether the objective is nonzero only for non-indicator variables */
339  SCIP_Real minabsobj; /**< minimum absolute nonzero objective of indicator variables */
340  SCIP_LPI* altlp; /**< alternative LP for cut separation */
341  int nrows; /**< # rows in the alt. LP corr. to original variables in linear constraints and slacks */
342  int nlbbounds; /**< # lower bounds of original variables */
343  int nubbounds; /**< # upper bounds of original variables */
344  SCIP_HASHMAP* varhash; /**< hash map from variable to row index in alternative LP */
345  SCIP_HASHMAP* lbhash; /**< hash map from variable to index of lower bound column in alternative LP */
346  SCIP_HASHMAP* ubhash; /**< hash map from variable to index of upper bound column in alternative LP */
347  SCIP_HASHMAP* slackhash; /**< hash map from slack variable to row index in alternative LP */
348  SCIP_HASHMAP* binvarhash; /**< hash map from binary indicator variable to indicator constraint */
349  int nslackvars; /**< # slack variables */
350  int niiscutsgen; /**< number of IIS-cuts generated */
351  int nperspcutsgen; /**< number of cuts based on perspective formulation generated */
352  int objcutindex; /**< index of objective cut in alternative LP (-1 if not added) */
353  SCIP_Real objupperbound; /**< best upper bound on objective known */
354  SCIP_Real objaltlpbound; /**< upper objective bound stored in alternative LP (infinity if not added) */
355  int maxroundingrounds; /**< maximal number of rounds that produced cuts in separation */
356  SCIP_Real roundingminthres; /**< minimal value for rounding in separation */
357  SCIP_Real roundingmaxthres; /**< maximal value for rounding in separation */
358  SCIP_Real roundingoffset; /**< offset for rounding in separation */
359  SCIP_Bool branchindicators; /**< Branch on indicator constraints in enforcing? */
360  SCIP_Bool genlogicor; /**< Generate logicor constraints instead of cuts? */
361  SCIP_Bool addcoupling; /**< whether the coupling inequalities should be added at the beginning */
362  SCIP_Bool addcouplingcons; /**< Add initial variable upper bound constraints, if 'addcoupling' is true? */
363  SCIP_Bool sepacouplingcuts; /**< Should the coupling inequalities be separated dynamically? */
364  SCIP_Bool sepacouplinglocal; /**< Allow to use local bounds in order to separate coupling inequalities? */
365  SCIP_Bool sepaperspective; /**< Separate cuts based on perspective formulation? */
366  SCIP_Bool sepapersplocal; /**< Allow to use local bounds in order to separate perspectice cuts? */
367  SCIP_Bool removeindicators; /**< Remove indicator constraint if corresponding variable bound constraint has been added? */
368  SCIP_Bool updatebounds; /**< whether the bounds of the original variables should be changed for separation */
369  SCIP_Bool trysolutions; /**< Try to make solutions feasible by setting indicator variables? */
370  SCIP_Bool enforcecuts; /**< in enforcing try to generate cuts (only if sepaalternativelp is true) */
371  SCIP_Bool dualreductions; /**< Should dual reduction steps be performed? */
372  SCIP_Bool addopposite; /**< Add opposite inequality in nodes in which the binary variable has been fixed to 0? */
373  SCIP_Bool generatebilinear; /**< Do not generate indicator constraint, but a bilinear constraint instead? */
374  SCIP_Bool scaleslackvar; /**< Scale slack variable coefficient at construction time? */
375  SCIP_Bool conflictsupgrade; /**< Try to upgrade bounddisjunction conflicts by replacing slack variables? */
376  SCIP_Bool performedrestart; /**< whether a restart has been performed already */
377  int maxsepacuts; /**< maximal number of cuts separated per separation round */
378  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in root node */
379  int maxsepanonviolated; /**< maximal number of separated non violated IISs, before separation is stopped */
380  int nbinvarszero; /**< binary variables globally fixed to zero */
381  int ninitconss; /**< initial number of indicator constraints (needed in event handlers) */
382  SCIP_Real maxcouplingvalue; /**< maximum coefficient for binary variable in initial coupling constraint */
383  SCIP_Real sepacouplingvalue; /**< maximum coefficient for binary variable in separated coupling constraint */
384  SCIP_Real maxconditionaltlp; /**< maximum estimated condition number of the alternative LP to trust its solution */
385  SCIP_Real restartfrac; /**< fraction of binary variables that need to be fixed before restart occurs (in forcerestart) */
386  SCIP_HEUR* heurtrysol; /**< trysol heuristic */
387  SCIP_Bool addedcouplingcons; /**< whether the coupling constraints have been added already */
388  SCIP_CONS** addlincons; /**< additional linear constraints that should be added to the alternative LP */
389  int naddlincons; /**< number of additional constraints */
390  int maxaddlincons; /**< maximal number of additional constraints */
391  SCIP_Bool useotherconss; /**< Collect other constraints to alternative LP? */
392  SCIP_Bool useobjectivecut; /**< Use objective cut with current best solution to alternative LP? */
393  SCIP_Bool trysolfromcover; /**< Try to construct a feasible solution from a cover? */
394  SCIP_Bool upgradelinear; /**< Try to upgrade linear constraints to indicator constraints? */
395  char normtype; /**< norm type for cut computation */
396  /* parameters that should not be changed after problem stage: */
397  SCIP_Bool sepaalternativelp; /**< Separate using the alternative LP? */
398  SCIP_Bool sepaalternativelp_; /**< used to store the sepaalternativelp parameter */
399  SCIP_Bool nolinconscont; /**< decompose problem - do not generate linear constraint if all variables are continuous */
400  SCIP_Bool nolinconscont_; /**< used to store the nolinconscont parameter */
401  SCIP_Bool forcerestart; /**< Force restart if absolute gap is 1 or enough binary variables have been fixed? */
402  SCIP_Bool forcerestart_; /**< used to store the forcerestart parameter */
403 };
404 
405 
406 /** indicator conflict handler data */
407 struct SCIP_ConflicthdlrData
408 {
409  SCIP_CONSHDLR* conshdlr; /**< indicator constraint handler */
410  SCIP_CONSHDLRDATA* conshdlrdata; /**< indicator constraint handler data */
411 };
412 
413 
414 /** type of enforcing/separation call */
416 {
417  SCIP_TYPE_ENFOLP = 0, /**< enforce LP */
418  SCIP_TYPE_ENFOPS = 1, /**< enforce pseudo solution */
419  SCIP_TYPE_ENFORELAX = 2, /**< enforce relaxation solution */
420  SCIP_TYPE_SEPALP = 3, /**< separate LP */
421  SCIP_TYPE_SEPARELAX = 4, /**< separate relaxation solution */
422  SCIP_TYPE_SEPASOL = 5 /**< separate relaxation solution */
423 };
426 
427 /* macro for parameters */
428 #define SCIP_CALL_PARAM(x) /*lint -e527 */ do \
429 { \
430  SCIP_RETCODE _restat_; \
431  if ( (_restat_ = (x)) != SCIP_OKAY && (_restat_ != SCIP_PARAMETERUNKNOWN) ) \
432  { \
433  SCIPerrorMessage("[%s:%d] Error <%d> in function call\n", __FILE__, __LINE__, _restat_); \
434  SCIPABORT(); \
435  return _restat_; \
436  } \
437 } \
438 while ( FALSE )
439 
440 
441 /* ---------------- Callback methods of event handlers ---------------- */
442 
443 /** execute the event handler for getting variable bound changes
444  *
445  * We update the number of variables fixed to be nonzero.
446  */
447 static
448 SCIP_DECL_EVENTEXEC(eventExecIndicatorBound)
449 {
450  SCIP_EVENTTYPE eventtype;
451  SCIP_CONSDATA* consdata;
452  SCIP_Real oldbound;
453  SCIP_Real newbound;
454 
455  assert( eventhdlr != NULL );
456  assert( eventdata != NULL );
457  assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_BOUND_NAME) == 0 );
458  assert( event != NULL );
459 
460  consdata = (SCIP_CONSDATA*)eventdata;
461  assert( consdata != NULL );
462  assert( 0 <= consdata->nfixednonzero && consdata->nfixednonzero <= 2 );
463  assert( consdata->linconsactive );
464 
465  oldbound = SCIPeventGetOldbound(event);
466  newbound = SCIPeventGetNewbound(event);
467 
468  eventtype = SCIPeventGetType(event);
469  switch ( eventtype )
470  {
472  /* if variable is now fixed to be positive */
473  if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
474  ++(consdata->nfixednonzero);
475 #ifdef SCIP_MORE_DEBUG
476  SCIPdebugMsg(scip, "Changed lower bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
477  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
478 #endif
479  break;
480 
482  /* if variable is now fixed to be negative */
483  if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
484  ++(consdata->nfixednonzero);
485 #ifdef SCIP_MORE_DEBUG
486  SCIPdebugMsg(scip, "Changed upper bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
487  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
488 #endif
489  break;
490 
492  /* if variable is not fixed to be positive anymore */
493  if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
494  --(consdata->nfixednonzero);
495 #ifdef SCIP_MORE_DEBUG
496  SCIPdebugMsg(scip, "Changed lower bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
497  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
498 #endif
499  break;
500 
502  /* if variable is not fixed to be negative anymore */
503  if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
504  --(consdata->nfixednonzero);
505 #ifdef SCIP_MORE_DEBUG
506  SCIPdebugMsg(scip, "Changed upper bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
507  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
508 #endif
509  break;
510 
511  default:
512  SCIPerrorMessage("Invalid event type.\n");
513  SCIPABORT();
514  return SCIP_INVALIDDATA; /*lint !e527*/
515  }
516  assert( 0 <= consdata->nfixednonzero && consdata->nfixednonzero <= 2 );
517 
518  return SCIP_OKAY;
519 }
520 
521 
522 /** exec the event handler for forcing a restart
523  *
524  * There are two cases in which we perform a (user) restart:
525  * - If we have a max FS instance, i.e., the objective is 1 for indicator variables and 0 otherwise,
526  * we can force a restart if the gap is 1. In this case, the remaining work consists of proving
527  * infeasibility of the non-fixed indicators.
528  * - If a large fraction of the binary indicator variables have been globally fixed, it makes sense
529  * to force a restart.
530  */
531 static
532 SCIP_DECL_EVENTEXEC(eventExecIndicatorRestart)
533 {
534  SCIP_CONSHDLRDATA* conshdlrdata;
535  SCIP_EVENTTYPE eventtype;
536 
537  assert( scip != NULL );
538  assert( eventhdlr != NULL );
539  assert( eventdata != NULL );
540  assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_RESTART_NAME) == 0 );
541  assert( event != NULL );
542 
543  conshdlrdata = (SCIP_CONSHDLRDATA*)eventdata;
544  assert( conshdlrdata != NULL );
545  assert( conshdlrdata->forcerestart );
546 
547  eventtype = SCIPeventGetType(event);
548  switch ( eventtype )
549  {
552  {
553 #ifndef NDEBUG
554  SCIP_Real oldbound;
555  SCIP_Real newbound;
556 
558  oldbound = SCIPeventGetOldbound(event);
559  newbound = SCIPeventGetNewbound(event);
560  assert( SCIPisIntegral(scip, oldbound) );
561  assert( SCIPisIntegral(scip, newbound) );
562  assert( ! SCIPisEQ(scip, oldbound, newbound) );
563  assert( SCIPisZero(scip, oldbound) || SCIPisEQ(scip, oldbound, 1.0) );
564  assert( SCIPisZero(scip, newbound) || SCIPisEQ(scip, newbound, 1.0) );
565 #endif
566 
567  /* do not treat this case if we have performed a restart already */
568  if ( conshdlrdata->performedrestart )
569  return SCIP_OKAY;
570 
571  /* variable is now fixed */
572  ++(conshdlrdata->nbinvarszero);
573  SCIPdebugMsg(scip, "Fixed variable <%s> (nbinvarszero: %d, total: %d).\n",
574  SCIPvarGetName(SCIPeventGetVar(event)), conshdlrdata->nbinvarszero, conshdlrdata->ninitconss);
575 
577  break;
578 
579  /* if enough variables have been fixed */
580  if ( conshdlrdata->nbinvarszero > (int) ((SCIP_Real) conshdlrdata->ninitconss * conshdlrdata->restartfrac) )
581  {
583  "Forcing restart, since %d binary variables among %d have been fixed.\n", conshdlrdata->nbinvarszero, conshdlrdata->ninitconss);
585 
586  /* drop event */
587  if ( conshdlrdata->objindicatoronly )
588  {
589  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, eventhdlr, (SCIP_EVENTDATA*) conshdlrdata, -1) );
590  }
591  conshdlrdata->performedrestart = TRUE;
592  }
593  break;
594  }
595 
597  assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
598  assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0 ) );
599 
601  break;
602 
603  if ( ! conshdlrdata->objindicatoronly )
604  break;
605 
606  /* if the absolute gap is equal to minabsobj */
607  if ( SCIPisEQ(scip, REALABS(SCIPgetPrimalbound(scip) - SCIPgetDualbound(scip)), conshdlrdata->minabsobj) )
608  {
609  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Forcing restart, since the absolute gap is %f.\n", conshdlrdata->minabsobj);
611 
612  /* use inference branching, since the objective is not meaningful */
613  if ( SCIPfindBranchrule(scip, "inference") != NULL && !SCIPisParamFixed(scip, "branching/inference/priority") )
614  {
615  SCIP_CALL( SCIPsetIntParam(scip, "branching/inference/priority", INT_MAX/4) );
616  }
617 
618  /* drop event */
619  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, eventhdlr, (SCIP_EVENTDATA*) conshdlrdata, -1) );
620  conshdlrdata->performedrestart = TRUE;
621  }
622  break;
623 
624  default:
625  SCIPerrorMessage("invalid event type.\n");
626  SCIPABORT();
627  return SCIP_INVALIDDATA; /*lint !e527*/
628  }
629 
630  return SCIP_OKAY;
631 }
632 
633 
634 /* ------------------------ conflict handler ---------------------------------*/
635 
636 /** destructor of conflict handler to free conflict handler data (called when SCIP is exiting) */
637 static
638 SCIP_DECL_CONFLICTFREE(conflictFreeIndicator)
639 {
640  SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
641 
642  assert( scip != NULL );
643  assert( conflicthdlr != NULL );
644  assert( strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0 );
645 
646  conflicthdlrdata = SCIPconflicthdlrGetData(conflicthdlr);
647  SCIPfreeBlockMemory(scip, &conflicthdlrdata);
648 
649  return SCIP_OKAY;
650 }
651 
652 
653 /** conflict processing method of conflict handler (called when conflict was found)
654  *
655  * In this conflict handler we try to replace slack variables by binary indicator variables and
656  * generate a logicor constraint if possible.
657  *
658  * @todo Extend to integral case.
659  */
660 static
661 SCIP_DECL_CONFLICTEXEC(conflictExecIndicator)
662 { /*lint --e{715}*/
663  SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
664  SCIP_Bool haveslack;
665  SCIP_VAR* var;
666  int i;
667 
668  assert( conflicthdlr != NULL );
669  assert( strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0 );
670  assert( bdchginfos != NULL || nbdchginfos == 0 );
671  assert( result != NULL );
672 
673  /* don't process already resolved conflicts */
674  if ( resolved )
675  {
676  *result = SCIP_DIDNOTRUN;
677  return SCIP_OKAY;
678  }
679 
680  SCIPdebugMsg(scip, "Indicator conflict handler.\n");
681 
682  conflicthdlrdata = SCIPconflicthdlrGetData(conflicthdlr);
683  assert( conflicthdlrdata != NULL );
684 
685  /* possibly skip conflict handler */
686  if ( ! ((SCIP_CONFLICTHDLRDATA*) conflicthdlrdata)->conshdlrdata->conflictsupgrade )
687  return SCIP_OKAY;
688 
689  *result = SCIP_DIDNOTFIND;
690 
691  /* check whether there seems to be one slack variable and all other variables are binary */
692  haveslack = FALSE;
693  for (i = 0; i < nbdchginfos; ++i)
694  {
695  assert( bdchginfos != NULL ); /* for flexelint */
696  assert( bdchginfos[i] != NULL );
697 
698  var = SCIPbdchginfoGetVar(bdchginfos[i]);
699 
700  /* quick check for slack variable that is implicitly integral or continuous */
702  {
703  /* check string */
704  if ( strstr(SCIPvarGetName(var), "indslack") != NULL )
705  {
706  /* make sure that the slack variable occurs with its lower bound */
708  break;
709 
710  /* make sure that the lower bound is 0 */
711  if ( ! SCIPisFeasZero(scip, SCIPbdchginfoGetNewbound(bdchginfos[i])) )
712  break;
713 
714  haveslack = TRUE;
715  continue;
716  }
717  }
718 
719  /* we only treat binary variables (other than slack variables) */
720  if ( ! SCIPvarIsBinary(var) )
721  break;
722  }
723 
724  /* if we have found at least one slack variable and all other variables are binary */
725  if ( haveslack && i == nbdchginfos )
726  {
727  SCIP_CONS** conss;
728  SCIP_VAR** vars;
729  int nconss;
730  int j;
731 
732  SCIPdebugMsg(scip, "Found conflict involving slack variables that can be remodelled.\n");
733 
734  assert( conflicthdlrdata->conshdlr != NULL );
735  assert( strcmp(SCIPconshdlrGetName(conflicthdlrdata->conshdlr), CONSHDLR_NAME) == 0 );
736 
737  nconss = SCIPconshdlrGetNConss(conflicthdlrdata->conshdlr);
738  conss = SCIPconshdlrGetConss(conflicthdlrdata->conshdlr);
739 
740  /* create array of variables in conflict constraint */
741  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nbdchginfos) );
742  for (i = 0; i < nbdchginfos; ++i)
743  {
744  assert( bdchginfos != NULL ); /* for flexelint */
745  assert( bdchginfos[i] != NULL );
746 
747  var = SCIPbdchginfoGetVar(bdchginfos[i]);
748 
749  SCIPdebugMsg(scip, " <%s> %s %g\n", SCIPvarGetName(var), SCIPbdchginfoGetBoundtype(bdchginfos[i]) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
750  SCIPbdchginfoGetNewbound(bdchginfos[i]));
751 
752  /* quick check for slack variable that is implicitly integral or continuous */
753  if ( (SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS) && strstr(SCIPvarGetName(var), "indslack") != NULL )
754  {
755  SCIP_VAR* slackvar;
756 
757  /* search for slack variable */
758  for (j = 0; j < nconss; ++j)
759  {
760  assert( conss[j] != NULL );
761  slackvar = SCIPgetSlackVarIndicator(conss[j]);
762  assert( slackvar != NULL );
763 
764  /* check whether we found the variable */
765  if ( slackvar == var )
766  {
767  /* replace slack variable by binary variable */
768  var = SCIPgetBinaryVarIndicator(conss[j]);
769  break;
770  }
771  }
772 
773  /* check whether we found the slack variable */
774  if ( j >= nconss )
775  {
776  SCIPdebugMsg(scip, "Could not find slack variable <%s>.\n", SCIPvarGetName(var));
777  break;
778  }
779  }
780  else
781  {
782  /* if the variable is fixed to one in the conflict set, we have to use its negation */
783  if ( SCIPbdchginfoGetNewbound(bdchginfos[i]) > 0.5 )
784  {
785  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
786  }
787  }
788 
789  vars[i] = var;
790  }
791 
792  /* whether all slack variables have been found */
793  if ( i == nbdchginfos )
794  {
795  SCIP_CONS* cons;
796  char consname[SCIP_MAXSTRLEN];
797 
798  SCIPdebugMsg(scip, "Generated logicor conflict constraint.\n");
799 
800  /* create a logicor constraint out of the conflict set */
801  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cf%d_%" SCIP_LONGINT_FORMAT, SCIPgetNRuns(scip), SCIPgetNConflictConssApplied(scip));
802  SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, consname, nbdchginfos, vars,
803  FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) );
804 
805 #ifdef SCIP_OUTPUT
806  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
807  SCIPinfoMessage(scip, NULL, ";\n");
808 #endif
809 
810  /* add constraint to SCIP */
811  SCIP_CALL( SCIPaddConflict(scip, node, cons, validnode, conftype, cutoffinvolved) );
812 
813  *result = SCIP_CONSADDED;
814  }
815 
816  /* free temporary memory */
817  SCIPfreeBufferArray(scip, &vars);
818  }
819 
820  return SCIP_OKAY;
821 }
822 
823 
824 /* ------------------------ parameter handling ---------------------------------*/
825 
826 /** check whether we transfer a changed parameter to the given value
827  *
828  * @see paramChangedIndicator()
829  */
830 static
832  SCIP* scip, /**< SCIP data structure */
833  SCIP_PARAM* param, /**< parameter */
834  const char* name, /**< parameter name to check */
835  SCIP_Bool newvalue, /**< new value */
836  SCIP_Bool* value /**< old and possibly changed value of parameter */
837  )
838 {
839  const char* paramname;
840 
841  assert( scip != NULL );
842  assert( param != NULL );
843  assert( name != NULL );
844  assert( value != NULL );
845 
846  if ( SCIPparamGetType(param) != SCIP_PARAMTYPE_BOOL )
847  return SCIP_OKAY;
848 
849  if ( *value == newvalue )
850  return SCIP_OKAY;
851 
852  paramname = SCIPparamGetName(param);
853  assert( paramname != NULL );
854 
855  /* check whether the change parameter corresponds to our name to check */
856  if ( strcmp(paramname, name) == 0 )
857  {
858  /* check stage and possibly ignore parameter change */
859  if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM )
860  {
861  SCIPwarningMessage(scip, "Cannot change parameter <%s> stage %d - reset to old value %s.\n", name, SCIPgetStage(scip), *value ? "true" : "false");
862  /* Note that the following command will create a recursive call, but then *value == newvalue above. */
863  SCIP_CALL( SCIPchgBoolParam(scip, param, *value) );
864  }
865  else
866  {
867  /* otherwise copy value */
868  *value = newvalue;
869  }
870  }
871 
872  return SCIP_OKAY;
873 }
874 
875 
876 /** called after a parameter has been changed */
877 static
878 SCIP_DECL_PARAMCHGD(paramChangedIndicator)
879 {
880  SCIP_CONSHDLR* conshdlr;
881  SCIP_CONSHDLRDATA* conshdlrdata;
882 
883  assert( scip != NULL );
884  assert( param != NULL );
885 
886  /* get indicator constraint handler */
887  conshdlr = SCIPfindConshdlr(scip, "indicator");
888  assert( conshdlr != NULL );
889 
890  /* get constraint handler data */
891  conshdlrdata = SCIPconshdlrGetData(conshdlr);
892  assert( conshdlrdata != NULL );
893 
894  SCIP_CALL( checkTransferBoolParam(scip, param, "constraints/indicator/sepaalternativelp", conshdlrdata->sepaalternativelp_, &conshdlrdata->sepaalternativelp) );
895  SCIP_CALL( checkTransferBoolParam(scip, param, "constraints/indicator/forcerestart", conshdlrdata->forcerestart_, &conshdlrdata->forcerestart) );
896  SCIP_CALL( checkTransferBoolParam(scip, param, "constraints/indicator/nolinconscont", conshdlrdata->nolinconscont_, &conshdlrdata->nolinconscont) );
897 
898  return SCIP_OKAY;
899 }
900 
901 
902 /* ------------------------ debugging routines ---------------------------------*/
903 
904 #ifdef SCIP_ENABLE_IISCHECK
905 /** Check that indicator constraints corresponding to nonnegative entries in @a vector are infeasible in original problem
906  *
907  * @note This function will probably fail if the has been presolved by the cons_linear presolver. To make it complete
908  * we would have to substitute active variables.
909  */
910 static
911 SCIP_RETCODE checkIIS(
912  SCIP* scip, /**< SCIP pointer */
913  int nconss, /**< number of constraints */
914  SCIP_CONS** conss, /**< indicator constraints */
915  SCIP_Real* vector /**< vector */
916  )
917 {
918  SCIP_CONSHDLRDATA* conshdlrdata;
919  SCIP_CONSHDLR* conshdlr;
920  SCIP_HASHMAP* varhash; /* hash map from variable to column index in auxiliary LP */
921  SCIP_LPI* lp;
922  int nvars = 0;
923  int c;
924 
925  assert( scip != NULL );
926  assert( vector != NULL );
927 
928  SCIPdebugMsg(scip, "Checking IIS ...\n");
929 
930  /* now check indicator constraints */
931  conshdlr = SCIPfindConshdlr(scip, "indicator");
932  assert( conshdlr != NULL );
933 
934  conshdlrdata = SCIPconshdlrGetData(conshdlr);
935  assert( conshdlrdata != NULL );
936 
937  conss = SCIPconshdlrGetConss(conshdlr);
938  nconss = SCIPconshdlrGetNConss(conshdlr);
939 
940  /* create LP */
942 
943  /* set up hash map */
944  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
945 
946  /* loop through indicator constraints */
947  for (c = 0; c < nconss; ++c)
948  {
949  SCIP_CONSDATA* consdata;
950  consdata = SCIPconsGetData(conss[c]);
951  assert( consdata != NULL );
952 
953  /* check whether constraint should be included */
954  if ( consdata->colindex >= 0 && (! SCIPisFeasZero(scip, vector[consdata->colindex]) || ! SCIPconsIsEnabled(conss[c])) )
955  {
956  SCIP_CONS* lincons;
957  SCIP_VAR** linvars;
958  SCIP_Real* linvals;
959  SCIP_Real linrhs;
960  SCIP_Real linlhs;
961  SCIP_VAR* slackvar;
962  int nlinvars;
963  SCIP_Real sign = 1.0;
964  int matbeg;
965  int* matind;
966  SCIP_Real* matval;
967  SCIP_VAR** newvars;
968  int nnewvars;
969  SCIP_Real lhs;
970  SCIP_Real rhs;
971  int cnt;
972  int v;
973 
974  lincons = consdata->lincons;
975  assert( lincons != NULL );
976  assert( ! SCIPconsIsEnabled(conss[c]) || SCIPconsIsActive(lincons) );
977  assert( ! SCIPconsIsEnabled(conss[c]) || SCIPconsIsEnabled(lincons) );
978 
979  slackvar = consdata->slackvar;
980  assert( slackvar != NULL );
981 
982  /* if the slack variable is aggregated (multi-aggregation should not happen) */
983  assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
984  if ( SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
985  {
986  SCIP_VAR* var;
987  SCIP_Real scalar = 1.0;
988  SCIP_Real constant = 0.0;
989 
990  var = slackvar;
991 
992  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
993  assert( ! SCIPisZero(scip, scalar) );
994 
995  /* SCIPdebugMsg(scip, "slack variable aggregated (scalar: %f, constant: %f)\n", scalar, constant); */
996 
997  /* otherwise construct a linear constraint */
998  SCIP_CALL( SCIPallocBufferArray(scip, &linvars, 1) );
999  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, 1) );
1000  linvars[0] = var;
1001  linvals[0] = scalar;
1002  nlinvars = 1;
1003  linlhs = -SCIPinfinity(scip);
1004  linrhs = constant;
1005  }
1006  else
1007  {
1008  /* in this case, the linear constraint is directly usable */
1009  linvars = SCIPgetVarsLinear(scip, lincons);
1010  linvals = SCIPgetValsLinear(scip, lincons);
1011  nlinvars = SCIPgetNVarsLinear(scip, lincons);
1012  linlhs = SCIPgetLhsLinear(scip, lincons);
1013  linrhs = SCIPgetRhsLinear(scip, lincons);
1014  }
1015 
1016  /* adapt rhs of linear constraint */
1017  assert( SCIPisInfinity(scip, -linlhs) || SCIPisInfinity(scip, linrhs) );
1018  if ( SCIPisInfinity(scip, linrhs) )
1019  {
1020  linrhs = -linlhs;
1021  assert( linrhs > -SCIPinfinity(scip) );
1022  sign = -1.0;
1023  }
1024 
1025  SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4*nlinvars) );
1026  SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4*nlinvars) );
1027  SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nlinvars) );
1028 
1029  /* set up row */
1030  nnewvars = 0;
1031  for (v = 0; v < nlinvars; ++v)
1032  {
1033  SCIP_VAR* var;
1034  var = linvars[v];
1035  assert( var != NULL );
1036 
1037  /* skip slack variable */
1038  if ( var == slackvar )
1039  continue;
1040 
1041  /* if variable is new */
1042  if ( ! SCIPhashmapExists(varhash, var) )
1043  {
1044  /* add variable in map */
1045  SCIP_CALL( SCIPhashmapInsertInt(varhash, var, nvars) );
1046  assert( nvars == SCIPhashmapGetImageInt(varhash, var) );
1047  /* SCIPdebugMsg(scip, "Inserted variable <%s> into hashmap (%d).\n", SCIPvarGetName(var), nvars); */
1048  nvars++;
1049 
1050  /* store new variables */
1051  newvars[nnewvars++] = var;
1052  }
1053  assert( SCIPhashmapExists(varhash, var) );
1054  }
1055 
1056  /* add new columns */
1057  if ( nnewvars > 0 )
1058  {
1059  SCIP_Real* lb;
1060  SCIP_Real* ub;
1061  SCIP_Real* obj;
1062  char** colnames;
1063 
1064  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nnewvars) );
1065  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nnewvars) );
1066  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nnewvars) );
1067  SCIP_CALL( SCIPallocBufferArray(scip, &colnames, nnewvars) );
1068 
1069  for (v = 0; v < nnewvars; ++v)
1070  {
1071  SCIP_VAR* var;
1072  var = newvars[v];
1073  obj[v] = 0.0;
1074  lb[v] = SCIPvarGetLbLocal(var);
1075  ub[v] = SCIPvarGetUbLocal(var);
1076  SCIP_CALL( SCIPallocBufferArray(scip, &(colnames[v]), SCIP_MAXSTRLEN) ); /*lint !e866*/
1077  (void) SCIPsnprintf(colnames[v], SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var));
1078  }
1079 
1080  /* now add columns */
1081  SCIP_CALL( SCIPlpiAddCols(lp, nnewvars, obj, lb, ub, colnames, 0, NULL, NULL, NULL) );
1082 
1083  for (v = nnewvars - 1; v >= 0; --v)
1084  {
1085  SCIPfreeBufferArray(scip, &(colnames[v]));
1086  }
1087  SCIPfreeBufferArray(scip, &colnames);
1088  SCIPfreeBufferArray(scip, &obj);
1089  SCIPfreeBufferArray(scip, &ub);
1090  SCIPfreeBufferArray(scip, &lb);
1091  }
1092 
1093  /* set up row */
1094  cnt = 0;
1095  for (v = 0; v < nlinvars; ++v)
1096  {
1097  SCIP_VAR* var;
1098  var = linvars[v];
1099  assert( var != NULL );
1100 
1101  /* skip slack variable */
1102  if ( var == slackvar )
1103  continue;
1104 
1105  assert( SCIPhashmapExists(varhash, var) );
1106  matind[cnt] = SCIPhashmapGetImageInt(varhash, var);
1107  matval[cnt] = sign * linvals[v];
1108  ++cnt;
1109  }
1110 
1111  lhs = -SCIPlpiInfinity(lp);
1112  rhs = linrhs;
1113 
1114  /* add new row */
1115  matbeg = 0;
1116  SCIP_CALL( SCIPlpiAddRows(lp, 1, &lhs, &rhs, NULL, cnt, &matbeg, matind, matval) );
1117 
1118  SCIPfreeBufferArray(scip, &matind);
1119  SCIPfreeBufferArray(scip, &matval);
1120  SCIPfreeBufferArray(scip, &newvars);
1121 
1122  assert( slackvar != NULL );
1123  if ( SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
1124  {
1125  SCIPfreeBufferArray(scip, &linvals);
1126  SCIPfreeBufferArray(scip, &linvars);
1127  }
1128  }
1129  }
1130 
1131  /* possibly handle additional linear constraints */
1132  if ( conshdlrdata->useotherconss )
1133  {
1134  /* get all linear constraints */
1135  conss = SCIPgetConss(scip);
1136  nconss = SCIPgetNConss(scip);
1137 
1138  /* loop through constraints */
1139  for (c = 0; c < nconss; ++c)
1140  {
1141  SCIP_CONS* cons;
1142  SCIP_VAR** linvars;
1143  SCIP_Real* linvals;
1144  SCIP_Real linrhs;
1145  SCIP_Real linlhs;
1146  SCIP_Real* matval;
1147  SCIP_VAR** newvars;
1148  int nnewvars = 0;
1149  int* matind;
1150  int nlinvars;
1151  int matbeg = 0;
1152  int cnt = 0;
1153  int v;
1154 
1155  cons = conss[c];
1156  assert( cons != NULL );
1157 
1158  /* avoid non-active, local constraints */
1159  if ( ! SCIPconsIsEnabled(cons) || ! SCIPconsIsActive(cons) || SCIPconsIsLocal(cons) )
1160  continue;
1161 
1162  /* check type of constraint (only take linear constraints) */
1163  if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") != 0 )
1164  continue;
1165 
1166  /* avoid adding linear constraints that correspond to indicator constraints */
1167  if ( strncmp(SCIPconsGetName(cons), "indlin", 6) == 0 )
1168  continue;
1169 
1170  /* get data of linear constraint */
1171  linvars = SCIPgetVarsLinear(scip, cons);
1172  linvals = SCIPgetValsLinear(scip, cons);
1173  nlinvars = SCIPgetNVarsLinear(scip, cons);
1174  linlhs = SCIPgetLhsLinear(scip, cons);
1175  linrhs = SCIPgetRhsLinear(scip, cons);
1176 
1177  /* reserve space */
1178  SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4*nlinvars) );
1179  SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4*nlinvars) );
1180  SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nlinvars) );
1181 
1182  /* collect possibly new variables */
1183  for (v = 0; v < nlinvars; ++v)
1184  {
1185  SCIP_VAR* var;
1186  var = linvars[v];
1187  assert( var != NULL );
1188 
1189  /* if variable is new */
1190  if ( ! SCIPhashmapExists(varhash, var) )
1191  {
1192  /* add variable in map */
1193  SCIP_CALL( SCIPhashmapInsertInt(varhash, var, nvars) );
1194  assert( nvars == SCIPhashmapGetImageInt(varhash, var) );
1195  /* SCIPdebugMsg(scip, "Inserted variable <%s> into hashmap (%d).\n", SCIPvarGetName(var), nvars); */
1196  nvars++;
1197 
1198  /* store new variables */
1199  newvars[nnewvars++] = var;
1200  }
1201  assert( SCIPhashmapExists(varhash, var) );
1202  }
1203 
1204  /* add new columns */
1205  if ( nnewvars > 0 )
1206  {
1207  SCIP_Real* lb;
1208  SCIP_Real* ub;
1209  SCIP_Real* obj;
1210  char** colnames;
1211 
1212  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nnewvars) );
1213  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nnewvars) );
1214  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nnewvars) );
1215  SCIP_CALL( SCIPallocBufferArray(scip, &colnames, nnewvars) );
1216 
1217  for (v = 0; v < nnewvars; ++v)
1218  {
1219  SCIP_VAR* var;
1220  var = newvars[v];
1221  obj[v] = 0.0;
1222  lb[v] = SCIPvarGetLbLocal(var);
1223  ub[v] = SCIPvarGetUbLocal(var);
1224  SCIP_CALL( SCIPallocBufferArray(scip, &(colnames[v]), SCIP_MAXSTRLEN) ); /*lint !e866*/
1225  (void) SCIPsnprintf(colnames[v], SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var));
1226  }
1227 
1228  /* now add columns */
1229  SCIP_CALL( SCIPlpiAddCols(lp, nnewvars, obj, lb, ub, colnames, 0, NULL, NULL, NULL) );
1230 
1231  for (v = nnewvars - 1; v >= 0; --v)
1232  {
1233  SCIPfreeBufferArray(scip, &(colnames[v]));
1234  }
1235  SCIPfreeBufferArray(scip, &colnames);
1236  SCIPfreeBufferArray(scip, &obj);
1237  SCIPfreeBufferArray(scip, &ub);
1238  SCIPfreeBufferArray(scip, &lb);
1239  }
1240 
1241  /* set up row */
1242  for (v = 0; v < nlinvars; ++v)
1243  {
1244  SCIP_VAR* var;
1245  var = linvars[v];
1246  assert( var != NULL );
1247 
1248  assert( SCIPhashmapExists(varhash, var) );
1249  matind[cnt] = SCIPhashmapGetImageInt(varhash, var);
1250  matval[cnt] = linvals[v];
1251  ++cnt;
1252  }
1253 
1254  /* add new row */
1255  SCIP_CALL( SCIPlpiAddRows(lp, 1, &linlhs, &linrhs, NULL, cnt, &matbeg, matind, matval) );
1256 
1257  SCIPfreeBufferArray(scip, &matind);
1258  SCIPfreeBufferArray(scip, &matval);
1259  SCIPfreeBufferArray(scip, &newvars);
1260  }
1261  }
1262 
1263  /* solve LP and check status */
1265 
1266  if ( ! SCIPlpiIsPrimalInfeasible(lp) )
1267  {
1268  SCIPerrorMessage("Detected IIS is not infeasible in original problem!\n");
1269 
1270  SCIP_CALL( SCIPlpiWriteLP(lp, "check.lp") );
1271  SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "altdebug.lp") );
1272  SCIPABORT();
1273  return SCIP_ERROR; /*lint !e527*/
1274  }
1275  SCIPdebugMsg(scip, "Check successful!\n");
1276 
1277  SCIPhashmapFree(&varhash);
1278  SCIP_CALL( SCIPlpiFree(&lp) );
1279 
1280  return SCIP_OKAY;
1281 }
1282 #endif
1283 
1284 
1285 /* ------------------------ auxiliary operations -------------------------------*/
1286 
1287 /** return objective contribution of variable
1288  *
1289  * Special treatment of negated variables: return negative of objective of original
1290  * variable. SCIPvarGetObj() would return 0 in these cases.
1291  */
1292 static
1294  SCIP_VAR* var /**< variable */
1295  )
1296 {
1297  if ( SCIPvarIsBinary(var) && SCIPvarIsNegated(var) )
1298  {
1299  assert( SCIPvarGetNegatedVar(var) != NULL );
1300  return -SCIPvarGetObj(SCIPvarGetNegatedVar(var));
1301  }
1302  else if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED )
1303  {
1304  assert( SCIPvarGetAggrVar(var) != NULL );
1306  }
1307 
1308  return SCIPvarGetObj(var);
1309 }
1310 
1311 
1312 /** ensures that the addlincons array can store at least num entries */
1313 static
1315  SCIP* scip, /**< SCIP data structure */
1316  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1317  int num /**< minimum number of entries to store */
1318  )
1319 {
1320  SCIP_CONSHDLRDATA* conshdlrdata;
1321 
1322  assert( scip != NULL );
1323  assert( conshdlr != NULL );
1324  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1325 
1326  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1327  assert( conshdlrdata != NULL );
1328  assert( conshdlrdata->naddlincons <= conshdlrdata->maxaddlincons );
1329 
1330  if ( num > conshdlrdata->maxaddlincons )
1331  {
1332  int newsize;
1333 
1334  newsize = SCIPcalcMemGrowSize(scip, num);
1335  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons, newsize) );
1336  conshdlrdata->maxaddlincons = newsize;
1337  }
1338  assert( num <= conshdlrdata->maxaddlincons );
1339 
1340  return SCIP_OKAY;
1341 }
1342 
1343 
1344 /* ------------------------ operations on the alternative LP -------------------*/
1345 
1346 /** initialize alternative LP
1347  *
1348  * The alternative system is organized as follows:
1349  * - The first row corresponds to the right hand side of the original system.
1350  * - The next nconss constraints correspond to the slack variables.
1351  * - The rows after that correspond to the original variables.
1352  */
1353 static
1355  SCIP* scip, /**< SCIP pointer */
1356  SCIP_CONSHDLR* conshdlr /**< constraint handler */
1357  )
1358 {
1359  SCIP_CONSHDLRDATA* conshdlrdata;
1360  SCIP_Real lhs = -1.0;
1361  SCIP_Real rhs = -1.0;
1362 
1363  assert( scip != NULL );
1364  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1365 
1366  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1367  assert( conshdlrdata != NULL );
1368  assert( conshdlrdata->altlp == NULL );
1369  assert( conshdlrdata->varhash == NULL );
1370  assert( conshdlrdata->lbhash == NULL );
1371  assert( conshdlrdata->ubhash == NULL );
1372  assert( conshdlrdata->slackhash != NULL );
1373 
1374  /* create hash map of variables */
1375  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
1376  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->lbhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
1377  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->ubhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
1378 
1379  /* create alternative LP */
1380  SCIP_CALL( SCIPlpiCreate(&conshdlrdata->altlp, SCIPgetMessagehdlr(scip), "altlp", SCIP_OBJSEN_MINIMIZE) );
1381 
1382  /* add first row */
1383  SCIP_CALL( SCIPlpiAddRows(conshdlrdata->altlp, 1, &lhs, &rhs, NULL, 0, NULL, NULL, NULL) );
1384  conshdlrdata->nrows = 1;
1385 
1386  /* set parameters */
1388  SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_PRESOLVING, TRUE) );
1389  SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_SCALING, 1) );
1390  SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_FASTMIP, FALSE) );
1391 
1392  SCIPdebugMsg(scip, "Initialized alternative LP.\n");
1393 
1394  /* uncomment the following for debugging */
1395  /* SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_LPINFO, TRUE) ); */
1396 
1397  return SCIP_OKAY;
1398 }
1399 
1400 
1401 /** check whether the bounds in given (alternative) LP are set correctly (for debugging) */
1402 #ifndef NDEBUG
1403 static
1405  SCIP* scip, /**< SCIP pointer */
1406  SCIP_LPI* lp, /**< LP for which bounds should be checked */
1407  int nconss, /**< number of constraints */
1408  SCIP_CONS** conss /**< constraints */
1409  )
1410 {
1411  SCIP_Real* lb;
1412  SCIP_Real* ub;
1413  SCIP_Bool* covered;
1414  int nCols;
1415  int j;
1416 
1417  assert( scip != NULL );
1418  assert( lp != NULL );
1419 
1420  SCIP_CALL( SCIPlpiGetNCols(lp, &nCols) );
1421 
1422  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nCols) );
1423  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nCols) );
1424  SCIP_CALL( SCIPallocBufferArray(scip, &covered, nCols) );
1425 
1426  for (j = 0; j < nCols; ++j)
1427  covered[j] = FALSE;
1428 
1429  /* check columns used by constraints */
1430  SCIP_CALL( SCIPlpiGetBounds(lp, 0, nCols-1, lb, ub) );
1431  for (j = 0; j < nconss; ++j)
1432  {
1433  SCIP_CONSDATA* consdata;
1434  int ind;
1435 
1436  assert( conss[j] != NULL );
1437  consdata = SCIPconsGetData(conss[j]);
1438  assert( consdata != NULL );
1439  ind = consdata->colindex;
1440 
1441  if ( ind >= 0 )
1442  {
1443  assert( ind < nCols );
1444  covered[ind] = TRUE;
1445  if ( ! SCIPisFeasZero(scip, lb[ind]) || ! SCIPlpiIsInfinity(lp, ub[ind]) )
1446  {
1447  SCIPABORT();
1448  }
1449  }
1450  }
1451 
1452  /* check other columns */
1453  for (j = 0; j < nCols; ++j)
1454  {
1455  if (! covered[j] )
1456  {
1457  /* some columns can be fixed to 0, since they correspond to disabled constraints */
1458  if ( ( ! SCIPlpiIsInfinity(lp, -lb[j]) && ! SCIPisFeasZero(scip, lb[j])) || (! SCIPlpiIsInfinity(lp, ub[j]) && ! SCIPisFeasZero(scip, ub[j])) )
1459  {
1460  SCIPABORT();
1461  }
1462  }
1463  }
1464 
1465  SCIPfreeBufferArray(scip, &covered);
1466  SCIPfreeBufferArray(scip, &lb);
1467  SCIPfreeBufferArray(scip, &ub);
1468 
1469  return SCIP_OKAY;
1470 }
1471 #endif
1472 
1473 
1474 /** set the alternative system objective function
1475  *
1476  * We assume that the objective function coefficients of the variables other than the binary
1477  * indicators are always 0 and hence do not have to be changed.
1478  *
1479  * We already use the tranformation \f$y' = 1 - y\f$.
1480  */
1481 static
1483  SCIP* scip, /**< SCIP pointer */
1484  SCIP_LPI* lp, /**< alternative LP */
1485  SCIP_SOL* sol, /**< solution to be dealt with */
1486  int nconss, /**< number of constraints */
1487  SCIP_CONS** conss /**< indicator constraints */
1488  )
1489 {
1490  int j;
1491  SCIP_Real* obj = NULL;
1492  int* indices = NULL;
1493  int cnt = 0;
1494 
1495  assert( scip != NULL );
1496  assert( lp != NULL );
1497  assert( conss != NULL );
1498 
1499  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nconss) );
1500  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1501 
1502  for (j = 0; j < nconss; ++j)
1503  {
1504  SCIP_CONSDATA* consdata;
1505 
1506  assert( conss[j] != NULL );
1507  consdata = SCIPconsGetData(conss[j]);
1508  assert( consdata != NULL );
1509 
1510  if ( consdata->colindex >= 0 )
1511  {
1512  SCIP_Real val = SCIPgetSolVal(scip, sol, consdata->binvar);
1513  if ( SCIPisFeasEQ(scip, val, 1.0) )
1514  obj[cnt] = OBJEPSILON; /* set objective to some small number to get small IISs */
1515  else
1516  obj[cnt] = 1.0 - val;
1517  indices[cnt++] = consdata->colindex;
1518  }
1519  }
1520 
1521  if ( cnt > 0 )
1522  {
1523  SCIP_CALL( SCIPlpiChgObj(lp, cnt, indices, obj) );
1524  }
1525 
1526  SCIPfreeBufferArray(scip, &indices);
1527  SCIPfreeBufferArray(scip, &obj);
1528 
1529  return SCIP_OKAY;
1530 }
1531 
1532 
1533 /** set the alternative system objective function to some small value */
1534 static
1536  SCIP* scip, /**< SCIP pointer */
1537  SCIP_LPI* lp, /**< alternative LP */
1538  int nconss, /**< number of constraints */
1539  SCIP_CONS** conss /**< indicator constraints */
1540  )
1541 {
1542  int j;
1543  SCIP_Real* obj = NULL;
1544  int* indices = NULL;
1545  int cnt = 0;
1546 
1547  assert( scip != NULL );
1548  assert( lp != NULL );
1549  assert( conss != NULL );
1550 
1551  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nconss) );
1552  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1553 
1554  for (j = 0; j < nconss; ++j)
1555  {
1556  SCIP_CONSDATA* consdata;
1557 
1558  assert( conss[j] != NULL );
1559  consdata = SCIPconsGetData(conss[j]);
1560  assert( consdata != NULL );
1561 
1562  if ( consdata->colindex >= 0 )
1563  {
1564  obj[cnt] = OBJEPSILON;
1565  indices[cnt++] = consdata->colindex;
1566  }
1567  }
1568 
1569  if ( cnt > 0 )
1570  {
1571  SCIP_CALL( SCIPlpiChgObj(lp, cnt, indices, obj) );
1572  }
1573 
1574  SCIPfreeBufferArray(scip, &indices);
1575  SCIPfreeBufferArray(scip, &obj);
1576 
1577  return SCIP_OKAY;
1578 }
1579 
1580 
1581 /** fix variable given by @a S to 0 */
1582 static
1584  SCIP* scip, /**< SCIP pointer */
1585  SCIP_LPI* lp, /**< alternative LP */
1586  int nconss, /**< number of constraints */
1587  SCIP_CONS** conss, /**< indicator constraints */
1588  SCIP_Bool* S /**< bitset of variables */
1589  )
1590 {
1591  SCIP_Real* lb = NULL;
1592  SCIP_Real* ub = NULL;
1593  int* indices = NULL;
1594  int cnt = 0;
1595  int j;
1596 
1597  assert( scip != NULL );
1598  assert( lp != NULL );
1599  assert( conss != NULL );
1600 
1601  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nconss) );
1602  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nconss) );
1603  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1604 
1605  /* collect bounds to be changed */
1606  for (j = 0; j < nconss; ++j)
1607  {
1608  SCIP_CONSDATA* consdata;
1609 
1610  assert( conss[j] != NULL );
1611  consdata = SCIPconsGetData(conss[j]);
1612  assert( consdata != NULL );
1613 
1614  if ( consdata->colindex >= 0 )
1615  {
1616  if ( S[j] )
1617  {
1618  indices[cnt] = consdata->colindex;
1619  lb[cnt] = 0.0;
1620  ub[cnt] = 0.0;
1621  ++cnt;
1622  }
1623  }
1624  }
1625 
1626  /* change bounds */
1627  if ( cnt > 0 )
1628  {
1629  SCIP_CALL( SCIPlpiChgBounds(lp, cnt, indices, lb, ub) );
1630  }
1631 
1632  SCIPfreeBufferArray(scip, &indices);
1633  SCIPfreeBufferArray(scip, &ub);
1634  SCIPfreeBufferArray(scip, &lb);
1635 
1636  return SCIP_OKAY;
1637 }
1638 
1639 
1640 /** fix variable @a ind to 0 */
1641 static
1643  SCIP_LPI* lp, /**< alternative LP */
1644  int ind /**< variable that should be fixed to 0 */
1645  )
1646 {
1647  SCIP_Real lb = 0.0;
1648  SCIP_Real ub = 0.0;
1649 
1650  /* change bounds */
1651  SCIP_CALL( SCIPlpiChgBounds(lp, 1, &ind, &lb, &ub) );
1652 
1653  return SCIP_OKAY;
1654 }
1655 
1656 
1657 /** unfix variable @a ind to 0 */
1658 static
1660  SCIP_LPI* lp, /**< alternative LP */
1661  int ind /**< variable that should be fixed to 0 */
1662  )
1663 {
1664  SCIP_Real lb = 0.0;
1665  SCIP_Real ub = SCIPlpiInfinity(lp);
1666 
1667  /* change bounds */
1668  SCIP_CALL( SCIPlpiChgBounds(lp, 1, &ind, &lb, &ub) );
1669 
1670  return SCIP_OKAY;
1671 }
1672 
1673 /** unfix variable given by @a S to 0 */
1674 static
1676  SCIP* scip, /**< SCIP pointer */
1677  SCIP_LPI* lp, /**< alternative LP */
1678  int nconss, /**< number of constraints */
1679  SCIP_CONS** conss, /**< indicator constraints */
1680  SCIP_Bool* S /**< bitset of variables */
1681  )
1682 {
1683  SCIP_Real* lb = NULL;
1684  SCIP_Real* ub = NULL;
1685  int* indices = NULL;
1686  int cnt = 0;
1687  int j;
1688 
1689  assert( scip != NULL );
1690  assert( lp != NULL );
1691  assert( conss != NULL );
1692 
1693  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nconss) );
1694  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nconss) );
1695  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1696 
1697  /* collect bounds to be changed */
1698  for (j = 0; j < nconss; ++j)
1699  {
1700  if ( S[j] )
1701  {
1702  SCIP_CONSDATA* consdata;
1703 
1704  assert( conss[j] != NULL );
1705  consdata = SCIPconsGetData(conss[j]);
1706  assert( consdata != NULL );
1707 
1708  if ( consdata->colindex >= 0 )
1709  {
1710  indices[cnt] = consdata->colindex;
1711  lb[cnt] = 0.0;
1712  ub[cnt] = SCIPlpiInfinity(lp);
1713  ++cnt;
1714  }
1715  }
1716  }
1717 
1718  /* change bounds */
1719  if ( cnt > 0 )
1720  {
1721  SCIP_CALL( SCIPlpiChgBounds(lp, cnt, indices, lb, ub) );
1722  }
1723 
1724  SCIPfreeBufferArray(scip, &indices);
1725  SCIPfreeBufferArray(scip, &ub);
1726  SCIPfreeBufferArray(scip, &lb);
1727 
1728  return SCIP_OKAY;
1729 }
1730 
1731 
1732 /** update bounds in first row to the current ones */
1733 static
1735  SCIP* scip, /**< SCIP pointer */
1736  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
1737  )
1738 {
1739  SCIP_HASHMAP* lbhash;
1740  SCIP_HASHMAP* ubhash;
1741  SCIP_VAR** vars;
1742  SCIP_LPI* altlp;
1743  int nvars;
1744  int cnt;
1745  int v;
1746 
1747  assert( scip != NULL );
1748  assert( conshdlrdata != NULL );
1749 
1750  altlp = conshdlrdata->altlp;
1751  lbhash = conshdlrdata->lbhash;
1752  ubhash = conshdlrdata->ubhash;
1753  assert( lbhash != NULL && ubhash != NULL );
1754 
1755  /* check all variables */
1756  vars = SCIPgetVars(scip);
1757  nvars = SCIPgetNVars(scip);
1758  cnt = 0;
1759 
1760  for (v = 0; v < nvars; ++v)
1761  {
1762  SCIP_VAR* var;
1763  var = vars[v];
1764  if ( SCIPhashmapExists(lbhash, var) )
1765  {
1766  int col;
1767 
1768  col = SCIPhashmapGetImageInt(lbhash, var);
1769  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, -SCIPvarGetLbLocal(var)) );
1770  if ( ! SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var)) )
1771  ++cnt;
1772  }
1773  if ( SCIPhashmapExists(ubhash, var) )
1774  {
1775  int col;
1776 
1777  col = SCIPhashmapGetImageInt(ubhash, var);
1778  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, SCIPvarGetUbLocal(var)) );
1779  if ( ! SCIPisEQ(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var)) )
1780  ++cnt;
1781  }
1782  }
1783  if ( cnt > 10 )
1784  {
1785  /* possible force a rescaling: */
1786  conshdlrdata->scaled = FALSE;
1787 
1788  /* SCIP_CALL( SCIPlpiWriteLP(altlp, "altChg.lp") ); */
1789  SCIPdebugMsg(scip, "Updated bounds of original variables: %d.\n", cnt);
1790  }
1791 
1792  return SCIP_OKAY;
1793 }
1794 
1795 
1796 /** update bounds in first row to the global bounds */
1797 static
1799  SCIP* scip, /**< SCIP pointer */
1800  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
1801  )
1802 {
1803  SCIP_HASHMAP* lbhash;
1804  SCIP_HASHMAP* ubhash;
1805  SCIP_VAR** vars;
1806  SCIP_LPI* altlp;
1807  int nvars;
1808  int cnt;
1809  int v;
1810 
1811  assert( scip != NULL );
1812  assert( conshdlrdata != NULL );
1813 
1814  altlp = conshdlrdata->altlp;
1815  lbhash = conshdlrdata->lbhash;
1816  ubhash = conshdlrdata->ubhash;
1817  assert( lbhash != NULL && ubhash != NULL );
1818 
1819  /* check all variables */
1820  vars = SCIPgetVars(scip);
1821  nvars = SCIPgetNVars(scip);
1822  cnt = 0;
1823 
1824  for (v = 0; v < nvars; ++v)
1825  {
1826  SCIP_VAR* var;
1827  int col;
1828 
1829  var = vars[v];
1830  if ( SCIPhashmapExists(lbhash, var) )
1831  {
1832  col = SCIPhashmapGetImageInt(lbhash, var);
1833  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, -SCIPvarGetLbGlobal(var)) );
1834  ++cnt;
1835  }
1836  if ( SCIPhashmapExists(ubhash, var) )
1837  {
1838  col = SCIPhashmapGetImageInt(ubhash, var);
1839  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, SCIPvarGetUbGlobal(var)) );
1840  ++cnt;
1841  }
1842  }
1843 
1844  if ( cnt > 0 )
1845  {
1846  /* SCIP_CALL( SCIPlpiWriteLP(altlp, "altChg.lp") ); */
1847  SCIPdebugMsg(scip, "Updated bounds of original variables: %d.\n", cnt);
1848  }
1849 
1850  /* possible force a rescaling: */
1851  /* conshdlrdata->scaled = FALSE; */
1852 
1853  return SCIP_OKAY;
1854 }
1855 
1856 
1857 /** check whether IIS defined by @a vector corresponds to a local cut */
1858 static
1860  SCIP* scip, /**< SCIP pointer */
1861  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler */
1862  SCIP_Real* vector, /**< solution to alternative LP defining IIS */
1863  SCIP_Bool* isLocal /**< whether the IIS uses local bounds different from the global ones */
1864  )
1865 {
1866  SCIP_HASHMAP* lbhash;
1867  SCIP_HASHMAP* ubhash;
1868  SCIP_VAR** vars;
1869 #ifndef NDEBUG
1870  int nCols;
1871 #endif
1872  int nvars;
1873  int v;
1874 
1875  assert( scip != NULL );
1876  assert( conshdlrdata != NULL );
1877  assert( vector != NULL );
1878  assert( isLocal != NULL );
1879 
1880  *isLocal = FALSE;
1881 
1882 #ifndef NDEBUG
1883  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &nCols) );
1884 #endif
1885 
1886  lbhash = conshdlrdata->lbhash;
1887  ubhash = conshdlrdata->ubhash;
1888  assert( lbhash != NULL && ubhash != NULL );
1889 
1890  /* get all variables */
1891  vars = SCIPgetVars(scip);
1892  nvars = SCIPgetNVars(scip);
1893 
1894  /* check all variables */
1895  for (v = 0; v < nvars; ++v)
1896  {
1897  SCIP_VAR* var;
1898  var = vars[v];
1899 
1900  /* if local bound is different from global bound */
1901  if ( ! SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var)) )
1902  {
1903  /* check whether the variable corresponding to the lower bounds has been used */
1904  if ( SCIPhashmapExists(lbhash, var) )
1905  {
1906  int col;
1907 
1908  col = SCIPhashmapGetImageInt(lbhash, var);
1909  assert( 0 <= col && col < nCols );
1910  if ( ! SCIPisFeasZero(scip, vector[col]) )
1911  {
1912  *isLocal = TRUE;
1913  return SCIP_OKAY;
1914  }
1915  }
1916  }
1917 
1918  /* if local bound is different from global bound */
1919  if ( ! SCIPisEQ(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var)) )
1920  {
1921  /* check whether the variable corresponding to the upper bounds has been used */
1922  if ( SCIPhashmapExists(ubhash, var) )
1923  {
1924  int col;
1925 
1926  col = SCIPhashmapGetImageInt(ubhash, var);
1927  assert( 0 <= col && col < nCols );
1928  if ( ! SCIPisFeasZero(scip, vector[col]) )
1929  {
1930  *isLocal = TRUE;
1931  return SCIP_OKAY;
1932  }
1933  }
1934  }
1935  }
1936 
1937  return SCIP_OKAY;
1938 }
1939 
1940 
1941 /** compute scaling for first row
1942  *
1943  * If the coefficients in the first row are large, a right hand side of -1 might not be
1944  * adequate. Here, we replace the right hand side by the sum of the coefficients divided by the
1945  * number of nonzeros.
1946  */
1947 static
1949  SCIP* scip, /**< SCIP pointer */
1950  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
1951  )
1952 {
1953  assert( scip != NULL );
1954  assert( conshdlrdata != NULL );
1955 
1956  if ( ! conshdlrdata->scaled )
1957  {
1958  SCIP_Real* val;
1959  SCIP_LPI* altlp;
1960  int* ind;
1961  SCIP_Real sum = 0.0;
1962  int beg[1];
1963  int nCols;
1964  int cnt;
1965  int j;
1966 
1967  altlp = conshdlrdata->altlp;
1968  SCIP_CALL( SCIPlpiGetNCols(altlp, &nCols) );
1969  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nCols) );
1970  SCIP_CALL( SCIPallocBufferArray(scip, &val, nCols) );
1971 
1972  SCIP_CALL( SCIPlpiGetRows(altlp, 0, 0, NULL, NULL, &cnt, beg, ind, val) );
1973 
1974  if ( cnt > 0 )
1975  {
1976  /* compute sum */
1977  for (j = 0; j < cnt; ++j)
1978  sum += REALABS(val[j]);
1979 
1980  /* set rhs */
1981  sum = - REALABS(sum) / ((double) cnt);
1982  j = 0;
1983  SCIP_CALL( SCIPlpiChgSides(altlp, 1, &j, &sum, &sum) );
1984  }
1985 
1986  SCIPfreeBufferArray(scip, &val);
1987  SCIPfreeBufferArray(scip, &ind);
1988 
1989  conshdlrdata->scaled = TRUE;
1990  }
1991 
1992  return SCIP_OKAY;
1993 }
1994 
1995 
1996 /** add column to alternative LP
1997  *
1998  * See the description at the top of the file for more information.
1999  */
2000 static
2002  SCIP* scip, /**< SCIP pointer */
2003  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2004  SCIP_CONSHDLRDATA* conshdlrdata, /**< data of constraint handler */
2005  SCIP_VAR* slackvar, /**< slack variable or NULL */
2006  int nvars, /**< number of variables in column */
2007  SCIP_VAR** vars, /**< variables for column */
2008  SCIP_Real* vals, /**< values for column */
2009  SCIP_Real rhscoef, /**< coefficient for first row */
2010  SCIP_Real objcoef, /**< objective in alternative LP */
2011  SCIP_Real sign, /**< sign (+1,-1) for column */
2012  SCIP_Bool colfree, /**< whether column should be free, e.g., for equations */
2013  int* colindex /**< index of new column (return value) */
2014  )
2015 {
2016  SCIP_VAR** newvars;
2017  SCIP_Real val;
2018  SCIP_Real* matval;
2019  SCIP_Bool* newrowsslack;
2020  SCIP_Real* obj;
2021  SCIP_Real* lb;
2022  SCIP_Real* ub;
2023  int* matbeg;
2024  int* matind;
2025  int nnewvars = 0;
2026  int nnewcols = 0;
2027  int nnewrows = 0;
2028  int ncols = 0;
2029  int cnt = 0;
2030  int v;
2031 
2032  assert( scip != NULL );
2033  assert( conshdlrdata != NULL );
2034  assert( vars != NULL || nvars == 0 );
2035  assert( vals != NULL || nvars == 0 );
2036  assert( ! SCIPisInfinity(scip, rhscoef) && ! SCIPisInfinity(scip, -rhscoef) );
2037  assert( SCIPisEQ(scip, sign, 1.0) || SCIPisEQ(scip, sign, -1.0) );
2038  assert( colindex != NULL );
2039 
2040  *colindex = -1;
2041 
2042  if ( conshdlrdata->altlp == NULL )
2043  {
2044  SCIP_CALL( initAlternativeLP(scip, conshdlr) );
2045  }
2046  assert( conshdlrdata->altlp != NULL );
2047  assert( conshdlrdata->varhash != NULL );
2048  assert( conshdlrdata->lbhash != NULL );
2049  assert( conshdlrdata->ubhash != NULL );
2050  assert( conshdlrdata->slackhash != NULL );
2051 
2052 #ifndef NDEBUG
2053  {
2054  int nrows;
2055  SCIP_CALL( SCIPlpiGetNRows(conshdlrdata->altlp, &nrows) );
2056  assert( nrows == conshdlrdata->nrows );
2057  }
2058 #endif
2059 
2060  /* set up data for construction */
2061  SCIP_CALL( SCIPallocBufferArray(scip, &matbeg, nvars) );
2062  SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4 * nvars) );
2063  SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4 * nvars) );
2064  SCIP_CALL( SCIPallocBufferArray(scip, &obj, 2 * nvars) );
2065  SCIP_CALL( SCIPallocBufferArray(scip, &lb, 2 * nvars) );
2066  SCIP_CALL( SCIPallocBufferArray(scip, &ub, 2 * nvars) );
2067  SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nvars) );
2068  SCIP_CALL( SCIPallocBufferArray(scip, &newrowsslack, 2 * nvars) );
2069 
2070  /* store index of column in constraint */
2071  /* coverity[var_deref_model] */
2072  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &ncols) );
2073  *colindex = ncols;
2074 
2075  /* handle first row */
2076  if ( ! SCIPisFeasZero(scip, rhscoef) )
2077  {
2078  matind[cnt] = 0;
2079  matval[cnt++] = sign * rhscoef;
2080  }
2081 
2082  /* set up column (recognize new original variables) */
2083  for (v = 0; v < nvars; ++v)
2084  {
2085  SCIP_VAR* var;
2086 
2087  var = vars[v];
2088  assert( var != NULL );
2089 
2090  /* if variable is a slack variable */
2091  if ( SCIPhashmapExists(conshdlrdata->slackhash, var) )
2092  {
2093  /* to avoid trivial rows: only add row corresponding to slack variable if it appears outside its own constraint */
2094  if ( var != slackvar )
2095  {
2096  int ind;
2097 
2098  ind = SCIPhashmapGetImageInt(conshdlrdata->slackhash, var);
2099 
2100  if ( ind < INT_MAX )
2101  matind[cnt] = ind;
2102  else
2103  {
2104  /* correct number of variable already in map/array and remember to add a new row */
2105  SCIP_CALL( SCIPhashmapSetImageInt(conshdlrdata->slackhash, var, conshdlrdata->nrows) );
2106  assert( conshdlrdata->nrows == SCIPhashmapGetImageInt(conshdlrdata->slackhash, var) );
2107  SCIPdebugMsg(scip, "Inserted slack variable <%s> into hashmap (row: %d).\n", SCIPvarGetName(var), conshdlrdata->nrows);
2108  matind[cnt] = (conshdlrdata->nrows)++;
2109 
2110  /* store new variables */
2111  newrowsslack[nnewrows++] = TRUE;
2112  }
2113  assert( conshdlrdata->nrows >= SCIPhashmapGetImageInt(conshdlrdata->slackhash, var) );
2114  matval[cnt++] = sign * vals[v];
2115  }
2116  }
2117  else
2118  {
2119  /* if variable exists */
2120  if ( SCIPhashmapExists(conshdlrdata->varhash, var) )
2121  matind[cnt] = SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
2122  else
2123  {
2124  /* add variable in map and array and remember to add a new row */
2125  SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->varhash, var, conshdlrdata->nrows) );
2126  assert( conshdlrdata->nrows == SCIPhashmapGetImageInt(conshdlrdata->varhash, var) );
2127  SCIPdebugMsg(scip, "Inserted variable <%s> into hashmap (row: %d).\n", SCIPvarGetName(var), conshdlrdata->nrows);
2128  matind[cnt] = (conshdlrdata->nrows)++;
2129 
2130  /* store new variables */
2131  newrowsslack[nnewrows++] = FALSE;
2132  newvars[nnewvars++] = var;
2133  }
2134  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2135  matval[cnt++] = sign * vals[v];
2136  }
2137  }
2138 
2139  /* add new rows */
2140  if ( nnewrows > 0 )
2141  {
2142  SCIP_Real* lhs;
2143  SCIP_Real* rhs;
2144  int i;
2145 
2146  SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nnewrows) );
2147  SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nnewrows) );
2148  for (i = 0; i < nnewrows; ++i)
2149  {
2150  if ( newrowsslack[i] )
2151  lhs[i] = -SCIPlpiInfinity(conshdlrdata->altlp);
2152  else
2153  lhs[i] = 0.0;
2154  rhs[i] = 0.0;
2155  }
2156  /* add new rows */
2157  SCIP_CALL( SCIPlpiAddRows(conshdlrdata->altlp, nnewrows, lhs, rhs, NULL, 0, NULL, NULL, NULL) );
2158 
2159  SCIPfreeBufferArray(scip, &lhs);
2160  SCIPfreeBufferArray(scip, &rhs);
2161  }
2162 
2163  /* now add column */
2164  obj[0] = objcoef;
2165  if ( colfree )
2166  {
2167  /* create a free variable -> should only happen for additional linear constraints */
2168  assert( slackvar == NULL );
2169  lb[0] = -SCIPlpiInfinity(conshdlrdata->altlp);
2170  }
2171  else
2172  lb[0] = 0.0;
2173  ub[0] = SCIPlpiInfinity(conshdlrdata->altlp);
2174  matbeg[0] = 0;
2175 
2176  SCIP_CALL( SCIPlpiAddCols(conshdlrdata->altlp, 1, obj, lb, ub, NULL, cnt, matbeg, matind, matval) );
2177 
2178  /* add columns corresponding to bounds of original variables - no bounds needed for slack vars */
2179  cnt = 0;
2180  for (v = 0; v < nnewvars; ++v)
2181  {
2182  SCIP_VAR* var = newvars[v];
2183  assert( var != NULL );
2184 
2185  /* if the lower bound is finite */
2186  val = SCIPvarGetLbGlobal(var);
2187  if ( ! SCIPisInfinity(scip, -val) )
2188  {
2189  matbeg[nnewcols] = cnt;
2190  if ( ! SCIPisZero(scip, val) )
2191  {
2192  matind[cnt] = 0;
2193  matval[cnt++] = -val;
2194  }
2195  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2196 
2197  matind[cnt] = SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
2198  matval[cnt++] = -1.0;
2199  obj[nnewcols] = 0.0;
2200  lb[nnewcols] = 0.0;
2201  ub[nnewcols] = SCIPlpiInfinity(conshdlrdata->altlp);
2202  ++conshdlrdata->nlbbounds;
2203 
2204  SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->lbhash, var, ncols + 1 + nnewcols) );
2205  assert( SCIPhashmapExists(conshdlrdata->lbhash, var) );
2206  SCIPdebugMsg(scip, "Added column for lower bound (%f) of variable <%s> to alternative polyhedron (col: %d).\n",
2207  val, SCIPvarGetName(var), ncols + 1 + nnewcols);
2208  ++nnewcols;
2209  }
2210 
2211  /* if the upper bound is finite */
2212  val = SCIPvarGetUbGlobal(var);
2213  if ( ! SCIPisInfinity(scip, val) )
2214  {
2215  matbeg[nnewcols] = cnt;
2216  if ( ! SCIPisZero(scip, val) )
2217  {
2218  matind[cnt] = 0;
2219  matval[cnt++] = val;
2220  }
2221  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2222 
2223  matind[cnt] = SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
2224  matval[cnt++] = 1.0;
2225  obj[nnewcols] = 0.0;
2226  lb[nnewcols] = 0.0;
2227  ub[nnewcols] = SCIPlpiInfinity(conshdlrdata->altlp);
2228  ++conshdlrdata->nubbounds;
2229 
2230  SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->ubhash, var, ncols + 1 + nnewcols) );
2231  assert( SCIPhashmapExists(conshdlrdata->ubhash, var) );
2232  SCIPdebugMsg(scip, "Added column for upper bound (%f) of variable <%s> to alternative polyhedron (col: %d).\n",
2233  val, SCIPvarGetName(var), ncols + 1 + nnewcols);
2234  ++nnewcols;
2235  }
2236  }
2237 
2238  /* add columns if necessary */
2239  if ( nnewcols > 0 )
2240  {
2241  SCIP_CALL( SCIPlpiAddCols(conshdlrdata->altlp, nnewcols, obj, lb, ub, NULL, cnt, matbeg, matind, matval) );
2242  }
2243 
2244 #ifndef NDEBUG
2245  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &cnt) );
2246  assert( cnt == ncols + nnewcols + 1 );
2247 #endif
2248 
2249  SCIPfreeBufferArray(scip, &ub);
2250  SCIPfreeBufferArray(scip, &lb);
2251  SCIPfreeBufferArray(scip, &obj);
2252  SCIPfreeBufferArray(scip, &matind);
2253  SCIPfreeBufferArray(scip, &matval);
2254  SCIPfreeBufferArray(scip, &matbeg);
2255  SCIPfreeBufferArray(scip, &newvars);
2256  SCIPfreeBufferArray(scip, &newrowsslack);
2257 
2258  conshdlrdata->scaled = FALSE;
2259 
2260 #ifdef SCIP_OUTPUT
2261  SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "alt.lp") );
2262 #endif
2263 
2264  return SCIP_OKAY;
2265 }
2266 
2267 
2268 /** add column corresponding to constraint to alternative LP
2269  *
2270  * See the description at the top of the file for more information.
2271  */
2272 static
2274  SCIP* scip, /**< SCIP pointer */
2275  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2276  SCIP_CONS* lincons, /**< linear constraint */
2277  SCIP_VAR* slackvar, /**< slack variable or NULL */
2278  SCIP_Real objcoef, /**< objective coefficient */
2279  int* colindex /**< index of new column */
2280  )
2281 {
2282  SCIP_CONSHDLRDATA* conshdlrdata;
2283  SCIP_VAR** linvars;
2284  SCIP_Real* linvals;
2285  SCIP_Real linrhs;
2286  SCIP_Real linlhs;
2287  int nlinvars;
2288 
2289  assert( scip != NULL );
2290  assert( conshdlr != NULL );
2291  assert( lincons != NULL );
2292  assert( colindex != NULL );
2293  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2294 
2295  *colindex = -1;
2296 
2297  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2298  assert( conshdlrdata != NULL );
2299 
2300  /* if the slack variable is aggregated (multi-aggregation should not happen) */
2301  assert( slackvar == NULL || SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
2302  if ( slackvar != NULL && SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
2303  {
2304  SCIP_VAR* var;
2305  SCIP_Real scalar = 1.0;
2306  SCIP_Real constant = 0.0;
2307 
2308  var = slackvar;
2309 
2310  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
2311 
2312  SCIPdebugMsg(scip, "Slack variable is aggregated (scalar: %f, constant: %f).\n", scalar, constant);
2313 
2314  /* if the slack variable is fixed */
2315  if ( SCIPisZero(scip, scalar) && ! SCIPconsIsActive(lincons) )
2316  return SCIP_OKAY;
2317 
2318  /* otherwise construct a linear constraint */
2319  SCIP_CALL( SCIPallocBufferArray(scip, &linvars, 1) );
2320  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, 1) );
2321  linvars[0] = var;
2322  linvals[0] = scalar;
2323  nlinvars = 1;
2324  linlhs = -SCIPinfinity(scip);
2325  linrhs = constant;
2326  }
2327  else
2328  {
2329  /* exit if linear constraint is not active */
2330  if ( ! SCIPconsIsActive(lincons) && slackvar != NULL )
2331  return SCIP_OKAY;
2332 
2333  /* in this case, the linear constraint is directly usable */
2334  linvars = SCIPgetVarsLinear(scip, lincons);
2335  linvals = SCIPgetValsLinear(scip, lincons);
2336  nlinvars = SCIPgetNVarsLinear(scip, lincons);
2337  linlhs = SCIPgetLhsLinear(scip, lincons);
2338  linrhs = SCIPgetRhsLinear(scip, lincons);
2339  }
2340 
2341  /* create column */
2342  if ( SCIPisEQ(scip, linlhs, linrhs) )
2343  {
2344  /* create free variable for equations (should only happen for additional linear constraints) */
2345  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, slackvar, nlinvars, linvars, linvals, linrhs, objcoef, 1.0, TRUE, colindex) );
2346  }
2347  else if ( ! SCIPisInfinity(scip, linrhs) )
2348  {
2349  /* create column for rhs */
2350  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, slackvar, nlinvars, linvars, linvals, linrhs, objcoef, 1.0, FALSE, colindex) );
2351  }
2352  else
2353  {
2354  /* create column for lhs */
2355  assert( ! SCIPisInfinity(scip, -linlhs) );
2356  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, slackvar, nlinvars, linvars, linvals, linlhs, objcoef, -1.0, FALSE, colindex) );
2357  }
2358 
2359  if ( slackvar != NULL && SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
2360  {
2361  SCIPfreeBufferArray(scip, &linvals);
2362  SCIPfreeBufferArray(scip, &linvars);
2363  }
2364 
2365  return SCIP_OKAY;
2366 }
2367 
2368 
2369 /** add column corresponding to row to alternative LP
2370  *
2371  * See the description at the top of the file for more information.
2372  */
2373 static
2375  SCIP* scip, /**< SCIP pointer */
2376  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2377  SCIP_ROW* row, /**< row to add */
2378  SCIP_Real objcoef, /**< objective coefficient */
2379  int* colindex /**< index of new column */
2380  )
2381 {
2382  SCIP_CONSHDLRDATA* conshdlrdata;
2383  SCIP_COL** rowcols;
2384  SCIP_Real* rowvals;
2385  SCIP_VAR** rowvars;
2386  SCIP_Real rowrhs;
2387  SCIP_Real rowlhs;
2388  int nrowcols;
2389  int j;
2390 
2391  assert( scip != NULL );
2392  assert( conshdlr != NULL );
2393  assert( row != NULL );
2394  assert( colindex != NULL );
2395  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2396 
2397  /* initialize data */
2398  *colindex = -1;
2399 
2400  /* exit if row is not global */
2401  if ( SCIProwIsLocal(row) )
2402  return SCIP_OKAY;
2403 
2404  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2405  assert( conshdlrdata != NULL );
2406 
2407  /* get row data */
2408  rowcols = SCIProwGetCols(row);
2409  rowvals = SCIProwGetVals(row);
2410  nrowcols = SCIProwGetNNonz(row);
2411  rowlhs = SCIProwGetLhs(row) - SCIProwGetConstant(row);
2412  rowrhs = SCIProwGetRhs(row) - SCIProwGetConstant(row);
2413 
2414  SCIP_CALL( SCIPallocBufferArray(scip, &rowvars, nrowcols) );
2415  for (j = 0; j < nrowcols; ++j)
2416  {
2417  rowvars[j] = SCIPcolGetVar(rowcols[j]);
2418  assert( rowvars[j] != NULL );
2419  }
2420 
2421  /* create column */
2422  if ( SCIPisEQ(scip, rowlhs, rowrhs) )
2423  {
2424  /* create free variable for equations (should only happen for additional linear constraints) */
2425  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nrowcols, rowvars, rowvals, rowrhs, objcoef, 1.0, TRUE, colindex) );
2426  }
2427  else if ( ! SCIPisInfinity(scip, rowrhs) )
2428  {
2429  /* create column for rhs */
2430  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nrowcols, rowvars, rowvals, rowrhs, objcoef, 1.0, FALSE, colindex) );
2431  }
2432  else
2433  {
2434  /* create column for lhs */
2435  assert( ! SCIPisInfinity(scip, -rowlhs) );
2436  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nrowcols, rowvars, rowvals, rowlhs, objcoef, -1.0, FALSE, colindex) );
2437  }
2438 
2439  SCIPfreeBufferArray(scip, &rowvars);
2440 
2441  return SCIP_OKAY;
2442 }
2443 
2444 
2445 /** try to add objective cut as column to alternative LP */
2446 static
2448  SCIP* scip, /**< SCIP pointer */
2449  SCIP_CONSHDLR* conshdlr /**< constraint handler */
2450  )
2451 {
2452  SCIP_CONSHDLRDATA* conshdlrdata;
2453  SCIP_VAR** objvars;
2454  SCIP_Real* objvals;
2455  SCIP_VAR** vars;
2456  int nobjvars = 0;
2457  int nvars;
2458  int v;
2459 
2460  assert( scip != NULL );
2461  assert( conshdlr != NULL );
2462  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2463 
2464  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2465  assert( conshdlrdata != NULL );
2466 
2467  /* skip procedure if already added */
2468  if ( conshdlrdata->objcutindex >= 0 )
2469  return SCIP_OKAY;
2470 
2471  /* check whether we can add objective cut: all indicator variables have zero objective */
2472  if ( ! conshdlrdata->objothervarsonly )
2473  return SCIP_OKAY;
2474 
2475  assert( ! SCIPisInfinity(scip, conshdlrdata->objupperbound) );
2476  SCIPdebugMsg(scip, "Add objective cut to alternative LP (obj. bound: %g).\n", conshdlrdata->objupperbound);
2477 
2478  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2479  SCIP_CALL( SCIPallocBufferArray(scip, &objvars, nvars) );
2480  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
2481 
2482  /* collect nonzeros */
2483  for (v = 0; v < nvars; ++v)
2484  {
2485  SCIP_VAR* var;
2486  SCIP_Real objval;
2487 
2488  var = vars[v];
2489  assert( var != NULL );
2490  objval = SCIPvarGetObj(var);
2491 
2492  /* skip variables with zero objective - this includes slack and indicator variables */
2493  if ( ! SCIPisZero(scip, objval) )
2494  {
2495  objvars[nobjvars] = var;
2496  objvals[nobjvars++] = objval;
2497  }
2498  }
2499 
2500  /* create column (with rhs = upperbound, objective 0, and scaling factor 1.0) */
2501  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nobjvars, objvars, objvals, conshdlrdata->objupperbound, 0.0, 1.0, FALSE, &conshdlrdata->objcutindex) );
2502  assert( conshdlrdata->objcutindex >= 0 );
2503  conshdlrdata->objaltlpbound = conshdlrdata->objupperbound;
2504 
2505  SCIPfreeBufferArray(scip, &objvals);
2506  SCIPfreeBufferArray(scip, &objvars);
2507 
2508  return SCIP_OKAY;
2509 }
2510 
2511 
2512 /** delete column corresponding to constraint in alternative LP
2513  *
2514  * We currently just fix the corresponding variable to 0.
2515  */
2516 static
2518  SCIP* scip, /**< SCIP pointer */
2519  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2520  SCIP_CONS* cons /**< indicator constraint */
2521  )
2522 {
2523  SCIP_CONSHDLRDATA* conshdlrdata;
2524 
2525  assert( scip != NULL );
2526  assert( conshdlr != NULL );
2527  assert( cons != NULL );
2528  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2529 
2530  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2531  assert( conshdlrdata != NULL );
2532 
2533  if ( conshdlrdata->altlp != NULL )
2534  {
2535  SCIP_CONSDATA* consdata;
2536 
2537  consdata = SCIPconsGetData(cons);
2538  assert( consdata != NULL );
2539 
2540  if ( consdata->colindex >= 0 )
2541  {
2542  SCIP_CALL( fixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
2543  }
2544  consdata->colindex = -1;
2545 
2546  SCIPdebugMsg(scip, "Fixed variable for column %d (constraint: <%s>) from alternative LP to 0.\n", consdata->colindex, SCIPconsGetName(cons));
2547  }
2548  conshdlrdata->scaled = FALSE;
2549 
2550  return SCIP_OKAY;
2551 }
2552 
2553 
2554 /** update upper bound in alternative LP */
2555 static
2557  SCIP* scip, /**< SCIP pointer */
2558  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2559  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
2560  )
2561 {
2562  SCIP_Real objbnd;
2563 
2564  assert( scip != NULL );
2565  assert( conshdlrdata != NULL );
2566 
2567  if ( ! conshdlrdata->useobjectivecut )
2568  return SCIP_OKAY;
2569 
2570  if ( conshdlrdata->altlp == NULL )
2571  return SCIP_OKAY;
2572 
2573  /* first check whether we can improve the upper bound */
2574  objbnd = SCIPgetUpperbound(scip);
2575  if ( ! SCIPisInfinity(scip, objbnd) )
2576  {
2577  if ( SCIPisObjIntegral(scip) )
2578  objbnd = SCIPfeasCeil(scip, objbnd) - (1.0 - SCIPcutoffbounddelta(scip));
2579  else
2580  objbnd -= SCIPcutoffbounddelta(scip);
2581 
2582  if ( SCIPisLT(scip, objbnd, conshdlrdata->objupperbound) )
2583  conshdlrdata->objupperbound = objbnd;
2584  }
2585 
2586  if ( SCIPisInfinity(scip, conshdlrdata->objupperbound) )
2587  return SCIP_OKAY;
2588 
2589  /* if we can improve on the bound stored in the alternative LP */
2590  if ( SCIPisLT(scip, conshdlrdata->objupperbound, conshdlrdata->objaltlpbound) )
2591  {
2592  SCIPdebugMsg(scip, "Update objective bound to %g.\n", conshdlrdata->objupperbound);
2593 
2594  /* possibly add column for objective cut */
2595  if ( conshdlrdata->objcutindex < 0 )
2596  {
2597  SCIP_CALL( addObjcut(scip, conshdlr) );
2598  }
2599  else
2600  {
2601 #ifndef NDEBUG
2602  SCIP_Real oldbnd;
2603  SCIP_CALL( SCIPlpiGetCoef(conshdlrdata->altlp, 0, conshdlrdata->objcutindex, &oldbnd) );
2604  assert( SCIPisEQ(scip, oldbnd, conshdlrdata->objaltlpbound) );
2605 #endif
2606 
2607  /* update bound */
2608  SCIP_CALL( SCIPlpiChgCoef(conshdlrdata->altlp, 0, conshdlrdata->objcutindex, conshdlrdata->objupperbound) );
2609  conshdlrdata->objaltlpbound = conshdlrdata->objupperbound;
2610 
2611 #ifdef SCIP_OUTPUT
2612  SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "alt.lp") );
2613 #endif
2614  }
2615  }
2616 
2617  return SCIP_OKAY;
2618 }
2619 
2620 
2621 /** check whether the given LP is infeasible
2622  *
2623  * If @a primal is false we assume that the problem is <em>dual feasible</em>, e.g., the problem
2624  * was only changed by fixing bounds!
2625  *
2626  * This is the workhorse for all methods that have to solve the alternative LP. We try in several
2627  * ways to recover from possible stability problems.
2628  *
2629  * @pre It is assumed that all parameters for the alternative LP are set.
2630  */
2631 static
2633  SCIP* scip, /**< SCIP pointer */
2634  SCIP_LPI* lp, /**< LP */
2635  SCIP_Real maxcondition, /**< maximal allowed condition of LP solution basis matrix */
2636  SCIP_Bool primal, /**< whether we are using the primal or dual simplex */
2637  SCIP_Bool* infeasible, /**< output: whether the LP is infeasible */
2638  SCIP_Bool* error /**< output: whether an error occurred */
2639  )
2640 {
2641  SCIP_RETCODE retcode;
2642  SCIP_Real condition;
2643 
2644  assert( scip != NULL );
2645  assert( lp != NULL );
2646  assert( infeasible != NULL );
2647  assert( error != NULL );
2648 
2649  *error = FALSE;
2650 
2651  /* solve LP */
2652  if ( primal )
2653  retcode = SCIPlpiSolvePrimal(lp); /* use primal simplex */
2654  else
2655  retcode = SCIPlpiSolveDual(lp); /* use dual simplex */
2656  if ( retcode == SCIP_LPERROR )
2657  {
2658  *error = TRUE;
2659  return SCIP_OKAY;
2660  }
2661  SCIP_CALL( retcode );
2662 
2663  /* resolve if LP is not stable */
2664  if ( ! SCIPlpiIsStable(lp) )
2665  {
2668  SCIPwarningMessage(scip, "Numerical problems, retrying ...\n");
2669 
2670  /* re-solve LP */
2671  if ( primal )
2672  retcode = SCIPlpiSolvePrimal(lp); /* use primal simplex */
2673  else
2674  retcode = SCIPlpiSolveDual(lp); /* use dual simplex */
2675 
2676  /* reset parameters */
2679 
2680  if ( retcode == SCIP_LPERROR )
2681  {
2682  *error = TRUE;
2683  return SCIP_OKAY;
2684  }
2685  SCIP_CALL( retcode );
2686  }
2687 
2688  /* check whether we want to ignore the result, because the condition number is too large */
2689  if ( maxcondition > 0.0 )
2690  {
2691  /* check estimated condition number of basis matrix */
2693  if ( condition != SCIP_INVALID && condition > maxcondition ) /*lint !e777*/
2694  {
2695  SCIPdebugMsg(scip, "Estimated condition number of basis matrix (%e) exceeds maximal allowance (%e).\n", condition, maxcondition);
2696 
2697  *error = TRUE;
2698 
2699  return SCIP_OKAY;
2700  }
2701  else if ( condition != SCIP_INVALID ) /*lint !e777*/
2702  {
2703  SCIPdebugMsg(scip, "Estimated condition number of basis matrix (%e) is below maximal allowance (%e).\n", condition, maxcondition);
2704  }
2705  else
2706  {
2707  SCIPdebugMsg(scip, "Estimated condition number of basis matrix not available.\n");
2708  }
2709  }
2710 
2711  /* check whether we are in the paradoxical situation that
2712  * - the primal is not infeasible
2713  * - the primal is not unbounded
2714  * - the LP is not optimal
2715  * - we have a primal ray
2716  *
2717  * If we ran the dual simplex algorithm, then we run again with the primal simplex
2718  */
2720  ! SCIPlpiIsOptimal(lp) && SCIPlpiExistsPrimalRay(lp) && ! primal )
2721  {
2722  SCIPwarningMessage(scip, "The dual simplex produced a primal ray. Retrying with primal ...\n");
2723 
2724  /* the following settings might be changed: */
2728 
2729  SCIP_CALL( SCIPlpiSolvePrimal(lp) ); /* use primal simplex */
2730 
2731  /* reset parameters */
2735  }
2736 
2737  /* examine LP solution status */
2738  if ( SCIPlpiIsPrimalInfeasible(lp) ) /* the LP is provably infeasible */
2739  {
2740  assert( ! SCIPlpiIsPrimalUnbounded(lp) ); /* can't be unbounded or optimal */
2741  assert( ! SCIPlpiIsOptimal(lp) ); /* if it is infeasible! */
2742 
2743  *infeasible = TRUE; /* LP is infeasible */
2744  return SCIP_OKAY;
2745  }
2746  else
2747  {
2748  /* By assumption the dual is feasible if the dual simplex is run, therefore
2749  * the status has to be primal unbounded or optimal. */
2750  if ( ! SCIPlpiIsPrimalUnbounded(lp) && ! SCIPlpiIsOptimal(lp) )
2751  {
2752  /* We have a status different from unbounded or optimal. This should not be the case ... */
2753  if (primal)
2754  SCIPwarningMessage(scip, "Primal simplex returned with unknown status: %d\n", SCIPlpiGetInternalStatus(lp));
2755  else
2756  SCIPwarningMessage(scip, "Dual simplex returned with unknown status: %d\n", SCIPlpiGetInternalStatus(lp));
2757 
2758  /* SCIP_CALL( SCIPlpiWriteLP(lp, "debug.lp") ); */
2759  *error = TRUE;
2760  return SCIP_OKAY;
2761  }
2762  }
2763 
2764  /* at this point we have a feasible solution */
2765  *infeasible = FALSE;
2766  return SCIP_OKAY;
2767 }
2768 
2769 
2770 /** tries to extend a given set of variables to a cover
2771  *
2772  * At each step we include a variable which covers a new IIS. The corresponding IIS inequalities are added to the LP,
2773  * if this not already happened.
2774  *
2775  * @pre It is assumed that all parameters for the alternative LP are set and that the variables
2776  * corresponding to @a S are fixed. Furthermore @c xVal_ should contain the current LP solution.
2777  */
2778 static
2780  SCIP* scip, /**< SCIP pointer */
2781  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2782  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
2783  SCIP_LPI* lp, /**< LP */
2784  SCIP_SOL* sol, /**< solution to be separated */
2785  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
2786  SCIP_Bool removable, /**< whether cuts should be removable */
2787  SCIP_Bool genlogicor, /**< should logicor constraints be generated? */
2788  int nconss, /**< number of constraints */
2789  SCIP_CONS** conss, /**< indicator constraints */
2790  SCIP_Bool* S, /**< bitset of variables */
2791  int* size, /**< size of S */
2792  SCIP_Real* value, /**< objective value of S */
2793  SCIP_Bool* error, /**< output: whether an error occurred */
2794  SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
2795  int* nGen /**< number of generated cuts */
2796  )
2797 {
2798 #ifdef SCIP_DEBUG
2799  char name[SCIP_MAXSTRLEN];
2800 #endif
2801  SCIP_Real* primsol;
2802  int nnonviolated = 0;
2803  int step = 0;
2804  int nCols;
2805 
2806  assert( scip != NULL );
2807  assert( lp != NULL );
2808  assert( conss != NULL );
2809  assert( S != NULL );
2810  assert( size != NULL );
2811  assert( value != NULL );
2812  assert( error != NULL );
2813  assert( cutoff != NULL );
2814  assert( nGen != NULL );
2815 
2816  *error = FALSE;
2817  *cutoff = FALSE;
2818  *nGen = 0;
2819 
2820  SCIP_CALL( SCIPlpiGetNCols(lp, &nCols) );
2821  SCIP_CALL( SCIPallocBufferArray(scip, &primsol, nCols) );
2822  assert( nconss <= nCols );
2823 
2824  do
2825  {
2826  SCIP_Bool infeasible;
2827  SCIP_Real sum = 0.0;
2828  SCIP_Real candobj = -1.0;
2829  SCIP_Real candval = 2.0;
2830  SCIP_Real norm = 1.0;
2831  int sizeIIS = 0;
2832  int candidate = -1;
2833  int candindex = -1;
2834  int j;
2835 
2836  if ( step == 0 )
2837  {
2838  /* the first LP is solved without warm start, after that we use a warmstart. */
2840  SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, TRUE, &infeasible, error) );
2842  }
2843  else
2844  SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, FALSE, &infeasible, error) );
2845 
2846  if ( *error )
2847  break;
2848 
2849  /* if the alternative polyhedron is infeasible, we found a cover */
2850  if ( infeasible )
2851  {
2852  /* Note: checking for a primal solution is done in extendToCover(). */
2853  SCIPdebugMsg(scip, " size: %4d produced possible cover with indicator variable objective value %f.\n", *size, *value);
2854 
2855  /* we currently cannot call probing if there are cuts in the sepastore; @todo fix this */
2856  if ( conshdlrdata->trysolfromcover )
2857  {
2858  /* Check whether we want to try to construct a feasible solution: there should be no integer/binary variables
2859  * except the indicator variables. Thus, there should be no integral variables and the number of indicator
2860  * variables should be at least (actually equal to) the number of binary variables. */
2861  if ( SCIPgetNIntVars(scip) == 0 && nconss >= SCIPgetNBinVars(scip) )
2862  {
2863  SCIP_HEUR* heurindicator;
2864 
2865  heurindicator = SCIPfindHeur(scip, "indicator");
2866  if ( heurindicator == NULL )
2867  {
2868  SCIPerrorMessage("Could not find heuristic \"indicator\".\n");
2869  return SCIP_PLUGINNOTFOUND;
2870  }
2871 
2872  SCIP_CALL( SCIPheurPassIndicator(scip, heurindicator, nconss, conss, S, -*value) );
2873  SCIPdebugMsg(scip, "Passed feasible solution to indicator heuristic.\n");
2874  }
2875  }
2876  break;
2877  }
2878 
2879  /* get solution of alternative LP */
2880  SCIP_CALL( SCIPlpiGetSol(lp, NULL, primsol, NULL, NULL, NULL) );
2881 
2882  /* get value of cut and find candidate for variable to add */
2883  for (j = 0; j < nconss; ++j)
2884  {
2885  SCIP_CONSDATA* consdata;
2886  int ind;
2887 
2888  consdata = SCIPconsGetData(conss[j]);
2889  assert( consdata != NULL );
2890  ind = consdata->colindex;
2891 
2892  if ( ind >= 0 )
2893  {
2894  assert( ind < nCols );
2895 
2896  /* check support of the solution, i.e., the corresponding IIS */
2897  if ( ! SCIPisFeasZero(scip, primsol[ind]) )
2898  {
2899  SCIP_Real val;
2900 
2901  assert( ! S[j] );
2902  ++sizeIIS;
2903  val = SCIPgetSolVal(scip, sol, consdata->binvar);
2904  sum += val;
2905 
2906  /* take element with smallest relaxation value */
2907  if ( val < candval )
2908  {
2909  candidate = j;
2910  candindex = ind;
2911  candval = val;
2912  candobj = varGetObjDelta(consdata->binvar);
2913  }
2914  }
2915  }
2916  }
2917 
2918  /* check for error */
2919  if ( candidate < 0 )
2920  {
2921  /* Because of numerical problems it might happen that the solution primsol above is zero
2922  * within the tolerances. In this case we quit. */
2923  break;
2924  }
2925  assert( candidate >= 0 );
2926  assert( ! S[candidate] );
2927  assert( sizeIIS > 0 );
2928 
2929  /* get the type of norm to use for efficacy calculations */
2930  switch ( conshdlrdata->normtype )
2931  {
2932  case 'e':
2933  norm = sqrt((SCIP_Real) sizeIIS);
2934  break;
2935  case 'm':
2936  norm = 1.0;
2937  break;
2938  case 's':
2939  norm = (SCIP_Real) sizeIIS;
2940  break;
2941  case 'd':
2942  norm = 1.0;
2943  break;
2944  default:
2945  SCIPerrorMessage("Invalid efficacy norm parameter '%c'.\n", conshdlrdata->normtype);
2946  SCIPABORT();
2947  norm = 1.0; /*lint !e527*/
2948  }
2949 
2950  SCIPdebugMsg(scip, " size: %4d, add var. %4d (obj: %-6g, alt-LP sol: %-8.4f); IIS size: %4d, eff.: %g.\n",
2951  *size, candidate, candobj, primsol[SCIPconsGetData(conss[candidate])->colindex], sizeIIS, (sum - (SCIP_Real) (sizeIIS - 1))/norm);
2952 
2953  /* update new set S */
2954  S[candidate] = TRUE;
2955  ++(*size);
2956  *value += candobj;
2957 
2958  /* fix chosen variable to 0 */
2959  SCIP_CALL( fixAltLPVariable(lp, candindex) );
2960 
2961  /* if cut is violated, i.e., sum - sizeIIS + 1 > 0 */
2962  if ( SCIPisEfficacious(scip, (sum - (SCIP_Real) (sizeIIS - 1))/norm) )
2963  {
2964  SCIP_Bool isLocal = FALSE;
2965 
2966 #ifdef SCIP_ENABLE_IISCHECK
2967  /* check whether we really have an infeasible subsystem */
2968  SCIP_CALL( checkIIS(scip, nconss, conss, primsol) );
2969 #endif
2970 
2971  /* check whether IIS corresponds to a local cut */
2972  if ( conshdlrdata->updatebounds )
2973  {
2974  SCIP_CALL( checkIISlocal(scip, conshdlrdata, primsol, &isLocal) );
2975  }
2976 
2977  if ( genlogicor )
2978  {
2979  SCIP_RESULT result;
2980  SCIP_CONS* cons;
2981  SCIP_VAR** vars;
2982  int cnt = 0;
2983 
2984  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nconss) );
2985 
2986  /* collect variables corresponding to support to cut */
2987  for (j = 0; j < nconss; ++j)
2988  {
2989  SCIP_CONSDATA* consdata;
2990  int ind;
2991 
2992  consdata = SCIPconsGetData(conss[j]);
2993  ind = consdata->colindex;
2994 
2995  if ( ind >= 0 )
2996  {
2997  assert( ind < nCols );
2998  assert( consdata->binvar != NULL );
2999 
3000  /* check support of the solution, i.e., the corresponding IIS */
3001  if ( ! SCIPisFeasZero(scip, primsol[ind]) )
3002  {
3003  SCIP_VAR* var;
3004  SCIP_CALL( SCIPgetNegatedVar(scip, consdata->binvar, &var) );
3005  vars[cnt++] = var;
3006  }
3007  }
3008  }
3009  assert( cnt == sizeIIS );
3010 
3011 #ifdef SCIP_DEBUG
3012  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "iis%d", conshdlrdata->niiscutsgen + *nGen);
3013  SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, name, cnt, vars, FALSE, TRUE, TRUE, TRUE, TRUE, isLocal, FALSE, TRUE, removable, FALSE) );
3014 #else
3015  SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, "", cnt, vars, FALSE, TRUE, TRUE, TRUE, TRUE, isLocal, FALSE, TRUE, removable, FALSE) );
3016 #endif
3017 
3018 #ifdef SCIP_OUTPUT
3019  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
3020  SCIPinfoMessage(scip, NULL, ";\n");
3021 #endif
3022 
3023  /* enforce or separate logicor constraint to make sure that this has an effect in this round */
3024  switch ( enfosepatype )
3025  {
3026  case SCIP_TYPE_ENFOLP:
3027  SCIP_CALL( SCIPenfolpCons(scip, cons, FALSE, &result) );
3028  break;
3029  case SCIP_TYPE_ENFOPS:
3030  SCIP_CALL( SCIPenfopsCons(scip, cons, FALSE, FALSE, &result) );
3031  break;
3032  case SCIP_TYPE_ENFORELAX:
3033  SCIP_CALL( SCIPenforelaxCons(scip, cons, sol, FALSE, &result) );
3034  break;
3035  case SCIP_TYPE_SEPALP:
3036  SCIP_CALL( SCIPsepalpCons(scip, cons, &result) );
3037  break;
3038  case SCIP_TYPE_SEPARELAX:
3039  case SCIP_TYPE_SEPASOL:
3040  SCIP_CALL( SCIPsepasolCons(scip, cons, sol, &result) );
3041  break;
3042  default:
3043  SCIPerrorMessage("Wrong enforcing/separation type.\n");
3044  SCIPABORT();
3045  }
3046 
3047  SCIP_CALL( SCIPaddCons(scip, cons) );
3048  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3049 
3050  SCIPfreeBufferArray(scip, &vars);
3051  ++(*nGen);
3052  }
3053  else
3054  {
3055  SCIP_ROW* row;
3056 
3057  /* create row */
3058 #ifdef SCIP_DEBUG
3059  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "iis%d", conshdlrdata->niiscutsgen + *nGen);
3060  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, name, -SCIPinfinity(scip), (SCIP_Real) (sizeIIS - 1), isLocal, FALSE, removable) );
3061 #else
3062  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, "", -SCIPinfinity(scip), (SCIP_Real) (sizeIIS - 1), isLocal, FALSE, removable) );
3063 #endif
3064  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
3065 
3066  /* add variables corresponding to support to cut */
3067  for (j = 0; j < nconss; ++j)
3068  {
3069  int ind;
3070  SCIP_CONSDATA* consdata;
3071 
3072  consdata = SCIPconsGetData(conss[j]);
3073  ind = consdata->colindex;
3074 
3075  if ( ind >= 0 )
3076  {
3077  assert( ind < nCols );
3078  assert( consdata->binvar != NULL );
3079 
3080  /* check support of the solution, i.e., the corresponding IIS */
3081  if ( ! SCIPisFeasZero(scip, primsol[ind]) )
3082  {
3083  SCIP_VAR* var = consdata->binvar;
3084  SCIP_CALL( SCIPaddVarToRow(scip, row, var, 1.0) );
3085  }
3086  }
3087  }
3088  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
3089 #ifdef SCIP_OUTPUT
3090  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
3091 #endif
3092  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
3093  if ( *cutoff )
3094  {
3095  SCIPfreeBufferArray(scip, &primsol);
3096  return SCIP_OKAY;
3097  }
3098 
3099  /* cut should be violated: */
3100  assert( SCIPisFeasNegative(scip, SCIPgetRowSolFeasibility(scip, row, sol)) );
3101 
3102  /* add cuts to pool if they are globally valid */
3103  if ( ! isLocal )
3104  SCIP_CALL( SCIPaddPoolCut(scip, row) );
3105  SCIP_CALL( SCIPreleaseRow(scip, &row));
3106  ++(*nGen);
3107  }
3108  nnonviolated = 0;
3109  }
3110  else
3111  ++nnonviolated;
3112  ++step;
3113 
3114  if ( nnonviolated > conshdlrdata->maxsepanonviolated )
3115  {
3116  SCIPdebugMsg(scip, "Stop separation after %d non violated IISs.\n", nnonviolated);
3117  break;
3118  }
3119  }
3120  while (step < nconss);
3121 
3122  SCIPfreeBufferArray(scip, &primsol);
3123 
3124  return SCIP_OKAY;
3125 }
3126 
3127 
3128 /* ---------------------------- constraint handler local methods ----------------------*/
3129 
3130 /** creates and initializes consdata */
3131 static
3133  SCIP* scip, /**< SCIP data structure */
3134  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3135  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3136  const char* consname, /**< name of constraint (or NULL) */
3137  SCIP_CONSDATA** consdata, /**< pointer to linear constraint data */
3138  SCIP_EVENTHDLR* eventhdlrbound, /**< event handler for bound change events */
3139  SCIP_EVENTHDLR* eventhdlrrestart, /**< event handler for handling restarts */
3140  SCIP_VAR* binvar, /**< binary variable (or NULL) */
3141  SCIP_Bool activeone, /**< whether the constraint is active on 1 or not */
3142  SCIP_Bool lessthanineq, /**< whether the original linear constraint is a less-than-rhs (TRUE) or not */
3143  SCIP_VAR* slackvar, /**< slack variable */
3144  SCIP_CONS* lincons, /**< linear constraint (or NULL) */
3145  SCIP_Bool linconsactive /**< whether the linear constraint is active */
3146  )
3147 {
3148  SCIP_VAR* binvarinternal;
3149 
3150  assert( scip != NULL );
3151  assert( conshdlr != NULL );
3152  assert( conshdlrdata != NULL );
3153  assert( consdata != NULL );
3154  assert( slackvar != NULL );
3155  assert( eventhdlrbound != NULL );
3156  assert( eventhdlrrestart != NULL );
3157 
3158  /* if active on 0, the binary variable is reversed */
3159  if ( activeone )
3160  {
3161  binvarinternal = binvar;
3162  }
3163  else
3164  {
3165  SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
3166  }
3167 
3168  /* create constraint data */
3169  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
3170  (*consdata)->nfixednonzero = 0;
3171  (*consdata)->colindex = -1;
3172  (*consdata)->linconsactive = linconsactive;
3173  (*consdata)->binvar = binvarinternal;
3174  (*consdata)->slackvar = slackvar;
3175  (*consdata)->activeone = activeone;
3176  (*consdata)->lessthanineq = lessthanineq;
3177  (*consdata)->lincons = lincons;
3178  (*consdata)->implicationadded = FALSE;
3179  (*consdata)->slacktypechecked = FALSE;
3180 
3181  /* if we are transformed, obtain transformed variables and catch events */
3182  if ( SCIPisTransformed(scip) )
3183  {
3184  SCIP_VAR* var;
3185 
3186  /* handle binary variable */
3187  if ( binvarinternal != NULL )
3188  {
3189  SCIP_CALL( SCIPgetTransformedVar(scip, binvarinternal, &var) );
3190  assert( var != NULL );
3191  (*consdata)->binvar = var;
3192 
3193  /* check type */
3194  if ( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY )
3195  {
3196  SCIPerrorMessage("Indicator variable <%s> is not binary %d.\n", SCIPvarGetName(var), SCIPvarGetType(var));
3197  return SCIP_ERROR;
3198  }
3199 
3200  /* the indicator variable must not be multi-aggregated because the constraint handler propagation tries
3201  * to tighten its bounds, which is not allowed for multi-aggregated variables
3202  */
3203  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) );
3204 
3205  /* catch local bound change events on binary variable */
3206  if ( linconsactive )
3207  {
3208  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlrbound, (SCIP_EVENTDATA*)*consdata, NULL) );
3209  }
3210 
3211  /* catch global bound change events on binary variable */
3212  if ( conshdlrdata->forcerestart )
3213  {
3214  SCIPdebugMsg(scip, "Catching GBDCHANGED event for <%s>.\n", SCIPvarGetName(var));
3215  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
3216  }
3217 
3218  /* if binary variable is fixed to be nonzero */
3219  if ( SCIPvarGetLbLocal(var) > 0.5 )
3220  ++((*consdata)->nfixednonzero);
3221  }
3222 
3223  /* handle slack variable */
3224  SCIP_CALL( SCIPgetTransformedVar(scip, slackvar, &var) );
3225  assert( var != NULL );
3226  (*consdata)->slackvar = var;
3227 
3228  /* catch bound change events on slack variable and adjust nfixednonzero */
3229  if ( linconsactive )
3230  {
3231  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlrbound, (SCIP_EVENTDATA*)*consdata, NULL) );
3232 
3233  /* if slack variable is fixed to be nonzero */
3234  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) )
3235  ++((*consdata)->nfixednonzero);
3236  }
3237 
3238  /* add corresponding column to alternative LP if the constraint is new */
3239  if ( conshdlrdata->sepaalternativelp && SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && lincons != NULL )
3240  {
3241  assert( lincons != NULL );
3242  assert( consname != NULL );
3243 
3244  SCIP_CALL( addAltLPConstraint(scip, conshdlr, lincons, var, 1.0, &(*consdata)->colindex) );
3245 
3246  SCIPdebugMsg(scip, "Added column for <%s> to alternative LP with column index %d.\n", consname, (*consdata)->colindex);
3247 #ifdef SCIP_OUTPUT
3248  SCIP_CALL( SCIPprintCons(scip, lincons, NULL) );
3249  SCIPinfoMessage(scip, NULL, ";\n");
3250 #endif
3251  }
3252 
3253 #ifdef SCIP_DEBUG
3254  if ( (*consdata)->nfixednonzero > 0 )
3255  {
3256  SCIPdebugMsg(scip, "Constraint <%s> has %d variables fixed to be nonzero.\n", consname, (*consdata)->nfixednonzero);
3257  }
3258 #endif
3259  }
3260 
3261  return SCIP_OKAY;
3262 }
3263 
3264 
3265 /** create variable upper bounds for constraints */
3266 static
3268  SCIP* scip, /**< SCIP pointer */
3269  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3270  SCIP_CONS** conss, /**< constraints */
3271  int nconss, /**< number of constraints */
3272  int* ngen /**< number of successful operations */
3273  )
3274 {
3275  char name[50];
3276  int c;
3277 
3278  assert( scip != NULL );
3279  assert( conshdlrdata != NULL );
3280  assert( ngen != NULL );
3281 
3282  *ngen = 0;
3283 
3284  /* check each constraint */
3285  for (c = 0; c < nconss; ++c)
3286  {
3287  SCIP_CONSDATA* consdata;
3288  SCIP_Real ub;
3289 
3290  consdata = SCIPconsGetData(conss[c]);
3291  assert( consdata != NULL );
3292 
3293  ub = SCIPvarGetUbGlobal(consdata->slackvar);
3294  assert( ! SCIPisNegative(scip, ub) );
3295 
3296  /* insert corresponding row if helpful and coefficient is not too large */
3297  if ( ub <= conshdlrdata->maxcouplingvalue )
3298  {
3299  SCIP_CONS* cons;
3300 
3301 #ifndef NDEBUG
3302  (void) SCIPsnprintf(name, 50, "couple%d", c);
3303 #else
3304  name[0] = '\0';
3305 #endif
3306 
3307  SCIPdebugMsg(scip, "Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
3308 
3309  /* add variable upper bound:
3310  * - check constraint if we remove the indicator constraint afterwards
3311  * - constraint is dynamic if we do not remove indicator constraints
3312  * - constraint is removable if we do not remove indicator constraints
3313  */
3314  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
3315  TRUE, TRUE, TRUE, conshdlrdata->removeindicators, TRUE, FALSE, FALSE,
3316  !conshdlrdata->removeindicators, !conshdlrdata->removeindicators, FALSE) );
3317 
3318  SCIP_CALL( SCIPaddCons(scip, cons) );
3319  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3320 
3321  /* remove indicator constraint if required */
3322  if ( conshdlrdata->removeindicators )
3323  {
3324  SCIPdebugMsg(scip, "Removing indicator constraint <%s>.\n", SCIPconsGetName(conss[c]));
3325  assert( ! SCIPconsIsModifiable(conss[c]) );
3326 
3327  /* mark linear constraint to be upgrade-able */
3328  if ( SCIPconsIsActive(consdata->lincons) )
3329  {
3330  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3331  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3332  }
3333 
3334  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
3335  }
3336 
3337  ++(*ngen);
3338  }
3339  }
3340 
3341  return SCIP_OKAY;
3342 }
3343 
3344 
3345 /** perform one presolving round */
3346 static
3348  SCIP* scip, /**< SCIP pointer */
3349  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3350  SCIP_CONS* cons, /**< constraint */
3351  SCIP_CONSDATA* consdata, /**< constraint data */
3352  SCIP_Bool dualreductions, /**< should dual reductions be performed? */
3353  SCIP_Bool* cutoff, /**< whether a cutoff happened */
3354  SCIP_Bool* success, /**< whether we performed a successful reduction */
3355  int* ndelconss, /**< number of deleted constraints */
3356  int* nfixedvars /**< number of fixed variables */
3357  )
3358 {
3359  SCIP_Bool infeasible;
3360  SCIP_Bool fixed;
3361 
3362  assert( scip != NULL );
3363  assert( cons != NULL );
3364  assert( consdata != NULL );
3365  assert( cutoff != NULL );
3366  assert( success != NULL );
3367  assert( ndelconss != NULL );
3368  assert( nfixedvars != NULL );
3369  assert( consdata->binvar != NULL );
3370  assert( consdata->slackvar != NULL );
3371 
3372  *cutoff = FALSE;
3373  *success = FALSE;
3374 
3375  /* if the binary variable is fixed to nonzero */
3376  if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3377  {
3378  SCIPdebugMsg(scip, "Presolving <%s>: Binary variable fixed to 1.\n", SCIPconsGetName(cons));
3379 
3380  /* if slack variable is fixed to nonzero, we are infeasible */
3381  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3382  {
3383  SCIPdebugMsg(scip, "The problem is infeasible: binary and slack variable are fixed to be nonzero.\n");
3384  *cutoff = TRUE;
3385  return SCIP_OKAY;
3386  }
3387 
3388  /* otherwise fix slack variable to 0 */
3389  SCIPdebugMsg(scip, "Fix slack variable to 0 and delete constraint.\n");
3390  SCIP_CALL( SCIPfixVar(scip, consdata->slackvar, 0.0, &infeasible, &fixed) );
3391  assert( ! infeasible );
3392  if ( fixed )
3393  ++(*nfixedvars);
3394 
3395  /* mark linear constraint to be update-able */
3396  if ( SCIPconsIsActive(consdata->lincons) )
3397  {
3398  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3399  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3400  }
3401 
3402  /* delete indicator constraint (leave linear constraint) */
3403  assert( ! SCIPconsIsModifiable(cons) );
3404  SCIP_CALL( SCIPdelCons(scip, cons) );
3405  ++(*ndelconss);
3406  *success = TRUE;
3407  return SCIP_OKAY;
3408  }
3409 
3410  /* if the binary variable is fixed to zero */
3411  if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
3412  {
3413  SCIPdebugMsg(scip, "Presolving <%s>: Binary variable <%s> fixed to 0, deleting indicator constraint.\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->binvar));
3414 
3415  /* mark linear constraint to be update-able */
3416  if ( SCIPconsIsActive(consdata->lincons) )
3417  {
3418  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3419  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3420  }
3421 
3422  /* delete indicator constraint */
3423  assert( ! SCIPconsIsModifiable(cons) );
3424  SCIP_CALL( SCIPdelCons(scip, cons) );
3425  ++(*ndelconss);
3426  *success = TRUE;
3427  return SCIP_OKAY;
3428  }
3429 
3430  /* if the slack variable is fixed to nonzero */
3431  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3432  {
3433  SCIPdebugMsg(scip, "Presolving <%s>: Slack variable fixed to nonzero.\n", SCIPconsGetName(cons));
3434 
3435  /* if binary variable is fixed to nonzero, we are infeasible */
3436  if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3437  {
3438  SCIPdebugMsg(scip, "The problem is infeasible: binary and slack variable are fixed to be nonzero.\n");
3439  *cutoff = TRUE;
3440  return SCIP_OKAY;
3441  }
3442 
3443  /* otherwise fix binary variable to 0 */
3444  SCIPdebugMsg(scip, "Fix binary variable to 0 and delete indicator constraint.\n");
3445  SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
3446  assert( ! infeasible );
3447  if ( fixed )
3448  ++(*nfixedvars);
3449 
3450  /* mark linear constraint to be update-able */
3451  if ( SCIPconsIsActive(consdata->lincons) )
3452  {
3453  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3454  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3455  }
3456 
3457  /* delete constraint */
3458  assert( ! SCIPconsIsModifiable(cons) );
3459  SCIP_CALL( SCIPdelCons(scip, cons) );
3460  ++(*ndelconss);
3461  *success = TRUE;
3462  return SCIP_OKAY;
3463  }
3464 
3465  /* if the slack variable is fixed to zero */
3466  if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3467  {
3468  /* perform dual reductions - if required */
3469  if ( dualreductions )
3470  {
3471  SCIP_VAR* binvar;
3472  SCIP_Real obj;
3473 
3474  /* check objective of binary variable */
3475  binvar = consdata->binvar;
3476  obj = varGetObjDelta(binvar);
3477 
3478  /* if obj = 0, we prefer fixing the binary variable to 1 (if possible) */
3479  if ( obj <= 0.0 )
3480  {
3481  /* In this case we would like to fix the binary variable to 1, if it is not locked up
3482  except by this indicator constraint. If more than one indicator constraint is
3483  effected, we have to hope that they are all fulfilled - in this case the last
3484  constraint will fix the binary variable to 1. */
3485  if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
3486  {
3487  if ( SCIPvarGetUbGlobal(binvar) > 0.5 )
3488  {
3489  SCIPdebugMsg(scip, "Presolving <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
3490  SCIP_CALL( SCIPfixVar(scip, binvar, 1.0, &infeasible, &fixed) );
3491  assert( ! infeasible );
3492  if ( fixed )
3493  ++(*nfixedvars);
3494  /* make sure that the other case does not occur */
3495  obj = -1.0;
3496  }
3497  }
3498  }
3499  if ( obj >= 0.0 )
3500  {
3501  /* In this case we would like to fix the binary variable to 0, if it is not locked down
3502  (should also have been performed by other dual reductions). */
3503  if ( SCIPvarGetNLocksDownType(binvar, SCIP_LOCKTYPE_MODEL) == 0 )
3504  {
3505  if ( SCIPvarGetLbGlobal(binvar) < 0.5 )
3506  {
3507  SCIPdebugMsg(scip, "Presolving <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
3508  SCIP_CALL( SCIPfixVar(scip, binvar, 0.0, &infeasible, &fixed) );
3509  assert( ! infeasible );
3510  if ( fixed )
3511  ++(*nfixedvars);
3512  }
3513  }
3514  }
3515  }
3516 
3517  SCIPdebugMsg(scip, "Presolving <%s>: Slack variable fixed to zero, delete redundant indicator constraint.\n", SCIPconsGetName(cons));
3518 
3519  /* mark linear constraint to be upgrade-able */
3520  if ( SCIPconsIsActive(consdata->lincons) )
3521  {
3522  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3523  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3524  }
3525 
3526  /* delete constraint */
3527  assert( ! SCIPconsIsModifiable(cons) );
3528  SCIP_CALL( SCIPdelCons(scip, cons) );
3529  ++(*ndelconss);
3530  *success = TRUE;
3531  return SCIP_OKAY;
3532  }
3533 
3534  /* check whether indicator variable is aggregated */
3535  if ( SCIPvarGetStatus(consdata->binvar) == SCIP_VARSTATUS_AGGREGATED )
3536  {
3537  SCIP_Bool negated = FALSE;
3538  SCIP_VAR* var;
3539 
3540  /* possibly get representation of indicator variable by active variable */
3541  var = consdata->binvar;
3542  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
3543  assert( var == consdata->binvar || SCIPvarIsActive(var) || SCIPvarIsNegated(var) );
3544 
3545  /* we can replace the binary variable by the active variable if it is not negated */
3546  if ( var != consdata->binvar && ! negated )
3547  {
3548  SCIPdebugMsg(scip, "Indicator variable <%s> is aggregated and replaced by active/negated variable <%s>.\n", SCIPvarGetName(consdata->binvar), SCIPvarGetName(var) );
3549 
3550  /* we need to update the events and locks */
3551  assert( conshdlrdata->eventhdlrbound != NULL );
3552  SCIP_CALL( SCIPdropVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, -1) );
3553  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, NULL) );
3554 
3555  /* We also need to update the events and locks if restart is forced, since global bound change events on binary
3556  * variables are also caught in this case. If it would not be updated and forcerestart = TRUE, then an event
3557  * might be dropped on a wrong variable. */
3558  if ( conshdlrdata->forcerestart )
3559  {
3560  assert( conshdlrdata->eventhdlrrestart != NULL );
3561  SCIP_CALL( SCIPdropVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_GBDCHANGED,
3562  conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, -1) );
3563  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
3564  (SCIP_EVENTDATA*) conshdlrdata, NULL) );
3565  }
3566 
3567  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->binvar, SCIP_LOCKTYPE_MODEL, 0, -1) );
3568  SCIP_CALL( SCIPaddVarLocksType(scip, var, SCIP_LOCKTYPE_MODEL, 0, 1) );
3569 
3570  /* change binvary variable */
3571  consdata->binvar = var;
3572  }
3573  }
3574  else if ( SCIPvarGetStatus(consdata->binvar) == SCIP_VARSTATUS_NEGATED )
3575  {
3576  SCIP_VAR* var;
3577 
3578  var = SCIPvarGetNegatedVar(consdata->binvar);
3579  assert( var != NULL );
3580 
3581  /* if the binary variable is the negated slack variable, we have 1 - s = 1 -> s = 0, i.e., the constraint is redundant */
3582  if ( var == consdata->slackvar )
3583  {
3584  /* delete constraint */
3585  assert( ! SCIPconsIsModifiable(cons) );
3586  SCIP_CALL( SCIPdelCons(scip, cons) );
3587  ++(*ndelconss);
3588  *success = TRUE;
3589  return SCIP_OKAY;
3590  }
3591  }
3592 
3593  /* check whether slack variable is aggregated */
3594  if ( SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_AGGREGATED || SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_NEGATED )
3595  {
3597  SCIP_Real bound;
3598  SCIP_VAR* var;
3599 
3600  /* possibly get representation of slack variable by active variable */
3601  var = consdata->slackvar;
3602  bound = SCIPvarGetLbGlobal(var);
3603 
3604  SCIP_CALL( SCIPvarGetProbvarBound(&var, &bound, &boundtype) );
3605  assert( var != consdata->slackvar );
3606 
3607  /* we can replace the slack variable by the active variable if it is also a >= variable */
3608  if ( var != consdata->binvar && boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisEQ(scip, bound, 0.0) )
3609  {
3610  assert( SCIPvarIsActive(var) );
3611  SCIPdebugMsg(scip, "Slack variable <%s> is aggregated or negated and replaced by active variable <%s>.\n", SCIPvarGetName(consdata->slackvar), SCIPvarGetName(var) );
3612 
3613  /* we need to update the events, locks, and captures */
3614  assert( conshdlrdata->eventhdlrbound != NULL );
3615  SCIP_CALL( SCIPdropVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, -1) );
3616  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, NULL) );
3617 
3618  SCIP_CALL( SCIPunlockVarCons(scip, consdata->slackvar, cons, FALSE, TRUE) );
3619  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
3620 
3621  SCIP_CALL( SCIPreleaseVar(scip, &consdata->slackvar) );
3622  SCIP_CALL( SCIPcaptureVar(scip, var) );
3623 
3624  /* change slack variable */
3625  consdata->slackvar = var;
3626  }
3627  else if ( var == consdata->binvar )
3628  {
3629  /* check special case that aggregating variable is equal to the indicator variable */
3630  assert( SCIPisEQ(scip, bound, 0.0) || SCIPisEQ(scip, bound, 1.0) );
3631 
3632  /* if the lower bound is transformed to an upper bound, we have "y = 1 -> 1 - y = 0", i.e., the constraint is redundant */
3633  if ( boundtype == SCIP_BOUNDTYPE_UPPER )
3634  {
3635  SCIPdebugMsg(scip, "Slack variable <%s> is aggregated to negated indicator variable <%s> -> constraint redundant.\n",
3636  SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3637  assert( SCIPisEQ(scip, bound, 1.0) );
3638 
3639  /* delete constraint */
3640  assert( ! SCIPconsIsModifiable(cons) );
3641  SCIP_CALL( SCIPdelCons(scip, cons) );
3642  ++(*ndelconss);
3643  *success = TRUE;
3644  return SCIP_OKAY;
3645  }
3646  else
3647  {
3648  /* 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 */
3649  SCIPdebugMsg(scip, "Slack variable <%s> is aggregated to the indicator variable <%s> -> fix indicator variable to 0.\n",
3650  SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3651  assert( boundtype == SCIP_BOUNDTYPE_LOWER );
3652  assert( SCIPisEQ(scip, bound, 0.0) );
3653 
3654  SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
3655  assert( ! infeasible );
3656 
3657  if ( fixed )
3658  ++(*nfixedvars);
3659 
3660  SCIP_CALL( SCIPdelCons(scip, cons) );
3661 
3662  ++(*ndelconss);
3663  *success = TRUE;
3664 
3665  return SCIP_OKAY;
3666  }
3667  }
3668  }
3669 
3670  /* Note that because of possible multi-aggregation we cannot simply remove the indicator
3671  * constraint if the linear constraint is not active or disabled - see the note in @ref
3672  * PREPROC. */
3673 
3674  return SCIP_OKAY;
3675 }
3676 
3677 
3678 /** propagate indicator constraint */
3679 static
3681  SCIP* scip, /**< SCIP pointer */
3682  SCIP_CONS* cons, /**< constraint */
3683  SCIP_CONSDATA* consdata, /**< constraint data */
3684  SCIP_Bool dualreductions, /**< should dual reductions be performed? */
3685  SCIP_Bool addopposite, /**< add opposite inequalities if binary var = 0? */
3686  SCIP_Bool* cutoff, /**< whether a cutoff happened */
3687  int* nGen /**< number of domain changes */
3688  )
3689 {
3690  SCIP_Bool infeasible;
3691  SCIP_Bool tightened;
3692 
3693  assert( scip != NULL );
3694  assert( cons != NULL );
3695  assert( consdata != NULL );
3696  assert( cutoff != NULL );
3697  assert( nGen != NULL );
3698 
3699  *cutoff = FALSE;
3700  *nGen = 0;
3701 
3702  /* if the linear constraint has not been generated, we do nothing */
3703  if ( ! consdata->linconsactive )
3704  return SCIP_OKAY;
3705 
3706  assert( consdata->slackvar != NULL );
3707  assert( consdata->binvar != NULL );
3708  assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(consdata->slackvar), 0.0) );
3709 
3710  /* if both slackvar and binvar are fixed to be nonzero */
3711  if ( consdata->nfixednonzero > 1 )
3712  {
3713  SCIPdebugMsg(scip, "The node is infeasible, both the slack variable and the binary variable are fixed to be nonzero.\n");
3714  *cutoff = TRUE;
3715 
3716  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3717  assert( SCIPvarGetLbLocal(consdata->binvar) > 0.5 );
3718  assert( SCIPisPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) );
3719 
3720  /* check if conflict analysis is turned on */
3721  if ( ! SCIPisConflictAnalysisApplicable(scip) )
3722  return SCIP_OKAY;
3723 
3724  /* conflict analysis can only be applied in solving stage */
3725  assert( SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip) );
3726 
3727  /* perform conflict analysis */
3729 
3730  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->binvar) );
3731  SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, NULL) );
3732  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
3733 
3734  return SCIP_OKAY;
3735  }
3736 
3737  /* if exactly one of the variables is fixed to be nonzero */
3738  if ( consdata->nfixednonzero == 1 )
3739  {
3740  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
3741  if ( ! SCIPinRepropagation(scip) )
3742  SCIP_CALL( SCIPincConsAge(scip, cons) );
3743 
3744  /* if binvar is fixed to be nonzero */
3745  if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3746  {
3747  assert( SCIPvarGetStatus(consdata->slackvar) != SCIP_VARSTATUS_MULTAGGR );
3748 
3749  /* if slack variable is not already fixed to 0 */
3750  if ( ! SCIPisZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3751  {
3752  SCIPdebugMsg(scip, "Binary variable <%s> is fixed to be nonzero, fixing slack variable <%s> to 0.\n",
3753  SCIPvarGetName(consdata->binvar), SCIPvarGetName(consdata->slackvar));
3754 
3755  /* fix slack variable to 0 */
3756  SCIP_CALL( SCIPinferVarUbCons(scip, consdata->slackvar, 0.0, cons, 0, FALSE, &infeasible, &tightened) );
3757  assert( ! infeasible );
3758  if ( tightened )
3759  ++(*nGen);
3760  }
3761  }
3762 
3763  /* if slackvar is fixed to be nonzero */
3764  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3765  {
3766  /* if binary variable is not yet fixed to 0 */
3767  if ( SCIPvarGetUbLocal(consdata->binvar) > 0.5 )
3768  {
3769  SCIPdebugMsg(scip, "Slack variable <%s> is fixed to be nonzero, fixing binary variable <%s> to 0.\n",
3770  SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3771 
3772  /* fix binary variable to 0 */
3773  SCIP_CALL( SCIPinferVarUbCons(scip, consdata->binvar, 0.0, cons, 1, FALSE, &infeasible, &tightened) );
3774  assert( ! infeasible );
3775  if ( tightened )
3776  ++(*nGen);
3777  }
3778  }
3779 
3780  /* reset constraint age counter */
3781  if ( *nGen > 0 )
3782  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3783 
3784  /* remove constraint if we are not in probing */
3785  if ( ! SCIPinProbing(scip) )
3786  {
3787  /* mark linear constraint to be update-able */
3788  if ( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && SCIPconsIsActive(consdata->lincons) )
3789  {
3790  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3791  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3792  }
3793 
3794  /* delete constraint locally */
3795  assert( ! SCIPconsIsModifiable(cons) );
3796  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3797  }
3798  }
3799  else
3800  {
3801  /* if the binary variable is fixed to zero */
3802  if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
3803  {
3804  if ( addopposite && consdata->linconsactive )
3805  {
3806  char name[SCIP_MAXSTRLEN];
3807  SCIP_CONS* reversecons;
3808  SCIP_VAR** linvars;
3809  SCIP_Real* linvals;
3810  SCIP_Bool allintegral = TRUE;
3811  SCIP_VAR* slackvar;
3812  SCIP_VAR** vars;
3813  SCIP_Real* vals;
3814  SCIP_Real lhs;
3815  SCIP_Real rhs;
3816  int nlinvars;
3817  int nvars = 0;
3818  int j;
3819 
3820  /* determine lhs/rhs (first exchange lhs/rhs) */
3821  lhs = SCIPgetRhsLinear(scip, consdata->lincons);
3822  if ( SCIPisInfinity(scip, lhs) )
3823  lhs = -SCIPinfinity(scip);
3824  rhs = SCIPgetLhsLinear(scip, consdata->lincons);
3825  if ( SCIPisInfinity(scip, -rhs) )
3826  rhs = SCIPinfinity(scip);
3827 
3828  assert( ! SCIPisInfinity(scip, lhs) );
3829  assert( ! SCIPisInfinity(scip, -rhs) );
3830 
3831  /* consider only finite lhs/rhs */
3832  if ( ! SCIPisInfinity(scip, -lhs) || ! SCIPisInfinity(scip, rhs) )
3833  {
3834  /* ignore equations (cannot add opposite constraint) */
3835  if ( ! SCIPisEQ(scip, lhs, rhs) )
3836  {
3837  assert( consdata->lincons != NULL );
3838  nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
3839  linvars = SCIPgetVarsLinear(scip, consdata->lincons);
3840  linvals = SCIPgetValsLinear(scip, consdata->lincons);
3841  slackvar = consdata->slackvar;
3842  assert( slackvar != NULL );
3843 
3844  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlinvars) );
3845  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlinvars) );
3846 
3847  /* copy data and check whether the linear constraint is integral */
3848  for (j = 0; j < nlinvars; ++j)
3849  {
3850  if ( linvars[j] != slackvar )
3851  {
3852  if (! SCIPvarIsIntegral(linvars[j]) || ! SCIPisIntegral(scip, linvals[j]) )
3853  allintegral = FALSE;
3854 
3855  vars[nvars] = linvars[j];
3856  vals[nvars++] = linvals[j];
3857  }
3858  }
3859  assert( nlinvars == nvars + 1 );
3860 
3861  /* possibly adjust lhs/rhs */
3862  if ( allintegral && ! SCIPisInfinity(scip, REALABS(lhs)) )
3863  lhs += 1.0;
3864 
3865  if ( allintegral && ! SCIPisInfinity(scip, REALABS(rhs)) )
3866  rhs -= 1.0;
3867 
3868  /* create reverse constraint */
3869  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "reverse_%s", SCIPconsGetName(consdata->lincons));
3870 
3871  /* constraint is initial, separated, not enforced, not checked, propagated, local, not modifiable, dynamic, removable */
3872  SCIP_CALL( SCIPcreateConsLinear(scip, &reversecons, name, nvars, vars, vals, lhs, rhs,
3873  TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE) );
3874 
3875  SCIPdebugMsg(scip, "Binary variable <%s> fixed to 0. Adding opposite linear inequality.\n", SCIPvarGetName(consdata->binvar));
3876  SCIPdebugPrintCons(scip, reversecons, NULL);
3877 
3878  /* add constraint */
3879  SCIP_CALL( SCIPaddCons(scip, reversecons) );
3880  SCIP_CALL( SCIPreleaseCons(scip, &reversecons) );
3881 
3882  SCIPfreeBufferArray(scip, &vals);
3883  SCIPfreeBufferArray(scip, &vars);
3884  }
3885  }
3886  }
3887 
3888  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3889  }
3890 
3891  /* if the slack variable is fixed to zero */
3892  if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3893  {
3894  /* perform dual reduction - if required */
3895  if ( dualreductions )
3896  {
3897  SCIP_VAR* binvar;
3898  SCIP_Real obj;
3899 
3900  /* check objective of binary variable */
3901  binvar = consdata->binvar;
3902  obj = varGetObjDelta(binvar);
3903 
3904  /* if obj = 0, we prefer setting the binary variable to 1 (if possible) */
3905  if ( obj <= 0.0 )
3906  {
3907  /* In this case we would like to fix the binary variable to 1, if it is not locked up
3908  except by this indicator constraint. If more than one indicator constraint is
3909  affected, we have to hope that they are all fulfilled - in this case the last
3910  constraint will fix the binary variable to 1. */
3911  if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
3912  {
3913  if ( SCIPvarGetUbLocal(binvar) > 0.5 )
3914  {
3915  SCIPdebugMsg(scip, "Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
3916  SCIP_CALL( SCIPinferVarLbCons(scip, binvar, 1.0, cons, 2, FALSE, &infeasible, &tightened) );
3917  assert( ! infeasible );
3918  if ( tightened )
3919  ++(*nGen);
3920  /* Make sure that the other case does not occur, since we are not sure whether SCIPinferVarLbCons() directly changes the bounds. */
3921  obj = -1.0;
3922  }
3923  }
3924  }
3925  if ( obj >= 0.0 )
3926  {
3927  /* In this case we would like to fix the binary variable to 0, if it is not locked down
3928  (should also have been performed by other dual reductions). */
3929  if ( SCIPvarGetNLocksDownType(binvar, SCIP_LOCKTYPE_MODEL) == 0 )
3930  {
3931  if ( SCIPvarGetLbLocal(binvar) < 0.5 )
3932  {
3933  SCIPdebugMsg(scip, "Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
3934  SCIP_CALL( SCIPinferVarUbCons(scip, binvar, 0.0, cons, 2, FALSE, &infeasible, &tightened) );
3935  assert( ! infeasible );
3936  if ( tightened )
3937  ++(*nGen);
3938  }
3939  }
3940  }
3941  }
3942 
3943  SCIPdebugMsg(scip, "Slack variable fixed to zero, delete redundant indicator constraint <%s>.\n", SCIPconsGetName(cons));
3944 
3945  /* delete constraint */
3946  assert( ! SCIPconsIsModifiable(cons) );
3947 
3948  /* remove constraint if we are not in probing */
3949  if ( ! SCIPinProbing(scip) )
3950  {
3951  /* mark linear constraint to be update-able */
3952  if ( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && SCIPconsIsActive(consdata->lincons) )
3953  {
3954  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3955  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3956  }
3957 
3958  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3959  }
3960  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3961  ++(*nGen);
3962  }
3963 
3964  /* Note that because of possible multi-aggregation we cannot simply remove the indicator
3965  * constraint if the linear constraint is not active or disabled - see the note in @ref
3966  * PREPROC and consPresolIndicator(). Moreover, it would drastically increase memory
3967  * consumption, because the linear constraints have to be stored in each node. */
3968  }
3969 
3970  return SCIP_OKAY;
3971 }
3972 
3973 
3974 /** enforcement method that produces cuts if possible
3975  *
3976  * This is a variant of the enforcement method that generates cuts/constraints via the alternative
3977  * LP, if possible.
3978  */
3979 static
3981  SCIP* scip, /**< SCIP pointer */
3982  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3983  int nconss, /**< number of constraints */
3984  SCIP_CONS** conss, /**< indicator constraints */
3985  SCIP_SOL* sol, /**< solution to be enforced */
3986  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
3987  SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
3988  SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
3989  int* nGen /**< number of cuts generated */
3990  )
3991 {
3992  SCIP_CONSHDLRDATA* conshdlrdata;
3993  SCIP_LPI* lp;
3994  SCIP_Bool* S;
3995  SCIP_Real value = 0.0;
3996  SCIP_Bool error;
3997  int size = 0;
3998  int nCuts;
3999  int j;
4000 
4001  assert( scip != NULL );
4002  assert( conshdlr != NULL );
4003  assert( conss != NULL );
4004  assert( cutoff != NULL );
4005  assert( nGen != NULL );
4006 
4007  SCIPdebugMsg(scip, "Enforcing via cuts ...\n");
4008  *cutoff = FALSE;
4009  *nGen = 0;
4010 
4011  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4012  assert( conshdlrdata != NULL );
4013  lp = conshdlrdata->altlp;
4014  assert( lp != NULL );
4015 
4016 #ifndef NDEBUG
4017  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4018 #endif
4019 
4020  /* change coefficients of bounds in alternative LP */
4021  if ( conshdlrdata->updatebounds )
4022  SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
4023 
4024  /* possibly update upper bound */
4025  SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4026 
4027  /* scale first row if necessary */
4028  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
4029 
4030  /* set objective function to current solution */
4031  SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
4032 
4033  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
4034 
4035  /* set up variables fixed to 1 */
4036  for (j = 0; j < nconss; ++j)
4037  {
4038  SCIP_CONSDATA* consdata;
4039 
4040  assert( conss[j] != NULL );
4041  consdata = SCIPconsGetData(conss[j]);
4042  assert( consdata != NULL );
4043 
4044  assert( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
4045  if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
4046  {
4047  ++size;
4048  value += varGetObjDelta(consdata->binvar);
4049  S[j] = TRUE;
4050  }
4051  else
4052  S[j] = FALSE;
4053  }
4054 
4055  /* fix the variables in S */
4056  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
4057 
4058  /* extend set S to a cover and generate cuts */
4059  error = FALSE;
4060  SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, genlogicor, nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
4061  *nGen = nCuts;
4062 
4063  /* return with an error if no cuts have been produced and and error occurred in extendToCover() */
4064  if ( nCuts == 0 && error )
4065  return SCIP_LPERROR;
4066 
4067  SCIPdebugMsg(scip, "Generated %d IIS-cuts.\n", nCuts);
4068 
4069  /* reset bounds */
4070  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
4071 
4072 #ifndef NDEBUG
4073  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4074 #endif
4075 
4076  SCIPfreeBufferArray(scip, &S);
4077 
4078  return SCIP_OKAY;
4079 }
4080 
4081 
4082 /** enforcement method
4083  *
4084  * We check whether the current solution is feasible, i.e., if binvar = 1
4085  * implies that slackvar = 0. If not, we branch as follows:
4086  *
4087  * In one branch we fix binvar = 1 and slackvar = 0. In the other branch
4088  * we fix binvar = 0 and leave slackvar unchanged.
4089  */
4090 static
4092  SCIP* scip, /**< SCIP pointer */
4093  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4094  int nconss, /**< number of constraints */
4095  SCIP_CONS** conss, /**< indicator constraints */
4096  SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
4097  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4098  SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
4099  SCIP_RESULT* result /**< result */
4100  )
4101 {
4102  SCIP_CONSDATA* consdata;
4103  SCIP_CONSHDLRDATA* conshdlrdata;
4104  SCIP_NODE* node1;
4105  SCIP_NODE* node2;
4106  SCIP_VAR* slackvar;
4107  SCIP_VAR* binvar;
4109  SCIP_Real maxSlack = -1.0;
4110  SCIP_Bool someLinconsNotActive = FALSE;
4111  int c;
4112 
4113  assert( scip != NULL );
4114  assert( conshdlr != NULL );
4115  assert( conss != NULL );
4116  assert( result != NULL );
4117 
4118  *result = SCIP_FEASIBLE;
4119 
4120  SCIPdebugMsg(scip, "Enforcing indicator constraints for <%s> ...\n", SCIPconshdlrGetName(conshdlr) );
4121 
4122  /* get constraint handler data */
4123  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4124  assert( conshdlrdata != NULL );
4125 
4126 #ifdef SCIP_OUTPUT
4127  SCIP_CALL( SCIPwriteTransProblem(scip, "ind.cip", "cip", FALSE) );
4128 #endif
4129 
4130  /* check each constraint */
4131  for (c = 0; c < nconss; ++c)
4132  {
4133  SCIP_Bool cutoff;
4134  SCIP_Real valSlack;
4135  int cnt;
4136 
4137  assert( conss[c] != NULL );
4138  consdata = SCIPconsGetData(conss[c]);
4139  assert( consdata != NULL );
4140  assert( consdata->lincons != NULL );
4141 
4142  /* if the linear constraint has not been generated, we do nothing */
4143  if ( ! consdata->linconsactive )
4144  {
4145  someLinconsNotActive = TRUE;
4146  continue;
4147  }
4148 
4149  /* first perform propagation (it might happen that standard propagation is turned off) */
4150  SCIP_CALL( propIndicator(scip, conss[c], consdata,
4151  conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip), conshdlrdata->addopposite,
4152  &cutoff, &cnt) );
4153  if ( cutoff )
4154  {
4155  SCIPdebugMsg(scip, "Propagation in enforcing <%s> detected cutoff.\n", SCIPconsGetName(conss[c]));
4156  *result = SCIP_CUTOFF;
4157  return SCIP_OKAY;
4158  }
4159  if ( cnt > 0 )
4160  {
4161  SCIPdebugMsg(scip, "Propagation in enforcing <%s> reduced domains: %d.\n", SCIPconsGetName(conss[c]), cnt);
4162  *result = SCIP_REDUCEDDOM;
4163  return SCIP_OKAY;
4164  }
4165 
4166  /* check whether constraint is infeasible */
4167  binvar = consdata->binvar;
4168  valSlack = SCIPgetSolVal(scip, sol, consdata->slackvar);
4169  assert( ! SCIPisFeasNegative(scip, valSlack) );
4170  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, binvar)) && ! SCIPisFeasZero(scip, valSlack) )
4171  {
4172  /* binary variable is not fixed - otherwise we would not be infeasible */
4173  assert( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 );
4174 
4175  if ( valSlack > maxSlack )
4176  {
4177  maxSlack = valSlack;
4178  branchCons = conss[c];
4179 #ifdef SCIP_OUTPUT
4180  SCIPinfoMessage(scip, NULL, "Violated indicator constraint:\n");
4181  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
4182  SCIPinfoMessage(scip, NULL, ";\n");
4183  SCIPinfoMessage(scip, NULL, "Corresponding linear constraint:\n");
4184  SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
4185  SCIPinfoMessage(scip, NULL, ";\n");
4186 #endif
4187  }
4188  }
4189  }
4190 
4191  /* if some constraint has a linear constraint that is not active, we need to check feasibility via the alternative polyhedron */
4192  if ( (someLinconsNotActive || conshdlrdata->enforcecuts) && conshdlrdata->sepaalternativelp )
4193  {
4194  SCIP_Bool cutoff;
4195  int ngen;
4196 
4197  SCIP_CALL( enforceCuts(scip, conshdlr, nconss, conss, sol, enfosepatype, genlogicor, &cutoff, &ngen) );
4198  if ( cutoff )
4199  {
4200  conshdlrdata->niiscutsgen += ngen;
4201  *result = SCIP_CUTOFF;
4202  return SCIP_OKAY;
4203  }
4204 
4205  if ( ngen > 0 )
4206  {
4207  conshdlrdata->niiscutsgen += ngen;
4208  if ( genlogicor )
4209  {
4210  SCIPdebugMsg(scip, "Generated %d constraints.\n", ngen);
4211  *result = SCIP_CONSADDED;
4212  }
4213  else
4214  {
4215  SCIPdebugMsg(scip, "Generated %d cuts.\n", ngen);
4216  *result = SCIP_SEPARATED;
4217  }
4218  return SCIP_OKAY;
4219  }
4220  SCIPdebugMsg(scip, "Enforcing produced no cuts.\n");
4221 
4222  assert( ! someLinconsNotActive || branchCons == NULL );
4223  }
4224 
4225  /* if all constraints are feasible */
4226  if ( branchCons == NULL )
4227  {
4228  SCIPdebugMsg(scip, "All indicator constraints are feasible.\n");
4229  return SCIP_OKAY;
4230  }
4231 
4232  /* skip branching if required */
4233  if ( ! conshdlrdata->branchindicators )
4234  {
4235  *result = SCIP_INFEASIBLE;
4236  return SCIP_OKAY;
4237  }
4238 
4239  /* otherwise create branches */
4240  SCIPdebugMsg(scip, "Branching on constraint <%s> (slack value: %f).\n", SCIPconsGetName(branchCons), maxSlack);
4241  consdata = SCIPconsGetData(branchCons);
4242  assert( consdata != NULL );
4243  binvar = consdata->binvar;
4244  slackvar = consdata->slackvar;
4245 
4246  /* node1: binvar = 1, slackvar = 0 */
4247  SCIP_CALL( SCIPcreateChild(scip, &node1, 0.0, SCIPcalcChildEstimate(scip, binvar, 1.0) ) );
4248 
4249  if ( SCIPvarGetLbLocal(binvar) < 0.5 )
4250  {
4251  SCIP_CALL( SCIPchgVarLbNode(scip, node1, binvar, 1.0) );
4252  }
4253 
4254  /* if slack-variable is multi-aggregated */
4255  assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
4256  if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(slackvar)) )
4257  {
4258  SCIP_CALL( SCIPchgVarUbNode(scip, node1, slackvar, 0.0) );
4259  }
4260 
4261  /* node2: binvar = 0, no restriction on slackvar */
4262  SCIP_CALL( SCIPcreateChild(scip, &node2, 0.0, SCIPcalcChildEstimate(scip, binvar, 0.0) ) );
4263 
4264  if ( SCIPvarGetUbLocal(binvar) > 0.5 )
4265  {
4266  SCIP_CALL( SCIPchgVarUbNode(scip, node2, binvar, 0.0) );
4267  }
4268 
4269  SCIP_CALL( SCIPresetConsAge(scip, branchCons) );
4270  *result = SCIP_BRANCHED;
4271 
4272  return SCIP_OKAY;
4273 }
4274 
4275 
4276 /** separate IIS-cuts via rounding
4277  *
4278  * @todo Check whether the cover produced at the end is a feasible solution.
4279  */
4280 static
4282  SCIP* scip, /**< SCIP pointer */
4283  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4284  SCIP_SOL* sol, /**< solution to be separated */
4285  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4286  int nconss, /**< number of constraints */
4287  SCIP_CONS** conss, /**< indicator constraints */
4288  int maxsepacuts, /**< maximal number of cuts to be generated */
4289  SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
4290  int* nGen /**< number of domain changes */
4291  )
4292 { /*lint --e{850}*/
4293  SCIP_CONSHDLRDATA* conshdlrdata;
4294  SCIP_LPI* lp;
4295  int rounds;
4296  SCIP_Real threshold;
4297  SCIP_Bool* S;
4298  SCIP_Bool error;
4299  int oldsize = -1;
4300  SCIPdebug( int nGenOld = *nGen; )
4301 
4302  assert( scip != NULL );
4303  assert( conshdlr != NULL );
4304  assert( conss != NULL );
4305  assert( cutoff != NULL );
4306  assert( nGen != NULL );
4307 
4308  if ( *nGen >= maxsepacuts )
4309  return SCIP_OKAY;
4310 
4311  *cutoff = FALSE;
4312  rounds = 0;
4313 
4314  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4315  assert( conshdlrdata != NULL );
4316  lp = conshdlrdata->altlp;
4317  assert( lp != NULL );
4318 
4319  SCIPdebugMsg(scip, "Separating IIS-cuts by rounding ...\n");
4320 
4321 #ifndef NDEBUG
4322  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4323 #endif
4324 
4325  /* change coefficients of bounds in alternative LP */
4326  if ( conshdlrdata->updatebounds )
4327  {
4328  /* update to local bounds */
4329  SCIP_CALL( updateFirstRow(scip, conshdlrdata) );
4330  }
4331 
4332  /* possibly update upper bound */
4333  SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4334 
4335  /* scale first row if necessary */
4336  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
4337 
4338  /* set objective function to current solution */
4339  SCIP_CALL( setAltLPObj(scip, lp, sol, nconss, conss) );
4340 
4341  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
4342 
4343  /* loop through the possible thresholds */
4344  for (threshold = conshdlrdata->roundingmaxthres;
4345  rounds < conshdlrdata->maxroundingrounds && threshold >= conshdlrdata->roundingminthres && *nGen < maxsepacuts && ! (*cutoff);
4346  threshold -= conshdlrdata->roundingoffset )
4347  {
4348  SCIP_Real value = 0.0;
4349  int size = 0;
4350  int nCuts = 0;
4351  int j;
4352 #ifdef SCIP_DEBUG
4353  int nvarsone = 0;
4354  int nvarszero = 0;
4355  int nvarsfrac = 0;
4356 #endif
4357 
4358  SCIPdebugMsg(scip, "Threshold: %g.\n", threshold);
4359 
4360  /* choose variables that have a value < current threshold value */
4361  for (j = 0; j < nconss; ++j)
4362  {
4363  SCIP_CONSDATA* consdata;
4364  SCIP_Real binvarval;
4365  SCIP_VAR* binvarneg;
4366 
4367  assert( conss[j] != NULL );
4368  consdata = SCIPconsGetData(conss[j]);
4369  assert( consdata != NULL );
4370 
4371  binvarval = SCIPgetVarSol(scip, consdata->binvar);
4372 
4373 #ifdef SCIP_DEBUG
4374  if ( SCIPisFeasEQ(scip, binvarval, 1.0) )
4375  ++nvarsone;
4376  else if ( SCIPisFeasZero(scip, binvarval) )
4377  ++nvarszero;
4378  else
4379  ++nvarsfrac;
4380 #endif
4381 
4382  /* check whether complementary (negated) variable is present as well */
4383  binvarneg = SCIPvarGetNegatedVar(consdata->binvar);
4384  assert( binvarneg != NULL );
4385 
4386  /* negated variable is present as well */
4387  assert( conshdlrdata->binvarhash != NULL );
4388  if ( SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarneg) )
4389  {
4390  SCIP_Real binvarnegval = SCIPgetVarSol(scip, binvarneg);
4391 
4392  /* take larger one */
4393  if ( binvarval > binvarnegval )
4394  S[j] = TRUE;
4395  else
4396  S[j] = FALSE;
4397  continue;
4398  }
4399 
4400  /* check for threshold */
4401  if ( SCIPisFeasLT(scip, SCIPgetVarSol(scip, consdata->binvar), threshold) )
4402  {
4403  S[j] = TRUE;
4404  value += varGetObjDelta(consdata->binvar);
4405  ++size;
4406  }
4407  else
4408  S[j] = FALSE;
4409  }
4410 
4411  if ( size == nconss )
4412  {
4413  SCIPdebugMsg(scip, "All variables in the set. Continue ...\n");
4414  continue;
4415  }
4416 
4417  /* skip computation if size has not changed (computation is likely the same) */
4418  if ( size == oldsize )
4419  {
4420  SCIPdebugMsg(scip, "Skipping computation: size support has not changed.\n");
4421  continue;
4422  }
4423  oldsize = size;
4424 
4425 #ifdef SCIP_DEBUG
4426  SCIPdebugMsg(scip, " Vars with value 1: %d 0: %d and fractional: %d.\n", nvarsone, nvarszero, nvarsfrac);
4427 #endif
4428 
4429  /* fix the variables in S */
4430  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
4431 
4432  /* extend set S to a cover and generate cuts */
4433  SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, conshdlrdata->genlogicor,
4434  nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
4435 
4436  /* we ignore errors in extendToCover */
4437  if ( nCuts > 0 )
4438  {
4439  *nGen += nCuts;
4440  ++rounds;
4441  }
4442  else
4443  {
4444  /* possibly update upper bound */
4445  SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4446  }
4447 
4448  /* reset bounds */
4449  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
4450  }
4451  SCIPdebug( SCIPdebugMsg(scip, "Generated %d IISs.\n", *nGen - nGenOld); )
4452 
4453 #ifndef NDEBUG
4454  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4455 #endif
4456 
4457  SCIPfreeBufferArray(scip, &S);
4458 
4459  return SCIP_OKAY;
4460 }
4461 
4462 
4463 
4464 /** separate cuts based on perspective formulation
4465  *
4466  * Hijazi, Bonami, and Ouorou (2014) introduced the following cuts: We consider an indicator constraint
4467  * \f[
4468  * y = 1 \rightarrow \alpha^T x \leq \beta
4469  * \f]
4470  * and assume finite bounds \f$\ell \leq x \leq u\f$. Then for \f$I \subseteq \{1, \dots, n\}\f$ define
4471  * \f[
4472  * \Sigma(I,x,y) = \sum_{i \notin I} \alpha_i x_i +
4473  * y \Big(\sum_{i \in I, \alpha_i < 0} \alpha_i u_i + \sum_{i \in I, \alpha_i > 0} \alpha_i \ell_i +
4474  * \sum_{i \notin I, \alpha_i < 0} \alpha_i \ell_i + \sum_{i \notin I, \alpha_i > 0} \alpha_i u_i - \beta\Big).
4475  * \f]
4476  * Then the cuts
4477  * \f[
4478  * \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
4479  * \f]
4480  * are valid for the disjunction
4481  * \f[
4482  * \{y = 0,\; \ell \leq x \leq u\} \cup \{y = 1,\; \ell \leq x \leq u,\; \alpha^T x \leq \beta\}.
4483  * \f]
4484  * 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
4485  * \f[
4486  * y^*(\alpha_i\, u_i\, [\alpha_i < 0] + \alpha_i\, \ell_i\, [\alpha_i > 0]) >
4487  * \alpha_i x_i^* + y^* )\alpha_i \ell_i [\alpha_i < 0] + \alpha_i u_i [\alpha_i > 0]),
4488  * \f]
4489  * where \f$[C] = 1\f$ if condition \f$C\f$ is satisfied, otherwise it is 0.
4490  * If the above inequality holds, \f$i\f$ is included in \f$I\f$, otherwise not.
4491  */
4492 static
4494  SCIP* scip, /**< SCIP pointer */
4495  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4496  SCIP_SOL* sol, /**< solution to be separated */
4497  int nconss, /**< number of constraints */
4498  SCIP_CONS** conss, /**< indicator constraints */
4499  int maxsepacuts, /**< maximal number of cuts to be generated */
4500  int* nGen /**< number of generated cuts */
4501  )
4502 { /*lint --e{850}*/
4503  SCIP_CONSHDLRDATA* conshdlrdata;
4504  SCIP_VAR** cutvars;
4505  SCIP_Real* cutvals;
4506  int nvars;
4507  int c;
4508 
4509  assert( scip != NULL );
4510  assert( conshdlr != NULL );
4511  assert( conss != NULL );
4512  assert( nGen != NULL );
4513 
4514  if ( *nGen >= maxsepacuts )
4515  return SCIP_OKAY;
4516 
4517  nvars = SCIPgetNVars(scip);
4518  SCIP_CALL( SCIPallocBufferArray(scip, &cutvars, nvars+1) );
4519  SCIP_CALL( SCIPallocBufferArray(scip, &cutvals, nvars+1) );
4520 
4521  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4522  assert( conshdlrdata != NULL );
4523 
4524  /* loop through constraints */
4525  for (c = 0; c < nconss; ++c)
4526  {
4527  SCIP_CONSDATA* consdata;
4528  SCIP_CONS* lincons;
4529  SCIP_VAR* slackvar;
4530  SCIP_VAR* binvar;
4531  SCIP_Real binval;
4532 
4533  assert( conss[c] != NULL );
4534  consdata = SCIPconsGetData(conss[c]);
4535  assert( consdata != NULL );
4536  slackvar = consdata->slackvar;
4537 
4538  lincons = consdata->lincons;
4539  assert( lincons != NULL );
4540 
4541  binvar = consdata->binvar;
4542  assert( binvar != NULL );
4543  binval = SCIPgetSolVal(scip, sol, binvar);
4544 
4545  if ( SCIPconsIsActive(lincons) )
4546  {
4547  SCIP_VAR** linvars;
4548  SCIP_Real* linvals;
4549  SCIP_Real linrhs;
4550  SCIP_Bool finitebound = TRUE;
4551  SCIP_Real cutrhs = 0.0;
4552  SCIP_Real cutval;
4553  SCIP_Real signfactor = 1.0;
4554  SCIP_Real ypart;
4555  SCIP_Bool islocal = FALSE;
4556  int nlinvars;
4557  int cnt = 0;
4558  int j;
4559 
4560  linvars = SCIPgetVarsLinear(scip, lincons);
4561  linvals = SCIPgetValsLinear(scip, lincons);
4562  nlinvars = SCIPgetNVarsLinear(scip, lincons);
4563 
4564  linrhs = SCIPgetRhsLinear(scip, lincons);
4565  if ( SCIPisInfinity(scip, linrhs) )
4566  {
4567  if ( ! SCIPisInfinity(scip, SCIPgetLhsLinear(scip, lincons)) )
4568  {
4569  linrhs = -SCIPgetLhsLinear(scip, lincons);
4570  signfactor = -1.0;
4571  }
4572  else
4573  continue;
4574  }
4575  ypart = -linrhs;
4576  cutval = binval * ypart;
4577 
4578  for (j = 0; j < nlinvars; ++j)
4579  {
4580  SCIP_Real linval;
4581  SCIP_Real lb;
4582  SCIP_Real ub;
4583  SCIP_Real din = 0.0;
4584  SCIP_Real dout = 0.0;
4585  SCIP_Real xpart;
4586  SCIP_Real xval;
4587 
4588  if ( linvars[j] == slackvar )
4589  continue;
4590 
4591  if ( conshdlrdata->sepapersplocal )
4592  {
4593  lb = SCIPvarGetLbLocal(linvars[j]);
4594  ub = SCIPvarGetUbLocal(linvars[j]);
4595 
4596  if ( lb > SCIPvarGetLbGlobal(linvars[j]) )
4597  islocal = TRUE;
4598  if ( ub < SCIPvarGetUbGlobal(linvars[j]) )
4599  islocal = TRUE;
4600  }
4601  else
4602  {
4603  lb = SCIPvarGetLbGlobal(linvars[j]);
4604  ub = SCIPvarGetUbGlobal(linvars[j]);
4605  }
4606 
4607  /* skip cases with unbounded variables */
4608  if ( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
4609  {
4610  finitebound = FALSE;
4611  break;
4612  }
4613 
4614  /* compute rest parts for i in the set (din) or not in the set (dout) */
4615  linval = signfactor * linvals[j];
4616  if ( SCIPisNegative(scip, linval) )
4617  {
4618  din += linval * ub;
4619  dout += linval * lb;
4620  }
4621  else if ( SCIPisPositive(scip, linval) )
4622  {
4623  din += linval * lb;
4624  dout += linval * ub;
4625  }
4626 
4627  xval = SCIPgetSolVal(scip, sol, linvars[j]);
4628  xpart = linval * xval;
4629 
4630  /* if din > dout, we want to include i in the set */
4631  if ( SCIPisGT(scip, binval * din, binval * dout + xpart) )
4632  {
4633  ypart += din;
4634  cutval += binval * din;
4635  }
4636  else
4637  {
4638  /* otherwise i is not in the set */
4639  ypart += dout;
4640 
4641  cutrhs += dout;
4642  cutval += binval * dout + xpart;
4643 
4644  cutvars[cnt] = linvars[j];
4645  cutvals[cnt++] = linval;
4646  }
4647  }
4648 
4649  if ( ! finitebound )
4650  continue;
4651 
4652  if ( SCIPisEfficacious(scip, cutval - cutrhs) )
4653  {
4654  SCIP_ROW* row;
4655  SCIP_Bool infeasible;
4656  char name[50];
4657 
4658  /* add y-variable */
4659  cutvars[cnt] = binvar;
4660  cutvals[cnt] = ypart;
4661  ++cnt;
4662 
4663  SCIPdebugMsg(scip, "Found cut of lhs value %f > %f.\n", cutval, cutrhs);
4664  (void) SCIPsnprintf(name, 50, "persp%d", conshdlrdata->nperspcutsgen + *nGen);
4665  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), cutrhs, islocal, FALSE, conshdlrdata->removable) );
4666  SCIP_CALL( SCIPaddVarsToRow(scip, row, cnt, cutvars, cutvals) );
4667 #ifdef SCIP_OUTPUT
4668  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
4669 #endif
4670  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
4671  assert( ! infeasible );
4672  SCIP_CALL( SCIPreleaseRow(scip, &row));
4673  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
4674  ++(*nGen);
4675  }
4676  }
4677  if ( *nGen >= maxsepacuts )
4678  break;
4679  }
4680 
4681  SCIPfreeBufferArray(scip, &cutvals);
4682  SCIPfreeBufferArray(scip, &cutvars);
4683 
4684  return SCIP_OKAY;
4685 }
4686 
4687 
4688 /** separation method
4689  *
4690  * We first check whether coupling inequalities can be separated (if required). If not enough of
4691  * these could be generated, we check whether IIS inequalities can be separated.
4692  */
4693 static
4695  SCIP* scip, /**< SCIP pointer */
4696  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4697  int nconss, /**< number of constraints */
4698  int nusefulconss, /**< number of useful constraints */
4699  SCIP_CONS** conss, /**< indicator constraints */
4700  SCIP_SOL* sol, /**< solution to be separated */
4701  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4702  SCIP_RESULT* result /**< result */
4703  )
4704 {
4705  SCIP_CONSHDLRDATA* conshdlrdata;
4706  int maxsepacuts;
4707  int ncuts;
4708 
4709  assert( scip != NULL );
4710  assert( conshdlr != NULL );
4711  assert( conss != NULL );
4712  assert( result != NULL );
4713 
4714  *result = SCIP_DIDNOTRUN;
4715 
4716  if ( nconss == 0 )
4717  return SCIP_OKAY;
4718 
4719  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4720  assert( conshdlrdata != NULL );
4721  ncuts = 0;
4722 
4723  /* get the maximal number of cuts allowed in a separation round */
4724  if ( SCIPgetDepth(scip) == 0 )
4725  maxsepacuts = conshdlrdata->maxsepacutsroot;
4726  else
4727  maxsepacuts = conshdlrdata->maxsepacuts;
4728 
4729  /* first separate coupling inequalities (if required) */
4730  if ( conshdlrdata->sepacouplingcuts )
4731  {
4732  int c;
4733 
4734  *result = SCIP_DIDNOTFIND;
4735 
4736  /* check each constraint */
4737  for (c = 0; c < nusefulconss && ncuts < maxsepacuts; ++c)
4738  {
4739  SCIP_CONSDATA* consdata;
4740  SCIP_Bool islocal;
4741  SCIP_Real ub;
4742 
4743  assert( conss != NULL );
4744  assert( conss[c] != NULL );
4745  consdata = SCIPconsGetData(conss[c]);
4746  assert( consdata != NULL );
4747  assert( consdata->slackvar != NULL );
4748  assert( consdata->binvar != NULL );
4749 
4750  /* get upper bound for slack variable in linear constraint */
4751  islocal = FALSE;
4752  if ( conshdlrdata->sepacouplinglocal )
4753  {
4754  ub = SCIPvarGetUbLocal(consdata->slackvar);
4755  if ( ub < SCIPvarGetUbGlobal(consdata->slackvar) )
4756  islocal = TRUE;
4757  }
4758  else
4759  ub = SCIPvarGetUbGlobal(consdata->slackvar);
4760  assert( ! SCIPisFeasNegative(scip, ub) );
4761 
4762  /* only use coefficients that are not too large */
4763  if ( ub <= conshdlrdata->sepacouplingvalue )
4764  {
4765  SCIP_Real activity;
4766 
4767  activity = SCIPgetSolVal(scip, sol, consdata->slackvar) + ub * SCIPgetSolVal(scip, sol, consdata->binvar) - ub;
4768  if ( SCIPisEfficacious(scip, activity) )
4769  {
4770  SCIP_ROW* row;
4771  SCIP_Bool infeasible;
4772 #ifndef NDEBUG
4773  char name[50];
4774 
4775  (void) SCIPsnprintf(name, 50, "couple%d", c);
4776  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
4777 #else
4778  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], "", -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
4779 #endif
4780  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4781 
4782  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
4783  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
4784  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4785 
4786  SCIPdebugMsg(scip, "Separated coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
4787 #ifdef SCIP_OUTPUT
4788  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
4789 #endif
4790  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
4791  assert( ! infeasible );
4792  SCIP_CALL( SCIPreleaseRow(scip, &row));
4793 
4794  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
4795  *result = SCIP_SEPARATED;
4796 
4797  ++ncuts;
4798  }
4799  }
4800  }
4801  SCIPdebugMsg(scip, "Number of separated coupling inequalities: %d.\n", ncuts);
4802  }
4803 
4804  /* separate cuts from the alternative lp (if required) */
4805  if ( conshdlrdata->sepaalternativelp && ncuts < SEPAALTTHRESHOLD )
4806  {
4807  SCIP_Bool cutoff;
4808  int noldcuts;
4809 
4810  SCIPdebugMsg(scip, "Separating inequalities for indicator constraints.\n");
4811 
4812  noldcuts = ncuts;
4813  if ( *result == SCIP_DIDNOTRUN )
4814  *result = SCIP_DIDNOTFIND;
4815 
4816  /* start separation */
4817  SCIP_CALL( separateIISRounding(scip, conshdlr, sol, enfosepatype, nconss, conss, maxsepacuts, &cutoff, &ncuts) );
4818  SCIPdebugMsg(scip, "Separated %d cuts from indicator constraints.\n", ncuts - noldcuts);
4819 
4820  if ( cutoff )
4821  *result = SCIP_CUTOFF;
4822  else if ( ncuts > noldcuts )
4823  {
4824  conshdlrdata->niiscutsgen += ncuts;
4825 
4826  /* possibly overwrite result from separation above */
4827  if ( conshdlrdata->genlogicor )
4828  *result = SCIP_CONSADDED;
4829  else
4830  *result = SCIP_SEPARATED;
4831  }
4832  }
4833 
4834  /* separate cuts based on perspective formulation */
4835  if ( conshdlrdata->sepaperspective && ncuts < SEPAALTTHRESHOLD )
4836  {
4837  int noldcuts;
4838 
4839  SCIPdebugMsg(scip, "Separating inequalities based on perspective formulation.\n");
4840 
4841  noldcuts = ncuts;
4842  if ( *result == SCIP_DIDNOTRUN )
4843  *result = SCIP_DIDNOTFIND;
4844 
4845  /* start separation */
4846  SCIP_CALL( separatePerspective(scip, conshdlr, sol, nconss, conss, maxsepacuts, &ncuts) );
4847  SCIPdebugMsg(scip, "Separated %d cuts from perspective formulation.\n", ncuts - noldcuts);
4848 
4849  if ( ncuts > noldcuts )
4850  {
4851  conshdlrdata->nperspcutsgen += ncuts;
4852 
4853  /* possibly overwrite result from separation above */
4854  *result = SCIP_SEPARATED;
4855  }
4856  }
4857 
4858  return SCIP_OKAY;
4859 }
4860 
4861 
4862 /** initializes the constraint handler data */
4863 static
4864 void initConshdlrData(
4865  SCIP* scip, /**< SCIP pointer */
4866  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
4867  )
4868 {
4869  assert( conshdlrdata != NULL );
4870 
4871  conshdlrdata->removable = TRUE;
4872  conshdlrdata->scaled = FALSE;
4873  conshdlrdata->altlp = NULL;
4874  conshdlrdata->nrows = 0;
4875  conshdlrdata->varhash = NULL;
4876  conshdlrdata->slackhash = NULL;
4877  conshdlrdata->lbhash = NULL;
4878  conshdlrdata->ubhash = NULL;
4879  conshdlrdata->nlbbounds = 0;
4880  conshdlrdata->nubbounds = 0;
4881  conshdlrdata->nslackvars = 0;
4882  conshdlrdata->objcutindex = -1;
4883  conshdlrdata->objupperbound = SCIPinfinity(scip);
4884  conshdlrdata->objaltlpbound = SCIPinfinity(scip);
4885  conshdlrdata->roundingminthres = 0.1;
4886  conshdlrdata->roundingmaxthres = 0.6;
4887  conshdlrdata->maxroundingrounds = MAXROUNDINGROUNDS;
4888  conshdlrdata->roundingoffset = 0.1;
4889  conshdlrdata->addedcouplingcons = FALSE;
4890  conshdlrdata->ninitconss = 0;
4891  conshdlrdata->nbinvarszero = 0;
4892  conshdlrdata->performedrestart = FALSE;
4893  conshdlrdata->objindicatoronly = FALSE;
4894  conshdlrdata->objothervarsonly = FALSE;
4895  conshdlrdata->minabsobj = 0.0;
4896  conshdlrdata->normtype = 'e';
4897  conshdlrdata->niiscutsgen = 0;
4898  conshdlrdata->nperspcutsgen = 0;
4899 }
4900 
4901 
4902 /* ---------------------------- upgrading methods -----------------------------------*/
4903 
4904 /** tries to upgrade a linear constraint into an indicator constraint
4905  *
4906  * 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
4907  * it to an indicator constraint if for the residual value \f$a^T x \geq \gamma\f$, we have \f$\alpha + \gamma \geq
4908  * \beta\f$: in this case, the constraint is always satisfied if \f$y = 1\f$.
4909  *
4910  * 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
4911  * upgrade it to an indicator constraint if for the residual value \f$a^T x \leq \gamma\f$, we have \f$\alpha + \gamma
4912  * \leq \beta\f$.
4913  */
4914 static
4915 SCIP_DECL_LINCONSUPGD(linconsUpgdIndicator)
4916 { /*lint --e{715}*/
4917  SCIP_CONSHDLRDATA* conshdlrdata;
4918  SCIP_CONSHDLR* conshdlr;
4919  SCIP_Real minactivity = 0.0;
4920  SCIP_Real maxactivity = 0.0;
4921  SCIP_Real maxabsval = -1.0;
4922  SCIP_Real secabsval = -1.0;
4923  int maxabsvalidx = -1;
4924  int j;
4925 
4926  assert( scip != NULL );
4927  assert( upgdcons != NULL );
4928  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0 );
4929  assert( ! SCIPconsIsModifiable(cons) );
4930 
4931  /* do not upgrade if there are at most 2 variables (2 variables should be upgraded to a varbound constraint) */
4932  if ( nvars <= 2 )
4933  return SCIP_OKAY;
4934 
4935  /* cannot currently ranged constraints, since we can only return one constraint (and we would need one for each side each) */
4936  if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
4937  return SCIP_OKAY;
4938 
4939  /* check whether upgrading is turned on */
4940  conshdlr = SCIPfindConshdlr(scip, "indicator");
4941  assert( conshdlr != NULL );
4942  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4943  assert( conshdlrdata != NULL );
4944 
4945  if ( ! conshdlrdata->upgradelinear )
4946  return SCIP_OKAY;
4947 
4948  /* calculate activities */
4949  for (j = 0; j < nvars; ++j)
4950  {
4951  SCIP_VAR* var;
4952  SCIP_Real val;
4953  SCIP_Real lb;
4954  SCIP_Real ub;
4955 
4956  val = vals[j];
4957  assert( ! SCIPisZero(scip, val) );
4958 
4959  var = vars[j];
4960  assert( var != NULL );
4961 
4962  /* store maximal (and second to largest) value of coefficients */
4963  if ( SCIPisGE(scip, REALABS(val), maxabsval) )
4964  {
4965  secabsval = maxabsval;
4966  maxabsval = REALABS(val);
4967  maxabsvalidx = j;
4968  }
4969 
4970  if ( ! SCIPvarIsBinary(var) )
4971  {
4972  if ( val > 0.0 )
4973  {
4974  lb = SCIPvarGetLbGlobal(var);
4975  ub = SCIPvarGetUbGlobal(var);
4976  }
4977  else
4978  {
4979  ub = SCIPvarGetLbGlobal(var);
4980  lb = SCIPvarGetUbGlobal(var);
4981  }
4982 
4983  /* compute minimal activity */
4984  if ( SCIPisInfinity(scip, -lb) )
4985  minactivity = -SCIPinfinity(scip);
4986  else
4987  {
4988  if ( ! SCIPisInfinity(scip, -minactivity) )
4989  minactivity += val * lb;
4990  }
4991 
4992  /* compute maximal activity */
4993  if ( SCIPisInfinity(scip, ub) )
4994  maxactivity = SCIPinfinity(scip);
4995  else
4996  {
4997  if ( ! SCIPisInfinity(scip, maxactivity) )
4998  maxactivity += val * ub;
4999  }
5000  }
5001  }
5002  assert( maxabsval >= 0.0 );
5003  assert( 0 <= maxabsvalidx && maxabsvalidx < nvars );
5004 
5005  /* exit if largest coefficient does not belong to binary variable */
5006  if ( ! SCIPvarIsBinary(vars[maxabsvalidx]) )
5007  return SCIP_OKAY;
5008 
5009  /* exit if the second largest coefficient is as large as largest */
5010  if ( SCIPisEQ(scip, secabsval, maxabsval) )
5011  return SCIP_OKAY;
5012 
5013  /* cannot upgrade if all activities are infinity */
5014  if ( SCIPisInfinity(scip, -minactivity) && SCIPisInfinity(scip, maxactivity) )
5015  return SCIP_OKAY;
5016 
5017  /* check each variable as indicator variable */
5018  for (j = 0; j < nvars; ++j)
5019  {
5020  SCIP_VAR** indconsvars;
5021  SCIP_Real* indconsvals;
5022  SCIP_Bool upgdlhs = FALSE;
5023  SCIP_Bool upgdrhs = FALSE;
5024  SCIP_Bool indneglhs = FALSE;
5025  SCIP_Bool indnegrhs = FALSE;
5026  SCIP_VAR* indvar;
5027  SCIP_Real indval;
5028  int l;
5029 
5030  indvar = vars[j];
5031  indval = vals[j];
5032  assert( ! SCIPisZero(scip, indval) );
5033 
5034  if ( ! SCIPvarIsBinary(indvar) )
5035  continue;
5036 
5037  /* check for upgrading of lhs */
5038  if ( ! SCIPisInfinity(scip, -minactivity) && ! SCIPisInfinity(scip, -lhs) )
5039  {
5040  /* upgrading is possible with binary variable */
5041  if ( SCIPisGE(scip, minactivity, lhs) )
5042  upgdlhs = TRUE;
5043 
5044  /* upgrading is possible with negated binary variable */
5045  if ( SCIPisGE(scip, minactivity + indval, lhs) )
5046  {
5047  upgdlhs = TRUE;
5048  indneglhs = TRUE;
5049  }
5050  }
5051 
5052  /* check for upgrading of rhs */
5053  if ( ! SCIPisInfinity(scip, maxactivity) && ! SCIPisInfinity(scip, rhs) )
5054  {
5055  /* upgrading is possible with binary variable */
5056  if ( SCIPisLE(scip, maxactivity, rhs) )
5057  upgdrhs = TRUE;
5058 
5059  /* upgrading is possible with negated binary variable */
5060  if ( SCIPisLE(scip, maxactivity + indval, rhs) )
5061  {
5062  upgdrhs = TRUE;
5063  indnegrhs = TRUE;
5064  }
5065  }
5066 
5067  /* upgrade constraint */
5068  if ( upgdlhs || upgdrhs )
5069  {
5070  SCIP_VAR* indvar2;
5071  SCIP_Real bnd;
5072  int cnt = 0;
5073 
5074  assert( ! upgdlhs || ! upgdrhs ); /* cannot treat ranged rows */
5075  SCIPdebugMsg(scip, "upgrading constraint <%s> to an indicator constraint.\n", SCIPconsGetName(cons));
5076 
5077  SCIP_CALL( SCIPallocBufferArray(scip, &indconsvars, nvars - 1) );
5078  SCIP_CALL( SCIPallocBufferArray(scip, &indconsvals, nvars - 1) );
5079 
5080  /* create constraint */
5081  for (l = 0; l < nvars; ++l)
5082  {
5083  if ( vars[l] == indvar )
5084  continue;
5085  indconsvars[cnt] = vars[l];
5086  if ( upgdlhs )
5087  indconsvals[cnt] = -vals[l];
5088  else
5089  indconsvals[cnt] = vals[l];
5090  ++cnt;
5091  }
5092 
5093  if ( indneglhs || indnegrhs )
5094  {
5095  SCIP_CALL( SCIPgetNegatedVar(scip, indvar, &indvar2) );
5096  }
5097  else
5098  indvar2 = indvar;
5099 
5100  if ( upgdlhs )
5101  {
5102  bnd = -lhs;
5103  if ( ! indneglhs )
5104  bnd -= indval;
5105  SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
5108  }
5109  else
5110  {
5111  bnd = rhs;
5112  if ( ! indnegrhs )
5113  bnd -= indval;
5114  SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
5117  }
5118 
5119 #ifdef SCIP_DEBUG
5120  SCIPinfoMessage(scip, NULL, "upgrade: \n");
5121  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
5122  SCIPinfoMessage(scip, NULL, "\n");
5123  SCIP_CALL( SCIPprintCons(scip, *upgdcons, NULL) );
5124  SCIPinfoMessage(scip, NULL, "\n");
5126  SCIPinfoMessage(scip, NULL, " (minact: %f, maxact: %f)\n", minactivity, maxactivity);
5127 #endif
5128 
5129  SCIPfreeBufferArray(scip, &indconsvars);
5130  SCIPfreeBufferArray(scip, &indconsvals);
5131 
5132  return SCIP_OKAY;
5133  }
5134  }
5135 
5136  return SCIP_OKAY;
5137 }
5138 
5139 
5140 /* ---------------------------- constraint handler callback methods ----------------------*/
5141 
5142 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
5143 static
5144 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyIndicator)
5145 { /*lint --e{715}*/
5146  assert( scip != NULL );
5147  assert( conshdlr != NULL );
5148  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5149  assert( valid != NULL );
5150 
5151  /* call inclusion method of constraint handler */
5153 
5154  *valid = TRUE;
5155 
5156  return SCIP_OKAY;
5157 }
5158 
5159 
5160 /** initialization method of constraint handler (called after problem was transformed) */
5161 static
5162 SCIP_DECL_CONSINIT(consInitIndicator)
5163 { /*lint --e{715}*/
5164  SCIP_CONSHDLRDATA* conshdlrdata;
5165 
5166  assert( scip != NULL );
5167  assert( conshdlr != NULL );
5168  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5169 
5170  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5171  assert( conshdlrdata != NULL );
5172 
5173  initConshdlrData(scip, conshdlrdata);
5174 
5175  /* find trysol heuristic */
5176  if ( conshdlrdata->trysolutions && conshdlrdata->heurtrysol == NULL )
5177  {
5178  conshdlrdata->heurtrysol = SCIPfindHeur(scip, "trysol");
5179  }
5180 
5181  return SCIP_OKAY;
5182 }
5183 
5184 
5185 /** deinitialization method of constraint handler (called before transformed problem is freed) */
5186 static
5187 SCIP_DECL_CONSEXIT(consExitIndicator)
5188 { /*lint --e{715}*/
5189  SCIP_CONSHDLRDATA* conshdlrdata;
5190 
5191  assert( scip != NULL );
5192  assert( conshdlr != NULL );
5193  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5194 
5195  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5196 
5197  if ( conshdlrdata->binvarhash != NULL )
5198  SCIPhashmapFree(&conshdlrdata->binvarhash);
5199 
5200  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
5201  conshdlrdata->maxaddlincons = 0;
5202  conshdlrdata->naddlincons = 0;
5203  conshdlrdata->nrows = 0;
5204 
5205  return SCIP_OKAY;
5206 }
5207 
5208 
5209 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
5210 static
5211 SCIP_DECL_CONSFREE(consFreeIndicator)
5213  SCIP_CONSHDLRDATA* conshdlrdata;
5214 
5215  assert( scip != NULL );
5216  assert( conshdlr != NULL );
5217  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5218 
5219  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5220  assert( conshdlrdata != NULL );
5221  assert( conshdlrdata->altlp == NULL );
5222  assert( conshdlrdata->varhash == NULL );
5223  assert( conshdlrdata->lbhash == NULL );
5224  assert( conshdlrdata->ubhash == NULL );
5225  assert( conshdlrdata->slackhash == NULL );
5226 
5227  if ( conshdlrdata->maxaddlincons > 0 )
5228  {
5229  /* if problem was not yet transformed the array may need to be freed, because we did not call the EXIT callback */
5230  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
5231  }
5232  assert( conshdlrdata->addlincons == NULL );
5233  conshdlrdata->naddlincons = 0;
5234  conshdlrdata->maxaddlincons = 0;
5235 
5236  SCIPfreeBlockMemory(scip, &conshdlrdata);
5237 
5238  return SCIP_OKAY;
5239 }
5240 
5241 
5242 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
5243 static
5244 SCIP_DECL_CONSINITSOL(consInitsolIndicator)
5246  SCIP_CONSHDLRDATA* conshdlrdata;
5247  int c;
5248 
5249  assert( scip != NULL );
5250  assert( conshdlr != NULL );
5251  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5252 
5255  return SCIP_OKAY;
5256 
5257  SCIPdebugMsg(scip, "Initsol for indicator constraints.\n");
5258 
5259  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5260  assert( conshdlrdata != NULL );
5261  assert( conshdlrdata->slackhash == NULL );
5262 
5263  SCIP_CALL( SCIPgetCharParam(scip, "separating/efficacynorm", &conshdlrdata->normtype) );
5264 
5265  if ( conshdlrdata->sepaalternativelp )
5266  {
5267  /* generate hash for storing all slack variables (size is just a guess) */
5268  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->slackhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
5269  assert( conshdlrdata->slackhash != NULL );
5270 
5271  /* first initialize slack hash */
5272  for (c = 0; c < nconss; ++c)
5273  {
5274  SCIP_CONSDATA* consdata;
5275 
5276  assert( conss != NULL );
5277  assert( conss[c] != NULL );
5278  assert( SCIPconsIsTransformed(conss[c]) );
5279 
5280  consdata = SCIPconsGetData(conss[c]);
5281  assert( consdata != NULL );
5282 
5283  assert( consdata->slackvar != NULL );
5284 
5285  /* insert slack variable into hash */
5286  SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->slackhash, consdata->slackvar, INT_MAX) );
5287  assert( SCIPhashmapExists(conshdlrdata->slackhash, consdata->slackvar) );
5288  ++conshdlrdata->nslackvars;
5289  }
5290 
5291  if ( conshdlrdata->genlogicor )
5292  {
5293  SCIP_CONSHDLR* logicorconshdlr;
5294  int logicorsepafreq;
5295  int sepafreq;
5296 
5297  /* If we generate logicor constraints, but the separation frequency is not 1, output warning */
5298  logicorconshdlr = SCIPfindConshdlr(scip, "logicor");
5299  if ( logicorconshdlr == NULL )
5300  {
5301  SCIPerrorMessage("Logicor constraint handler not included, cannot generate constraints.\n");
5302  return SCIP_ERROR;
5303  }
5304  logicorsepafreq = SCIPconshdlrGetSepaFreq(logicorconshdlr);
5305  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
5306  if ( (sepafreq != -1 || conshdlrdata->enforcecuts) && logicorsepafreq != 1 )
5307  {
5308  SCIPwarningMessage(scip, "For better performance set parameter 'constraints/logicor/sepafreq' to 1 if 'constraints/included/genlogicor' is true.\n");
5309  }
5310  }
5311  }
5312 
5313  /* check each constraint */
5314  conshdlrdata->objothervarsonly = TRUE;
5315  for (c = 0; c < nconss; ++c)
5316  {
5317  SCIP_CONSDATA* consdata;
5318 
5319  assert( conss != NULL );
5320  assert( conss[c] != NULL );
5321  assert( SCIPconsIsTransformed(conss[c]) );
5322 
5323  consdata = SCIPconsGetData(conss[c]);
5324  assert( consdata != NULL );
5325  assert( consdata->binvar != NULL );
5326  assert( consdata->slackvar != NULL );
5327 
5328  /* Presolving might replace a slack variable by an active variable. Thus, the objective of a slack variables might
5329  * be nonzero. However, we do not need to check slack variables here. */
5330  if ( ! SCIPisZero(scip, varGetObjDelta(consdata->binvar)) )
5331  conshdlrdata->objothervarsonly = FALSE;
5332 
5333  /* deactivate */
5334  if ( ! consdata->linconsactive )
5335  {
5336  SCIP_CALL( SCIPdisableCons(scip, consdata->lincons) );
5337  }
5338  else
5339  {
5340  /* add constraint to alternative LP if not already done */
5341  if ( conshdlrdata->sepaalternativelp && consdata->colindex < 0 )
5342  {
5343  SCIP_CALL( addAltLPConstraint(scip, conshdlr, consdata->lincons, consdata->slackvar, 1.0, &consdata->colindex) );
5344  SCIPdebugMsg(scip, "Added column for <%s> to alternative LP with column index %d.\n", SCIPconsGetName(conss[c]),consdata->colindex);
5345 #ifdef SCIP_OUTPUT
5346  SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
5347  SCIPinfoMessage(scip, NULL, ";\n");
5348 #endif
5349  }
5350  }
5351 
5352  /* add nlrow representation to NLP, if NLP had been constructed
5353  *
5354  * Note, that we did not tell SCIP in exitpre that we have something to add to the NLP, thus
5355  * indicators are only available in the NLP for MINLPs, but not for MIPs with indicators.
5356  */
5357  if ( SCIPisNLPConstructed(scip) && SCIPconsIsChecked(conss[c]) )
5358  {
5359  /* create nonlinear row binary variable * slack variable = 0 */
5360  SCIP_NLROW* nlrow;
5361  SCIP_EXPR* quadexpr;
5362  SCIP_EXPR* varexprs[2];
5363 
5364  SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[0], consdata->binvar, NULL, NULL) );
5365  SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[1], consdata->slackvar, NULL, NULL) );
5366  SCIP_CALL( SCIPcreateExprProduct(scip, &quadexpr, 2, varexprs, 1.0, NULL, NULL) );
5367 
5368  SCIP_CALL( SCIPcreateNlRow(scip, &nlrow, SCIPconsGetName(conss[c]), 0.0, 0, NULL, NULL, quadexpr, 0.0, 0.0, SCIP_EXPRCURV_UNKNOWN) );
5369 
5370  SCIP_CALL( SCIPreleaseExpr(scip, &quadexpr) );
5371  SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[1]) );
5372  SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[0]) );
5373 
5374  /* add row to NLP and forget about it */
5375  SCIP_CALL( SCIPaddNlRow(scip, nlrow) );
5376  SCIP_CALL( SCIPreleaseNlRow(scip, &nlrow) );
5377  }
5378  }
5379 
5380  SCIPdebugMsg(scip, "Initialized %d indicator constraints.\n", nconss);
5381 
5382  /* check additional constraints */
5383  if ( conshdlrdata->sepaalternativelp )
5384  {
5385  SCIP_CONS* cons;
5386  int colindex;
5387  int cnt = 0;
5388 
5389  /* add stored linear constraints if they exist */
5390  if ( conshdlrdata->naddlincons > 0 )
5391  {
5392  for (c = 0; c < conshdlrdata->naddlincons; ++c)
5393  {
5394  cons = conshdlrdata->addlincons[c];
5395 
5396  /* get transformed constraint - since it is needed only here, we do not store the information */
5397  if ( ! SCIPconsIsTransformed(cons) )
5398  {
5399  SCIP_CALL( SCIPgetTransformedCons(scip, conshdlrdata->addlincons[c], &cons) );
5400 
5401  /* @todo check when exactly the transformed constraint does not exist - SCIPisActive() does not suffice */
5402  if ( cons == NULL )
5403  continue;
5404  }
5405  SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
5406  ++cnt;
5407 
5408 #ifdef SCIP_OUTPUT
5409  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
5410  SCIPinfoMessage(scip, NULL, ";\n");
5411 #endif
5412  }
5413  SCIPdebugMsg(scip, "Added %d additional columns to alternative LP.\n", cnt);
5414  }
5415  else
5416  {
5417  /* if no stored linear constraints are available, possibly collect other linear constraints; we only use linear
5418  * constraints, since most other constraints involve integral variables, and in this context we will likely
5419  * benefit much more from continuous variables. */
5420  if ( conshdlrdata->useotherconss )
5421  {
5422  const char* conshdlrname;
5423  SCIP_CONS** allconss;
5424  int nallconss;
5425 
5426  nallconss = SCIPgetNConss(scip);
5427  allconss = SCIPgetConss(scip);
5428 
5429  /* loop through all constraints */
5430  for (c = 0; c < nallconss; ++c)
5431  {
5432  /* get constraint */
5433  cons = allconss[c];
5434  assert( cons != NULL );
5435  assert( SCIPconsIsTransformed(cons) );
5436 
5437  /* get constraint handler name */
5438  conshdlrname = SCIPconshdlrGetName(SCIPconsGetHdlr(cons));
5439 
5440  /* check type of constraint (only take modifiable linear constraints) */
5441  if ( strcmp(conshdlrname, "linear") == 0 && ! SCIPconsIsModifiable(cons) )
5442  {
5443  /* avoid adding linear constraints that correspond to indicator constraints */
5444  if ( strncmp(SCIPconsGetName(cons), "indlin", 6) != 0 )
5445  {
5446  SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
5447  SCIPdebugMsg(scip, "Added column for linear constraint <%s> to alternative LP with column index %d.\n", SCIPconsGetName(cons), colindex);
5448  ++cnt;
5449  }
5450  }
5451  }
5452  SCIPdebugMsg(scip, "Added %d additional columns from linear constraints to alternative LP.\n", cnt);
5453  }
5454  }
5455  }
5456 
5457  /* initialize event handler if restart should be forced */
5458  if ( conshdlrdata->forcerestart )
5459  {
5460  SCIP_Bool* covered;
5461  SCIP_VAR** vars;
5462  int nvars;
5463  int j;
5464 
5465  assert( conshdlrdata->eventhdlrrestart != NULL );
5466 
5467  /* store number of initial constraints */
5468  conshdlrdata->ninitconss = SCIPconshdlrGetNActiveConss(conshdlr);
5469 
5470  /* reset number of fixed binary variables */
5471  conshdlrdata->nbinvarszero = 0;
5472 
5473  /* loop through variables */
5474  nvars = SCIPgetNVars(scip);
5475  vars = SCIPgetVars(scip);
5476 
5477  conshdlrdata->objindicatoronly = FALSE;
5478  conshdlrdata->minabsobj = SCIP_REAL_MAX;
5479 
5480  /* unmark all variables */
5481  SCIP_CALL( SCIPallocBufferArray(scip, &covered, nvars) );
5482  for (j = 0; j < nvars; ++j)
5483  covered[j] = FALSE;
5484 
5485  /* mark indicator variables */
5486  for (c = 0; c < nconss; ++c)
5487  {
5488  SCIP_CONSDATA* consdata;
5489  int probindex;
5490 
5491  assert( conss != NULL );
5492  assert( conss[c] != NULL );
5493 
5494  /* avoid non-active indicator constraints */
5495  if ( ! SCIPconsIsActive(conss[c]) )
5496  continue;
5497 
5498  consdata = SCIPconsGetData(conss[c]);
5499  assert( consdata != NULL );
5500  assert( consdata->binvar != NULL );
5501 
5502  if ( SCIPvarIsNegated(consdata->binvar) )
5503  {
5504  assert( SCIPvarGetNegatedVar(consdata->binvar) != NULL );
5505  probindex = SCIPvarGetProbindex(SCIPvarGetNegatedVar(consdata->binvar));
5506  }
5507  else
5508  probindex = SCIPvarGetProbindex(consdata->binvar);
5509 
5510  /* if presolving detected infeasibility it might be that the binary variables are not active */
5511  if ( probindex < 0 )
5512  continue;
5513 
5514  assert( 0 <= probindex && probindex < nvars );
5515  covered[probindex] = TRUE;
5516  }
5517 
5518  /* check all variables */
5519  for (j = 0; j < nvars; ++j)
5520  {
5521  SCIP_Real obj;
5522 
5523  obj = SCIPvarGetObj(vars[j]);
5524  if ( ! SCIPisZero(scip, obj) )
5525  {
5526  if ( ! covered[j] )
5527  break;
5528  if ( ! SCIPisIntegral(scip, obj) )
5529  break;
5530  if ( REALABS(obj) < conshdlrdata->minabsobj )
5531  conshdlrdata->minabsobj = REALABS(obj);
5532  }
5533  }
5534 
5535  /* if all variables have integral objective and only indicator variables have nonzero objective */
5536  if ( j >= nvars )
5537  {
5538  /* if there are variables with nonzero objective */
5539  if ( conshdlrdata->minabsobj < SCIP_REAL_MAX )
5540  {
5541  assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
5542  assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0) );
5543 
5544  conshdlrdata->objindicatoronly = TRUE;
5545 
5546  assert( conshdlrdata->eventhdlrrestart != NULL );
5547  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
5548  }
5549  }
5550 
5551  SCIPfreeBufferArray(scip, &covered);
5552  }
5553 
5554  return SCIP_OKAY;
5555 }
5556 
5557 
5558 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
5559 static
5560 SCIP_DECL_CONSEXITSOL(consExitsolIndicator)
5561 { /*lint --e{715}*/
5562  SCIP_CONSHDLRDATA* conshdlrdata;
5563  int c;
5564 
5565  assert( scip != NULL );
5566  assert( conshdlr != NULL );
5567  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5568 
5569  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5570  assert( conshdlrdata != NULL );
5571 
5572  if ( conshdlrdata->sepaalternativelp )
5573  {
5574  if ( conshdlrdata->slackhash != NULL )
5575  {
5576 #ifdef SCIP_DEBUG
5577  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator slack hash:\n");
5578  SCIPhashmapPrintStatistics(conshdlrdata->slackhash, SCIPgetMessagehdlr(scip));
5579 #endif
5580  SCIPhashmapFree(&conshdlrdata->slackhash);
5581  }
5582 
5583  if ( conshdlrdata->altlp != NULL )
5584  {
5585  assert( conshdlrdata->varhash != NULL );
5586  assert( conshdlrdata->lbhash != NULL );
5587  assert( conshdlrdata->ubhash != NULL );
5588 
5589 #ifdef SCIP_DEBUG
5590  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator var hash:\n");
5591  SCIPhashmapPrintStatistics(conshdlrdata->varhash, SCIPgetMessagehdlr(scip));
5592  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator lower bound hash:\n");
5593  SCIPhashmapPrintStatistics(conshdlrdata->lbhash, SCIPgetMessagehdlr(scip));
5594  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator upper bound hash:\n");
5595  SCIPhashmapPrintStatistics(conshdlrdata->ubhash, SCIPgetMessagehdlr(scip));
5596 #endif
5597 
5598  SCIPhashmapFree(&conshdlrdata->varhash);
5599  SCIPhashmapFree(&conshdlrdata->lbhash);
5600  SCIPhashmapFree(&conshdlrdata->ubhash);
5601 
5602  SCIP_CALL( SCIPlpiFree(&conshdlrdata->altlp) );
5603 
5604  /* save the information that the columns have been deleted */
5605  for (c = 0; c < nconss; ++c)
5606  {
5607  SCIP_CONSDATA* consdata;
5608 
5609  assert( conss != NULL );
5610  assert( conss[c] != NULL );
5611 
5612  consdata = SCIPconsGetData(conss[c]);
5613  assert( consdata != NULL );
5614  consdata->colindex = -1;
5615  }
5616  }
5617  }
5618  else
5619  {
5620  assert( conshdlrdata->slackhash == NULL );
5621  assert( conshdlrdata->varhash == NULL );
5622  assert( conshdlrdata->lbhash == NULL );
5623  assert( conshdlrdata->ubhash == NULL );
5624  }
5625 
5626  return SCIP_OKAY;
5627 }
5628 
5629 
5630 /** frees specific constraint data */
5631 static
5632 SCIP_DECL_CONSDELETE(consDeleteIndicator)
5634  assert( scip != NULL );
5635  assert( conshdlr != NULL );
5636  assert( cons != NULL );
5637  assert( consdata != NULL );
5638  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5639 
5640 #ifdef SCIP_MORE_DEBUG
5641  SCIPdebugMsg(scip, "Deleting indicator constraint <%s>.\n", SCIPconsGetName(cons) );
5642 #endif
5643 
5644  /* drop events on transformed variables */
5645  if ( SCIPconsIsTransformed(cons) )
5646  {
5647  SCIP_CONSHDLRDATA* conshdlrdata;
5648 
5649  /* get constraint handler data */
5650  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5651  assert( conshdlrdata != NULL );
5652 
5653  if ( conshdlrdata->sepaalternativelp )
5654  {
5655  SCIP_CALL( deleteAltLPConstraint(scip, conshdlr, cons) );
5656  }
5657 
5658  assert( (*consdata)->slackvar != NULL );
5659  assert( (*consdata)->binvar != NULL );
5660 
5661  /* free events only in correct stages */
5663  {
5664  if ( (*consdata)->linconsactive )
5665  {
5666  assert( conshdlrdata->eventhdlrbound != NULL );
5667  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
5668  (SCIP_EVENTDATA*)*consdata, -1) );
5669  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
5670  (SCIP_EVENTDATA*)*consdata, -1) );
5671  }
5672  if ( conshdlrdata->forcerestart )
5673  {
5674  assert( conshdlrdata->eventhdlrrestart != NULL );
5675  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
5676  (SCIP_EVENTDATA*) conshdlrdata, -1) );
5677  }
5678  }
5679  }
5680 
5681  /* Can there be cases where lincons is NULL, e.g., if presolve found the problem infeasible? */
5682  assert( (*consdata)->lincons != NULL );
5683 
5684  /* release linear constraint and slack variable */
5685  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->slackvar) );
5686  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->lincons) );
5687 
5688  SCIPfreeBlockMemory(scip, consdata);
5689 
5690  return SCIP_OKAY;
5691 }
5692 
5693 
5694 /** transforms constraint data into data belonging to the transformed problem */
5695 static
5696 SCIP_DECL_CONSTRANS(consTransIndicator)
5698  SCIP_CONSDATA* consdata;
5699  SCIP_CONSHDLRDATA* conshdlrdata;
5700  SCIP_CONSDATA* sourcedata;
5701  char s[SCIP_MAXSTRLEN];
5702 
5703  assert( scip != NULL );
5704  assert( conshdlr != NULL );
5705  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5706  assert( sourcecons != NULL );
5707  assert( targetcons != NULL );
5708 
5709  /* get constraint handler data */
5710  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5711  assert( conshdlrdata != NULL );
5712  assert( conshdlrdata->eventhdlrbound != NULL );
5713 
5714 #ifdef SCIP_MORE_DEBUG
5715  SCIPdebugMsg(scip, "Transforming indicator constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
5716 #endif
5717 
5718  /* get data of original constraint */
5719  sourcedata = SCIPconsGetData(sourcecons);
5720  assert( sourcedata != NULL );
5721  assert( sourcedata->binvar != NULL );
5722 
5723  /* check for slackvar */
5724  if ( sourcedata->slackvar == NULL )
5725  {
5726  SCIPerrorMessage("The indicator constraint <%s> needs a slack variable.\n", SCIPconsGetName(sourcecons));
5727  return SCIP_INVALIDDATA;
5728  }
5729 
5730  /* check for linear constraint */
5731  if ( sourcedata->lincons == NULL )
5732  {
5733  SCIPerrorMessage("The indicator constraint <%s> needs a linear constraint variable.\n", SCIPconsGetName(sourcecons));
5734  return SCIP_INVALIDDATA;
5735  }
5736  assert( sourcedata->lincons != NULL );
5737  assert( sourcedata->slackvar != NULL );
5738 
5739  /* create constraint data */
5740  consdata = NULL;
5741  /* Note that the constraint has activeone = TRUE, since the binary variable has been negated already if needed. */
5742  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, SCIPconsGetName(sourcecons), &consdata, conshdlrdata->eventhdlrbound,
5743  conshdlrdata->eventhdlrrestart, sourcedata->binvar, TRUE, sourcedata->lessthanineq, sourcedata->slackvar, sourcedata->lincons, sourcedata->linconsactive) );
5744  consdata->activeone = sourcedata->activeone;
5745  assert( consdata != NULL );
5746 
5747  /* capture slack variable and linear constraint */
5748  SCIP_CALL( SCIPcaptureVar(scip, consdata->slackvar) );
5749  SCIP_CALL( SCIPcaptureCons(scip, consdata->lincons) );
5750 
5751  /* create transformed constraint with the same flags */
5752  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));