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-2014 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 email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 /* #define SCIP_DEBUG */
16 /* #define SCIP_OUTPUT */
17 /* #define SCIP_ENABLE_IISCHECK */
18 
19 /**@file cons_indicator.c
20  * @brief constraint handler for indicator constraints
21  * @author Marc Pfetsch
22  *
23  * An indicator constraint is given by a binary variable \f$y\f$ and an inequality \f$ax \leq
24  * b\f$. It states that if \f$y = 1\f$ then \f$ax \leq b\f$ holds.
25  *
26  * This constraint is handled by adding a slack variable \f$s:\; ax - s \leq b\f$ with \f$s \geq
27  * 0\f$. The constraint is enforced by fixing \f$s\f$ to 0 if \f$y = 1\f$.
28  *
29  * @note The constraint only implements an implication not an equivalence, i.e., it does not ensure
30  * that \f$y = 1\f$ if \f$ax \leq b\f$ or equivalently if \f$s = 0\f$ holds.
31  *
32  * This constraint is equivalent to a linear constraint \f$ax - s \leq b\f$ and an SOS1 constraint on
33  * \f$y\f$ and \f$s\f$ (at most one should be nonzero). In the indicator context we can, however,
34  * separate more inequalities.
35  *
36  * The name indicator apparently comes from ILOG CPLEX.
37  *
38  *
39  * @section SEPARATION Separation Methods
40  *
41  * We now explain the handling of indicator constraints in more detail. The indicator constraint
42  * handler adds an inequality for each indicator constraint. We assume that this system (with added
43  * slack variables) is \f$ Ax - s \leq b \f$, where \f$ x \f$ are the original variables and \f$ s
44  * \f$ are the slack variables added by the indicator constraint. Variables \f$ y \f$ are the binary
45  * variables corresponding to the indicator constraints.
46  *
47  * @note In the implementation, we assume that bounds on the original variables \f$x\f$ cannot be
48  * influenced by the indicator constraint. If it should be possible to relax these constraints as
49  * well, then these constraints have to be added as indicator constraints.
50  *
51  * We separate inequalities by using the so-called alternative polyhedron.
52  *
53  *
54  * @section ALTERNATIVEPOLYHEDRON Separation via the Alternative Polyhedron
55  *
56  * We now describe the separation method of the first method in more detail.
57  *
58  * Consider the LP-relaxation of the current subproblem:
59  * \f[
60  * \begin{array}{ll}
61  * min & c^T x + d^T z\\
62  * & A x - s \leq b, \\
63  * & D x + C z \leq f, \\
64  * & l \leq x \leq u, \\
65  * & u \leq z \leq v, \\
66  * & 0 \leq s.
67  * \end{array}
68  * \f]
69  * As above \f$Ax - s \leq b\f$ contains all inequalities corresponding to indicator constraints,
70  * while the system \f$Dx + Cy \leq f\f$ contains all other inequalities (which are ignored in the
71  * following). Similarly, variables \f$z\f$ not appearing in indicator constraints are
72  * ignored. Bounds for the variables \f$x_j\f$ can be given, in particular, variables can be
73  * fixed. Note that \f$s \leq 0\f$ renders the system infeasible.
74  *
75  * To generate cuts, we construct the so-called @a alternative @a polyhedron:
76  * \f[
77  * \begin{array}{ll}
78  * P = \{ (w,r,t) : & A^T w - r + t = 0,\\
79  * & b^T w - l^T r + u^T t = -1,\\
80  * & w, r, t \geq 0 \}.
81  * \end{array}
82  * \f]
83  * Here, \f$r\f$ and \f$t\f$ correspond to the lower and upper bounds on \f$x\f$, respectively.
84  *
85  * It turns out that the vertices of \f$P\f$ correspond to minimal infeasible subsystems of \f$A x
86  * \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
87  * \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:
88  * \f[
89  * \sum_{i \in I} y_i \leq |I| - 1.
90  * \f]
91  *
92  *
93  * @subsection DETAIL Separation heuristic
94  *
95  * We separate the above inequalities by a heuristic described in
96  *
97  * Branch-And-Cut for the Maximum Feasible Subsystem Problem,@n
98  * Marc Pfetsch, SIAM Journal on Optimization 19, No.1, 21-38 (2008)
99  *
100  * The first step in the separation heuristic is to apply the transformation \f$\bar{y} = 1 - y\f$, which
101  * transforms the above inequality into the constraint
102  * \f[
103  * \sum_{i \in I} \bar{y}_i \geq 1,
104  * \f]
105  * that is, it is a set covering constraint on the negated variables.
106  *
107  * The basic idea is to use the current solution to the LP relaxation and use it as the objective,
108  * when optimizing of the alternative polyhedron. Since any vertex corresponds to such an
109  * inequality, we can check whether it is violated. To enlarge the chance that we find a @em
110  * violated inequality, we perform a fixing procedure, in which the variable corresponding to an
111  * arbitrary element of the last IIS \f$I\f$ is fixed to zero, i.e., cannot be used in the next
112  * IISs. This is repeated until the corresponding alternative polyhedron is infeasible, i.e., we
113  * have obtained an IIS-cover. For more details see the paper above.
114  *
115  *
116  * @subsection PREPROC Preprocessing
117  *
118  * Since each indicator constraint adds a linear constraint to the formulation, preprocessing of the
119  * linear constraints change the above approach as follows.
120  *
121  * The system as present in the formulation is the following (ignoring variables that are not
122  * contained in indicator constraints and the objective function):
123  * \f[
124  * \begin{array}{ll}
125  * & A x - s \leq b, \\
126  * & l \leq x \leq u, \\
127  * & s \leq 0.
128  * \end{array}
129  * \f]
130  * Note again that the requirement \f$s \leq 0\f$ leads to an infeasible system. Consider now the
131  * preprocessing of the linear constraint (aggregation, bound strengthening, etc.) and assume that
132  * this changes the above system to the following:
133  * \f[
134  * \begin{array}{ll}
135  * & \tilde{A} x - \tilde{B} s \leq \tilde{b}, \\
136  * & \tilde{l} \leq x \leq \tilde{u}, \\
137  * & s \leq 0. \\
138  * \end{array}
139  * \f]
140  * Note that we forbid multi-aggregation of the \f$s\f$ variables in order to be able to change their
141  * bounds in propagation/branching. The corresponding alternative system is the following:
142  * \f[
143  * \begin{array}{ll}
144  * & \tilde{A}^T w - r + t = 0,\\
145  * & - \tilde{B}^T w + v = 0,\\
146  * & b^T w - l^T r + u^T t = -1,\\
147  * & w, v, r, t \geq 0
148  * \end{array}
149  * \qquad \Leftrightarrow \qquad
150  * \begin{array}{ll}
151  * & \tilde{A}^T w - r + t = 0,\\
152  * & \tilde{B}^T w \geq 0,\\
153  * & b^T w - l^T r + u^T t = -1,\\
154  * & w, r, t \geq 0,
155  * \end{array}
156  * \f]
157  * where the second form arises by substituting \f$v \geq 0\f$. A closer look at this system reveals
158  * that it is not larger than the original one:
159  *
160  * - (Multi-)Aggregation of variables \f$x\f$ will remove these variables from the formulation, such that
161  * the corresponding column of \f$\tilde{A}\f$ (row of \f$\tilde{A}^T\f$) will be zero.
162  *
163  * - The rows of \f$\tilde{B}^T\f$ are not unit vectors, i.e., do not correspond to redundant
164  * nonnegativity constraints, only if the corresponding slack variables appear in an aggregation.
165  *
166  * Taken together, these two observations yield the conclusion that the new system is roughly as
167  * large as the original one.
168  *
169  * @note Because of possible (multi-)aggregation it might happen that the linear constraint
170  * corresponding to an indicator constraint becomes redundant and is deleted. From this we cannot
171  * conclude that the indicator constraint is redundant as well (i.e. always fulfilled), because the
172  * corresponding slack variable is still present and its setting to 0 might influence other
173  * (linear) constraints. Thus, we have to rely on the dual presolving of the linear constraints to
174  * detect this case: If the linear constraint is really redundant, i.e., is always fulfilled, it is
175  * deleted and the slack variable can be fixed to 0. In this case, the indicator constraint can be
176  * deleted as well.
177  *
178  * @todo Accept arbitrary ranged linear constraints as input (in particular: equations). Internally
179  * create two indicator constraints or correct alternative polyhedron accordingly (need to split the
180  * variables there, but not in original problem).
181  *
182  * @todo Treat variable upper bounds in a special way: Do not create the artificial slack variable,
183  * but directly enforce the propagations etc.
184  *
185  * @todo Turn off separation if the alternative polyhedron is infeasible and updateBounds is false.
186  *
187  * @todo Improve parsing of indicator constraint in CIP-format. Currently, we have to rely on a particular name, i.e.,
188  * the slack variable has to start with "indslack" and end with the name of the corresponding linear constraint.
189  *
190  * @todo Check whether one can further use the fact that the slack variable is aggregated.
191  *
192  * @todo Check whether using an objective cutoff can be integrated into the alternative polyhedron.
193  */
194 
195 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
196 
197 #include <assert.h>
198 #include <string.h>
199 
200 #include "scip/cons_indicator.h"
201 #include "scip/cons_linear.h"
202 #include "scip/cons_logicor.h"
203 #include "scip/cons_varbound.h"
204 #include "scip/cons_quadratic.h"
205 #include "scip/heur_trysol.h"
206 #include "scip/pub_misc.h"
207 
208 
209 /* constraint handler properties */
210 #define CONSHDLR_NAME "indicator"
211 #define CONSHDLR_DESC "indicator constraint handler"
212 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
213 #define CONSHDLR_ENFOPRIORITY -100 /**< priority of the constraint handler for constraint enforcing */
214 #define CONSHDLR_CHECKPRIORITY -1000000 /**< priority of the constraint handler for checking feasibility */
215 #define CONSHDLR_SEPAFREQ 10 /**< frequency for separating cuts; zero means to separate only in the root node */
216 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
217 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
218  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
219 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
220 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
221 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
222 #define CONSHDLR_DELAYPRESOL FALSE /**< should presolving method be delayed, if other presolvers found reductions? */
223 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
224 
225 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
226 
227 
228 /* event handler properties */
229 #define EVENTHDLR_BOUND_NAME "indicatorbound"
230 #define EVENTHDLR_BOUND_DESC "bound change event handler for indicator constraints"
231 
232 #define EVENTHDLR_RESTART_NAME "indicatorrestart"
233 #define EVENTHDLR_RESTART_DESC "force restart if absolute gap is 1"
234 
235 /* conflict handler properties */
236 #define CONFLICTHDLR_NAME "indicatorconflict"
237 #define CONFLICTHDLR_DESC "replace slack variables and generate logicor constraints"
238 #define CONFLICTHDLR_PRIORITY 200000
239 
240 /* default values for parameters */
241 #define DEFAULT_BRANCHINDICATORS FALSE /**< Branch on indicator constraints in enforcing? */
242 #define DEFAULT_GENLOGICOR FALSE /**< Generate logicor constraints instead of cuts? */
243 #define DEFAULT_ADDCOUPLING TRUE /**< Add coupling constraints if big-M is small enough? */
244 #define DEFAULT_MAXCOUPLINGVALUE 1e4 /**< maximum coefficient for binary variable in coupling constraint */
245 #define DEFAULT_ADDCOUPLINGCONS FALSE /**< Add initial coupling inequalities as linear constraints, if 'addcoupling' is true? */
246 #define DEFAULT_SEPACOUPLINGCUTS FALSE /**< Should the coupling inequalities be separated dynamically? */
247 #define DEFAULT_SEPACOUPLINGLOCAL FALSE /**< Allow to use local bounds in order to separated coupling inequalities? */
248 #define DEFAULT_SEPACOUPLINGVALUE 1e4 /**< maximum coefficient for binary variable in separated coupling constraint */
249 #define DEFAULT_SEPAALTERNATIVELP FALSE /**< Separate using the alternative LP? */
250 #define DEFAULT_TRYSOLFROMCOVER FALSE /**< Try to construct a feasible solution from a cover? */
251 #define DEFAULT_USEOTHERCONSS FALSE /**< Collect other constraints to alternative LP? */
252 #define DEFAULT_UPDATEBOUNDS FALSE /**< Update bounds of original variables for separation? */
253 #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) */
254 #define DEFAULT_MAXSEPACUTS 100 /**< maximal number of cuts separated per separation round */
255 #define DEFAULT_MAXSEPACUTSROOT 2000 /**< maximal number of cuts separated per separation round in the root node */
256 #define DEFAULT_REMOVEINDICATORS FALSE /**< Remove indicator constraint if corresponding variable bound constraint has been added? */
257 #define DEFAULT_GENERATEBILINEAR FALSE /**< Do not generate indicator constraint, but a bilinear constraint instead? */
258 #define DEFAULT_SCALESLACKVAR FALSE /**< Scale slack variable coefficient at construction time? */
259 #define DEFAULT_NOLINCONSCONT FALSE /**< decompose problem - do not generate linear constraint if all variables are continuous */
260 #define DEFAULT_TRYSOLUTIONS TRUE /**< Try to make solutions feasible by setting indicator variables? */
261 #define DEFAULT_ENFORCECUTS FALSE /**< In enforcing try to generate cuts (only if sepaalternativelp is true)? */
262 #define DEFAULT_DUALREDUCTIONS TRUE /**< Should dual reduction steps be performed? */
263 #define DEFAULT_ADDOPPOSITE FALSE /**< Add opposite inequality in nodes in which the binary variable has been fixed to 0? */
264 #define DEFAULT_CONFLICTSUPGRADE FALSE /**< Try to upgrade bounddisjunction conflicts by replacing slack variables? */
265 #define DEFAULT_FORCERESTART FALSE /**< force restart if we have a max FS instance and gap is 1? */
266 #define DEFAULT_RESTARTFRAC 0.9 /**< fraction of binary variables that need to be fixed before restart occurs (in forcerestart) */
267 
268 
269 /* other values */
270 #define OBJEPSILON 0.001 /**< value to add to objective in alt. LP if the binary variable is 1 to get small IISs */
271 #define SEPAALTTHRESHOLD 10 /**< only separate IIS cuts if the number of separated coupling cuts is less than this value */
272 
273 
274 /** constraint data for indicator constraints */
275 struct SCIP_ConsData
276 {
277  SCIP_VAR* binvar; /**< binary variable for indicator constraint */
278  SCIP_VAR* slackvar; /**< slack variable of inequality of indicator constraint */
279  SCIP_CONS* lincons; /**< linear constraint corresponding to indicator constraint */
280  int nfixednonzero; /**< number of variables among binvar and slackvar fixed to be nonzero */
281  int colindex; /**< column index in alternative LP */
282  unsigned int linconsactive:1; /**< whether linear constraint and slack variable are active */
283  unsigned int implicationadded:1; /**< whether corresponding implication has been added */
284  unsigned int slacktypechecked:1; /**< whether it has been checked to convert the slack variable to be implicit integer */
285 };
286 
287 
288 /** indicator constraint handler data */
289 struct SCIP_ConshdlrData
290 {
291  SCIP_EVENTHDLR* eventhdlrbound; /**< event handler for bound change events */
292  SCIP_EVENTHDLR* eventhdlrrestart; /**< event handler for performing restarts */
293  SCIP_Bool removable; /**< whether the separated cuts should be removable */
294  SCIP_Bool scaled; /**< if first row of alt. LP has been scaled */
295  SCIP_Bool objindicatoronly; /**< whether the objective is nonzero only for indicator variables */
296  SCIP_Real minabsobj; /**< minimum absolute nonzero objective of indicator variables */
297  SCIP_LPI* altlp; /**< alternative LP for cut separation */
298  int nrows; /**< # rows in the alt. LP corr. to original variables in linear constraints and slacks */
299  int nlbbounds; /**< # lower bounds of original variables */
300  int nubbounds; /**< # upper bounds of original variables */
301  SCIP_HASHMAP* varhash; /**< hash map from variable to row index in alternative LP */
302  SCIP_HASHMAP* lbhash; /**< hash map from variable to index of lower bound column in alternative LP */
303  SCIP_HASHMAP* ubhash; /**< hash map from variable to index of upper bound column in alternative LP */
304  SCIP_HASHMAP* slackhash; /**< hash map from slack variable to row index in alternative LP */
305  int nslackvars; /**< # slack variables */
306  int roundingrounds; /**< number of rounds in separation */
307  SCIP_Real roundingminthres; /**< minimal value for rounding in separation */
308  SCIP_Real roundingmaxthres; /**< maximal value for rounding in separation */
309  SCIP_Real roundingoffset; /**< offset for rounding in separation */
310  SCIP_Bool branchindicators; /**< Branch on indicator constraints in enforcing? */
311  SCIP_Bool genlogicor; /**< Generate logicor constraints instead of cuts? */
312  SCIP_Bool addcoupling; /**< whether the coupling inequalities should be added at the beginning */
313  SCIP_Bool addcouplingcons; /**< whether coupling inequalities should be variable bounds, if 'addcoupling' is true*/
314  SCIP_Bool sepacouplingcuts; /**< Should the coupling inequalities be separated dynamically? */
315  SCIP_Bool sepacouplinglocal; /**< Allow to use local bounds in order to separated coupling inequalities? */
316  SCIP_Bool removeindicators; /**< remove indicator constraint if corresponding variable bound constraint has been added? */
317  SCIP_Bool updatebounds; /**< whether the bounds of the original variables should be changed for separation */
318  SCIP_Bool trysolutions; /**< Try to make solutions feasible by setting indicator variables? */
319  SCIP_Bool enforcecuts; /**< in enforcing try to generate cuts (only if sepaalternativelp is true) */
320  SCIP_Bool dualreductions; /**< should dual reduction steps be performed? */
321  SCIP_Bool addopposite; /**< Add opposite inequality in nodes in which the binary variable has been fixed to 0? */
322  SCIP_Bool generatebilinear; /**< do not generate indicator constraint, but a bilinear constraint instead */
323  SCIP_Bool scaleslackvar; /**< Scale slack variable coefficient at construction time? */
324  SCIP_Bool conflictsupgrade; /**< Try to upgrade bounddisjunction conflicts by replacing slack variables? */
325  SCIP_Bool performedrestart; /**< whether a restart has been performed already */
326  int maxsepacuts; /**< maximal number of cuts separated per separation round */
327  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in root node */
328  int nbinvarszero; /**< binary variables globally fixed to zero */
329  int ninitconss; /**< initial number of indicator constraints (needed in event handlers) */
330  SCIP_Real maxcouplingvalue; /**< maximum coefficient for binary variable in initial coupling constraint */
331  SCIP_Real sepacouplingvalue; /**< maximum coefficient for binary variable in separated coupling constraint */
332  SCIP_Real maxconditionaltlp; /**< maximum estimated condition number of the alternative LP to trust its solution */
333  SCIP_Real restartfrac; /**< fraction of binary variables that need to be fixed before restart occurs (in forcerestart) */
334  SCIP_HEUR* heurtrysol; /**< trysol heuristic */
335  SCIP_Bool addedcouplingcons; /**< whether the coupling constraints have been added already */
336  SCIP_CONS** addlincons; /**< additional linear constraints that should be added to the alternative LP */
337  int naddlincons; /**< number of additional constraints */
338  int maxaddlincons; /**< maximal number of additional constraints */
339  SCIP_Bool useotherconss; /**< Collect other constraints to alternative LP? */
340  SCIP_Bool trysolfromcover; /**< Try to construct a feasible solution from a cover? */
341  /* parameters that should not be changed after problem stage: */
342  SCIP_Bool sepaalternativelp; /**< Separate using the alternative LP? */
343  SCIP_Bool sepaalternativelp_; /**< used to store the sepaalternativelp parameter */
344  SCIP_Bool nolinconscont; /**< decompose problem - do not generate linear constraint if all variables are continuous */
345  SCIP_Bool nolinconscont_; /**< used to store the nolinconscont parameter */
346  SCIP_Bool forcerestart; /**< force restart if we have a max FS instance and gap is 1? */
347  SCIP_Bool forcerestart_; /**< used to strore the forcerestart parameter */
348 };
349 
350 
351 /** indicator conflict handler data */
352 struct SCIP_ConflicthdlrData
353 {
354  SCIP_CONSHDLR* conshdlr; /**< indicator constraint handler */
355  SCIP_CONSHDLRDATA* conshdlrdata; /**< indicator constraint handler data */
356 };
357 
358 
359 /* Macro for parameters */
360 #define SCIP_CALL_PARAM(x) /*lint -e527 */ do \
361 { \
362  SCIP_RETCODE _restat_; \
363  if ( (_restat_ = (x)) != SCIP_OKAY && (_restat_ != SCIP_PARAMETERUNKNOWN) ) \
364  { \
365  SCIPerrorMessage("[%s:%d] Error <%d> in function call\n", __FILE__, __LINE__, _restat_); \
366  SCIPABORT(); \
367  return _restat_; \
368  } \
369 } \
370 while ( FALSE )
371 
372 
373 /* ---------------- Callback methods of event handlers ---------------- */
374 
375 /* exec the event handler for getting variable bound changes
376  *
377  * We update the number of variables fixed to be nonzero
378  */
379 static
380 SCIP_DECL_EVENTEXEC(eventExecIndicatorBound)
381 {
382  SCIP_EVENTTYPE eventtype;
383  SCIP_CONSDATA* consdata;
384  SCIP_Real oldbound;
385  SCIP_Real newbound;
386 
387  assert( eventhdlr != NULL );
388  assert( eventdata != NULL );
389  assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_BOUND_NAME) == 0 );
390  assert( event != NULL );
391 
392  consdata = (SCIP_CONSDATA*)eventdata;
393  assert( consdata != NULL );
394  assert( 0 <= consdata->nfixednonzero && consdata->nfixednonzero <= 2 );
395  assert( consdata->linconsactive );
396 
397  oldbound = SCIPeventGetOldbound(event);
398  newbound = SCIPeventGetNewbound(event);
399 
400  eventtype = SCIPeventGetType(event);
401  switch ( eventtype )
402  {
404  /* if variable is now fixed to be positive */
405  if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
406  ++(consdata->nfixednonzero);
407  SCIPdebugMessage("changed lower bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
408  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
409  break;
411  /* if variable is now fixed to be negative */
412  if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
413  ++(consdata->nfixednonzero);
414  SCIPdebugMessage("changed upper bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
415  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
416  break;
418  /* if variable is not fixed to be positive anymore */
419  if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
420  --(consdata->nfixednonzero);
421  SCIPdebugMessage("changed lower bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
422  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
423  break;
425  /* if variable is not fixed to be negative anymore */
426  if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
427  --(consdata->nfixednonzero);
428  SCIPdebugMessage("changed upper bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
429  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
430  break;
431  default:
432  SCIPerrorMessage("invalid event type.\n");
433  return SCIP_INVALIDDATA;
434  }
435  assert( 0 <= consdata->nfixednonzero && consdata->nfixednonzero <= 2 );
436 
437  return SCIP_OKAY;
438 }
439 
440 
441 /* exec the event handler for forcing a restart
442  *
443  * There are two case in which we perform a (user) restart:
444  * - If we have a max FS instance, i.e., the objective is 1 for indicator variables and 0 otherwise,
445  * we can force a restart if the gap is 1. In this case, the remaining work consists of proving
446  * infeasibility of the non-fixed indicators.
447  * - If a large fraction of the binary indicator variables have been globally fixed, it makes sense
448  * to force a restart.
449  */
450 static
451 SCIP_DECL_EVENTEXEC(eventExecIndicatorRestart)
452 {
453  SCIP_CONSHDLRDATA* conshdlrdata;
454  SCIP_EVENTTYPE eventtype;
455 
456  assert( scip != NULL );
457  assert( eventhdlr != NULL );
458  assert( eventdata != NULL );
459  assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_RESTART_NAME) == 0 );
460  assert( event != NULL );
461 
462  conshdlrdata = (SCIP_CONSHDLRDATA*)eventdata;
463  assert( conshdlrdata != NULL );
464  assert( conshdlrdata->forcerestart );
465 
466  eventtype = SCIPeventGetType(event);
467  switch ( eventtype )
468  {
471  {
472 #ifndef NDEBUG
473  SCIP_Real oldbound;
474  SCIP_Real newbound;
475 
477  oldbound = SCIPeventGetOldbound(event);
478  newbound = SCIPeventGetNewbound(event);
479  assert( SCIPisIntegral(scip, oldbound) );
480  assert( SCIPisIntegral(scip, newbound) );
481  assert( ! SCIPisEQ(scip, oldbound, newbound) );
482  assert( SCIPisZero(scip, oldbound) || SCIPisEQ(scip, oldbound, 1.0) );
483  assert( SCIPisZero(scip, newbound) || SCIPisEQ(scip, newbound, 1.0) );
484 #endif
485 
486  /* do not treat this case if we have performed a restart already */
487  if ( conshdlrdata->performedrestart )
488  return SCIP_OKAY;
489 
490  /* variable is now fixed */
491  ++(conshdlrdata->nbinvarszero);
492  SCIPdebugMessage("fixed variable <%s> (nbinvarszero: %d, total: %d).\n",
493  SCIPvarGetName(SCIPeventGetVar(event)), conshdlrdata->nbinvarszero, conshdlrdata->ninitconss);
494 
495  if ( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
496  break;
497 
498  /* if enough variables have been fixed */
499  if ( conshdlrdata->nbinvarszero > (int) ((SCIP_Real) conshdlrdata->ninitconss * conshdlrdata->restartfrac) )
500  {
502  "Forcing restart, since %d binary variables among %d have been fixed.\n", conshdlrdata->nbinvarszero, conshdlrdata->ninitconss);
503  SCIP_CALL( SCIPrestartSolve(scip) );
504 
505  /* drop event */
506  if ( conshdlrdata->objindicatoronly )
507  {
508  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, eventhdlr, (SCIP_EVENTDATA*) conshdlrdata, -1) );
509  }
510  conshdlrdata->performedrestart = TRUE;
511  }
512  break;
513  }
515  assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
516  assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0 ) );
517 
518  if ( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
519  break;
520 
521  if ( ! conshdlrdata->objindicatoronly )
522  break;
523 
524  /* if the absolute gap is equal to minabsobj */
525  if ( SCIPisEQ(scip, REALABS(SCIPgetPrimalbound(scip) - SCIPgetDualbound(scip)), conshdlrdata->minabsobj) )
526  {
527  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Forcing restart, since the absolute gap is %f.\n", conshdlrdata->minabsobj);
528  SCIP_CALL( SCIPrestartSolve(scip) );
529 
530  /* use inference branching, since the objective is not meaningful */
531  if ( SCIPfindBranchrule(scip, "inference") != NULL && !SCIPisParamFixed(scip, "branching/inference/priority") )
532  {
533  SCIP_CALL( SCIPsetIntParam(scip, "branching/inference/priority", INT_MAX/4) );
534  }
535 
536  /* drop event */
537  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, eventhdlr, (SCIP_EVENTDATA*) conshdlrdata, -1) );
538  conshdlrdata->performedrestart = TRUE;
539  }
540  break;
541 
542  default:
543  SCIPerrorMessage("invalid event type.\n");
544  return SCIP_INVALIDDATA;
545  }
546 
547  return SCIP_OKAY;
548 }
549 
550 
551 /* ------------------------ conflict handler ---------------------------------*/
552 
553 /** destructor of conflict handler to free conflict handler data (called when SCIP is exiting) */
554 static
555 SCIP_DECL_CONFLICTFREE(conflictFreeIndicator)
556 {
557  SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
558 
559  assert( scip != NULL );
560  assert( conflicthdlr != NULL );
561  assert( strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0 );
562 
563  conflicthdlrdata = SCIPconflicthdlrGetData(conflicthdlr);
564  SCIPfreeMemory(scip, &conflicthdlrdata);
565 
566  return SCIP_OKAY;
567 }
568 
569 
570 /** conflict processing method of conflict handler (called when conflict was found)
571  *
572  * In this conflict handler we try to replace slack variables by binary indicator variables and
573  * generate a logicor constraint if possible.
574  *
575  * @todo Extend to integral case.
576  */
577 static
578 SCIP_DECL_CONFLICTEXEC(conflictExecIndicator)
579 { /*lint --e{715}*/
580  SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
581  SCIP_Bool haveslack;
582  SCIP_VAR* var;
583  int i;
584 
585  assert( conflicthdlr != NULL );
586  assert( strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0 );
587  assert( bdchginfos != NULL || nbdchginfos == 0 );
588  assert( result != NULL );
589 
590  /* don't process already resolved conflicts */
591  if ( resolved )
592  {
593  *result = SCIP_DIDNOTRUN;
594  return SCIP_OKAY;
595  }
596 
597  SCIPdebugMessage("Indictor conflict handler.\n");
598 
599  conflicthdlrdata = SCIPconflicthdlrGetData(conflicthdlr);
600  assert( conflicthdlrdata != NULL );
601 
602  /* possibly skip conflict handler */
603  if ( ! ((SCIP_CONFLICTHDLRDATA*) conflicthdlrdata)->conshdlrdata->conflictsupgrade )
604  return SCIP_OKAY;
605 
606  *result = SCIP_DIDNOTFIND;
607 
608  /* check whether there seems to be one slack variable and all other variables are binary */
609  haveslack = FALSE;
610  for (i = 0; i < nbdchginfos; ++i)
611  {
612  assert( bdchginfos != NULL ); /* for flexelint */
613  assert( bdchginfos[i] != NULL );
614 
615  var = SCIPbdchginfoGetVar(bdchginfos[i]);
616 
617  /* quick check for slack variable that is implicitly integral or continuous */
619  {
620  /* check string */
621  if ( strstr(SCIPvarGetName(var), "indslack") != NULL )
622  {
623  /* make sure that the slack variable occurs with its lower bound */
625  break;
626 
627  /* make sure that the lower bound is 0 */
628  if ( ! SCIPisFeasZero(scip, SCIPbdchginfoGetNewbound(bdchginfos[i])) )
629  break;
630 
631  haveslack = TRUE;
632  continue;
633  }
634  }
635 
636  /* we only treat binary variables (other than slack variables) */
637  if ( ! SCIPvarIsBinary(var) )
638  break;
639  }
640 
641  /* if we have found at least one slack variable and all other variables are binary */
642  if ( haveslack && i == nbdchginfos )
643  {
644  SCIP_CONS** conss;
645  SCIP_VAR** vars;
646  int nconss;
647  int j;
648 
649  SCIPdebugMessage("Found conflict involving slack variables that can be remodelled.\n");
650 
651  assert( conflicthdlrdata->conshdlr != NULL );
652  assert( strcmp(SCIPconshdlrGetName(conflicthdlrdata->conshdlr), CONSHDLR_NAME) == 0 );
653 
654  nconss = SCIPconshdlrGetNConss(conflicthdlrdata->conshdlr);
655  conss = SCIPconshdlrGetConss(conflicthdlrdata->conshdlr);
656 
657  /* create array of variables in conflict constraint */
658  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nbdchginfos) );
659  for (i = 0; i < nbdchginfos; ++i)
660  {
661  assert( bdchginfos != NULL ); /* for flexelint */
662  assert( bdchginfos[i] != NULL );
663 
664  var = SCIPbdchginfoGetVar(bdchginfos[i]);
665 
666  SCIPdebugMessage(" <%s> %s %g\n", SCIPvarGetName(var), SCIPbdchginfoGetBoundtype(bdchginfos[i]) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
667  SCIPbdchginfoGetNewbound(bdchginfos[i]));
668 
669  /* quick check for slack variable that is implicitly integral or continuous */
670  if ( (SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS) && strstr(SCIPvarGetName(var), "indslack") != NULL )
671  {
672  SCIP_VAR* slackvar;
673 
674  /* search for slack variable */
675  for (j = 0; j < nconss; ++j)
676  {
677  assert( conss[j] != NULL );
678  slackvar = SCIPgetSlackVarIndicator(conss[j]);
679  assert( slackvar != NULL );
680 
681  /* check whether we found the variable */
682  if ( slackvar == var )
683  {
684  /* replace slack variable by binary variable */
685  var = SCIPgetBinaryVarIndicator(conss[j]);
686  break;
687  }
688  }
689 
690  /* check whether we found the slack variable */
691  if ( j >= nconss )
692  {
693  SCIPdebugMessage("Could not find slack variable <%s>.\n", SCIPvarGetName(var));
694  break;
695  }
696  }
697  else
698  {
699  /* if the variable is fixed to one in the conflict set, we have to use its negation */
700  if ( SCIPbdchginfoGetNewbound(bdchginfos[i]) > 0.5 )
701  {
702  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
703  }
704  }
705 
706  vars[i] = var;
707  }
708 
709  /* whether all slack variables have been found */
710  if ( i == nbdchginfos )
711  {
712  SCIP_CONS* cons;
713  char consname[SCIP_MAXSTRLEN];
714 
715  SCIPdebugMessage("Generated logicor conflict constraint.\n");
716 
717  /* create a logicor constraint out of the conflict set */
718  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cf%d_%"SCIP_LONGINT_FORMAT, SCIPgetNRuns(scip), SCIPgetNConflictConssApplied(scip));
719  SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, consname, nbdchginfos, vars,
720  FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) );
721  SCIP_CALL( SCIPaddConsNode(scip, node, cons, validnode) );
722 #ifdef SCIP_OUTPUT
723  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
724  SCIPinfoMessage(scip, NULL, ";\n");
725 #endif
726  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
727 
728  *result = SCIP_CONSADDED;
729  }
730 
731  /* free temporary memory */
732  SCIPfreeBufferArray(scip, &vars);
733  }
734 
735  return SCIP_OKAY;
736 }
737 
738 
739 /* ------------------------ parameter handling ---------------------------------*/
740 
741 /** check parameter */
742 static
744  SCIP* scip, /**< SCIP data structure */
745  SCIP_PARAM* param, /**< parameter */
746  const char* name, /**< parameter name to check */
747  SCIP_Bool oldvalue, /**< old value of parameter */
748  SCIP_Bool* newvalue /**< new value after call */
749  )
750 {
751  const char* paramname;
752 
753  assert( scip != NULL );
754  assert( param != NULL );
755  assert( name != NULL );
756  assert( newvalue != NULL );
757 
758  if ( oldvalue == *newvalue )
759  return SCIP_OKAY;
760 
761  paramname = SCIPparamGetName(param);
762  assert( paramname != NULL );
763 
764  /* check whether the change parameter corresponds to our name to check */
765  if ( strcmp(paramname, name) == 0 )
766  {
767  /* check stage */
768  if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM )
769  {
770  SCIPwarningMessage(scip, "Cannot change parameter <%s> stage %d - reset to old value %s.\n", name, SCIPgetStage(scip), oldvalue ? "true" : "false");
771  /* reset parameter (NULL = do not recursively call paramchd function) */
772  SCIP_CALL( SCIPchgBoolParam(scip, param, oldvalue) );
773  *newvalue = oldvalue;
774  }
775  }
776  return SCIP_OKAY;
777 }
778 
779 
780 /** called after a parameter has been changed */
781 static
782 SCIP_DECL_PARAMCHGD(paramChangedIndicator)
783 {
784  SCIP_CONSHDLR* conshdlr;
785  SCIP_CONSHDLRDATA* conshdlrdata;
786  SCIP_Bool value;
787 
788  assert( scip != NULL );
789  assert( param != NULL );
790 
791  /* get indicator constraint handler */
792  conshdlr = SCIPfindConshdlr(scip, "indicator");
793  assert( conshdlr != NULL );
794 
795  /* get constraint handler data */
796  conshdlrdata = SCIPconshdlrGetData(conshdlr);
797  assert( conshdlrdata != NULL );
798 
799  value = conshdlrdata->sepaalternativelp_;
800  SCIP_CALL( checkParam(scip, param, "constraints/indicator/sepaalternativelp", conshdlrdata->sepaalternativelp, &value) );
801  conshdlrdata->sepaalternativelp = value;
802 
803  value = conshdlrdata->forcerestart_;
804  SCIP_CALL( checkParam(scip, param, "constraints/indicator/forcerestart", conshdlrdata->forcerestart, &value) );
805  conshdlrdata->forcerestart = value;
806 
807  value = conshdlrdata->nolinconscont;
808  SCIP_CALL( checkParam(scip, param, "constraints/indicator/nolinconscont", conshdlrdata->nolinconscont, &value) );
809  conshdlrdata->nolinconscont = value;
810 
811  return SCIP_OKAY;
812 }
813 
814 
815 /* ------------------------ debugging routines ---------------------------------*/
816 
817 #ifdef SCIP_ENABLE_IISCHECK
818 /** Check that indicator constraints corresponding to nonnegative entries in @a vector are infeasible in original problem
819  *
820  * This function will probably fail if the has been presolved by the cons_linear presolver - to
821  * make it complete we would have to substitute active variables.
822  */
823 static
824 SCIP_RETCODE checkIIS(
825  SCIP* scip, /**< SCIP pointer */
826  int nconss, /**< number of constraints */
827  SCIP_CONS** conss, /**< indicator constraints */
828  SCIP_Real* vector /**< vector */
829  )
830 {
831  SCIP_CONSHDLR* conshdlr;
832  SCIP_HASHMAP* varhash; /* hash map from variable to column index in auxiliary LP */
833  SCIP_LPI* lp;
834  int nvars = 0;
835  int c;
836 
837  assert( scip != NULL );
838  assert( vector != NULL );
839 
840  SCIPdebugMessage("Checking IIS ...\n");
841 
842  /* now check indicator constraints */
843  conshdlr = SCIPfindConshdlr(scip, "indicator");
844  assert( conshdlr != NULL );
845 
846  conss = SCIPconshdlrGetConss(conshdlr);
847  nconss = SCIPconshdlrGetNConss(conshdlr);
848 
849  /* create LP */
851 
852  /* set up hash map */
854 
855  /* loop through indicator constraints */
856  for (c = 0; c < nconss; ++c)
857  {
858  SCIP_CONSDATA* consdata;
859  consdata = SCIPconsGetData(conss[c]);
860  assert( consdata != NULL );
861 
862  /* check whether constraint should be included */
863  if ( consdata->colindex >= 0 && (! SCIPisFeasZero(scip, vector[consdata->colindex]) || ! SCIPconsIsEnabled(conss[c])) )
864  {
865  SCIP_CONS* lincons;
866  SCIP_VAR** linvars;
867  SCIP_Real* linvals;
868  SCIP_Real linrhs;
869  SCIP_Real linlhs;
870  SCIP_VAR* slackvar;
871  int nlinvars;
872  SCIP_Real sign;
873  int matbeg;
874  int* matind;
875  SCIP_Real* matval;
876  SCIP_VAR** newVars;
877  int nNewVars;
878  SCIP_Real lhs;
879  SCIP_Real rhs;
880  int cnt;
881  int v;
882 
883  sign = 1.0;
884 
885  lincons = consdata->lincons;
886  assert( lincons != NULL );
887  assert( ! SCIPconsIsEnabled(conss[c]) || SCIPconsIsActive(lincons) );
888  assert( ! SCIPconsIsEnabled(conss[c]) || SCIPconsIsEnabled(lincons) );
889 
890  slackvar = consdata->slackvar;
891  assert( slackvar != NULL );
892 
893  /* if the slack variable is aggregated (multi-aggregation should not happen) */
894  assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
895  if ( SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
896  {
897  SCIP_VAR* var;
898  SCIP_Real scalar;
899  SCIP_Real constant;
900 
901  var = slackvar;
902  scalar = 1.0;
903  constant = 0.0;
904 
905  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
906  assert( ! SCIPisZero(scip, scalar) );
907 
908  /* SCIPdebugMessage("slack variable aggregated (scalar: %f, constant: %f)\n", scalar, constant); */
909 
910  /* otherwise construct a linear constraint */
911  SCIP_CALL( SCIPallocBufferArray(scip, &linvars, 1) );
912  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, 1) );
913  linvars[0] = var;
914  linvals[0] = scalar;
915  nlinvars = 1;
916  linlhs = -SCIPinfinity(scip);
917  linrhs = constant;
918  }
919  else
920  {
921  /* in this case, the linear constraint is directly usable */
922  linvars = SCIPgetVarsLinear(scip, lincons);
923  linvals = SCIPgetValsLinear(scip, lincons);
924  nlinvars = SCIPgetNVarsLinear(scip, lincons);
925  linlhs = SCIPgetLhsLinear(scip, lincons);
926  linrhs = SCIPgetRhsLinear(scip, lincons);
927  }
928 
929  /* adapt rhs of linear constraint */
930  assert( SCIPisInfinity(scip, -linlhs) || SCIPisInfinity(scip, linrhs) );
931  if ( SCIPisInfinity(scip, linrhs) )
932  {
933  linrhs = linlhs;
934  assert( linrhs > -SCIPinfinity(scip) );
935  sign = -1.0;
936  }
937 
938  SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4*nlinvars) );
939  SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4*nlinvars) );
940  SCIP_CALL( SCIPallocBufferArray(scip, &newVars, nlinvars) );
941 
942  /* set up row */
943  nNewVars = 0;
944  for (v = 0; v < nlinvars; ++v)
945  {
946  SCIP_VAR* var;
947  var = linvars[v];
948  assert( var != NULL );
949 
950  /* skip slack variable */
951  if ( var == slackvar )
952  continue;
953 
954  /* if variable new */
955  if ( ! SCIPhashmapExists(varhash, var) )
956  {
957  /* add variable in map */
958  SCIP_CALL( SCIPhashmapInsert(varhash, var, (void*) (size_t) nvars) );
959  assert( nvars == (int) (size_t) SCIPhashmapGetImage(varhash, var) );
960  /* SCIPdebugMessage("Inserted variable <%s> into hashmap (%d).\n", SCIPvarGetName(var), nvars); */
961  nvars++;
962 
963  /* store new variables */
964  newVars[nNewVars++] = var;
965  }
966  assert( SCIPhashmapExists(varhash, var) );
967  }
968 
969  /* add new columns */
970  if ( nNewVars > 0 )
971  {
972  SCIP_Real* lb;
973  SCIP_Real* ub;
974  SCIP_Real* obj;
975  char** colnames;
976 
977  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nNewVars) );
978  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nNewVars) );
979  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nNewVars) );
980  SCIP_CALL( SCIPallocBufferArray(scip, &colnames, nNewVars) );
981 
982  for (v = 0; v < nNewVars; ++v)
983  {
984  SCIP_VAR* var;
985  var = newVars[v];
986  obj[v] = 0.0;
987  lb[v] = SCIPvarGetLbLocal(var);
988  ub[v] = SCIPvarGetUbLocal(var);
989  SCIP_CALL( SCIPallocBufferArray(scip, &(colnames[v]), SCIP_MAXSTRLEN) ); /*lint !e866*/
990  (void) SCIPsnprintf(colnames[v], SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var));
991  }
992 
993  /* now add columns */
994  SCIP_CALL( SCIPlpiAddCols(lp, nNewVars, obj, lb, ub, colnames, 0, NULL, NULL, NULL) );
995 
996  for (v = nNewVars - 1; v >= 0; --v)
997  {
998  SCIPfreeBufferArray(scip, &(colnames[v]));
999  }
1000  SCIPfreeBufferArray(scip, &colnames);
1001  SCIPfreeBufferArray(scip, &obj);
1002  SCIPfreeBufferArray(scip, &ub);
1003  SCIPfreeBufferArray(scip, &lb);
1004  }
1005 
1006  /* set up row */
1007  cnt = 0;
1008  for (v = 0; v < nlinvars; ++v)
1009  {
1010  SCIP_VAR* var;
1011  var = linvars[v];
1012  assert( var != NULL );
1013 
1014  /* skip slack variable */
1015  if ( var == slackvar )
1016  continue;
1017 
1018  assert( SCIPhashmapExists(varhash, var) );
1019  matind[cnt] = (int) (size_t) SCIPhashmapGetImage(varhash, var);
1020  matval[cnt] = sign * linvals[v];
1021  ++cnt;
1022  }
1023 
1024  lhs = -SCIPlpiInfinity(lp);
1025  rhs = linrhs;
1026 
1027  /* add new row */
1028  matbeg = 0;
1029  SCIP_CALL( SCIPlpiAddRows(lp, 1, &lhs, &rhs, NULL, cnt, &matbeg, matind, matval) );
1030 
1031  SCIPfreeBufferArray(scip, &matind);
1032  SCIPfreeBufferArray(scip, &matval);
1033  SCIPfreeBufferArray(scip, &newVars);
1034 
1035  assert( slackvar != NULL );
1036  if ( SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
1037  {
1038  SCIPfreeBufferArray(scip, &linvals);
1039  SCIPfreeBufferArray(scip, &linvars);
1040  }
1041  }
1042  }
1043 
1044  /* solve LP and check status */
1046 
1047  if ( ! SCIPlpiIsPrimalInfeasible(lp) )
1048  {
1049  SCIP_CONSHDLRDATA* conshdlrdata;
1050 
1051  SCIPerrorMessage("Detected IIS is not infeasible in original problem!\n");
1052 
1053  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1054  assert( conshdlrdata != NULL );
1055 
1056  SCIP_CALL( SCIPlpiWriteLP(lp, "check.lp") );
1057  SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "altdebug.lp") );
1058  SCIPABORT();
1059  return SCIP_ERROR; /*lint !e527*/
1060  }
1061  SCIPdebugMessage("Check successful!\n");
1062 
1063  SCIPhashmapFree(&varhash);
1064  SCIP_CALL( SCIPlpiFree(&lp) );
1065 
1066  return SCIP_OKAY;
1067 }
1068 #endif
1069 
1070 
1071 /* ------------------------ auxiliary operations -------------------------------*/
1072 
1073 /** return objective contribution of variable
1074  *
1075  * Special treatment of negated variables: return negative of objective of original
1076  * variable. SCIPvarGetObj() would return 0 in these cases.
1077  */
1078 static
1080  SCIP_VAR* var /**< variable */
1081  )
1082 {
1083  if ( SCIPvarIsBinary(var) && SCIPvarIsNegated(var) )
1084  {
1085  assert( SCIPvarGetNegatedVar(var) != NULL );
1086  return -SCIPvarGetObj(SCIPvarGetNegatedVar(var));
1087  }
1088  else if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED )
1089  {
1090  assert( SCIPvarGetAggrVar(var) != NULL );
1092  }
1093 
1094  return SCIPvarGetObj(var);
1095 }
1096 
1097 
1098 /** ensures that the addlincons array can store at least num entries */
1099 static
1101  SCIP* scip, /**< SCIP data structure */
1102  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1103  int num /**< minimum number of entries to store */
1104  )
1105 {
1106  SCIP_CONSHDLRDATA* conshdlrdata;
1107 
1108  assert( scip != NULL );
1109  assert( conshdlr != NULL );
1110  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1111 
1112  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1113  assert( conshdlrdata != NULL );
1114  assert( conshdlrdata->naddlincons <= conshdlrdata->maxaddlincons );
1115 
1116  if ( num > conshdlrdata->maxaddlincons )
1117  {
1118  int newsize;
1119 
1120  newsize = SCIPcalcMemGrowSize(scip, num);
1121  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons, newsize) );
1122  conshdlrdata->maxaddlincons = newsize;
1123  }
1124  assert( num <= conshdlrdata->maxaddlincons );
1125 
1126  return SCIP_OKAY;
1127 }
1128 
1129 
1130 /* ------------------------ operations on the alternative LP -------------------*/
1131 
1132 /** initialize alternative LP
1133  *
1134  * The alternative system is organized as follows:
1135  * - The first row corresponds to the right hand side of the original system.
1136  * - The next nconss constraints correspond to the slack variables.
1137  * - The rows after that correspond to the original variables.
1138  */
1139 static
1141  SCIP* scip, /**< SCIP pointer */
1142  SCIP_CONSHDLR* conshdlr /**< constraint handler */
1143  )
1144 {
1145  SCIP_CONSHDLRDATA* conshdlrdata;
1146  SCIP_Real lhs;
1147  SCIP_Real rhs;
1148 
1149  assert( scip != NULL );
1150  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1151 
1152  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1153  assert( conshdlrdata != NULL );
1154  assert( conshdlrdata->altlp == NULL );
1155  assert( conshdlrdata->varhash == NULL );
1156  assert( conshdlrdata->lbhash == NULL );
1157  assert( conshdlrdata->ubhash == NULL );
1158  assert( conshdlrdata->slackhash != NULL );
1159 
1160  SCIPdebugMessage("Initializing alternative LP ...\n");
1161 
1162  /* create hash map of variables */
1163  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), SCIPcalcHashtableSize(10 * SCIPgetNVars(scip))) );
1164  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->lbhash, SCIPblkmem(scip), SCIPcalcHashtableSize(10 * SCIPgetNVars(scip))) );
1165  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->ubhash, SCIPblkmem(scip), SCIPcalcHashtableSize(10 * SCIPgetNVars(scip))) );
1166 
1167  /* create alternative LP */
1168  SCIP_CALL( SCIPlpiCreate(&conshdlrdata->altlp, SCIPgetMessagehdlr(scip), "altlp", SCIP_OBJSEN_MINIMIZE) );
1169 
1170  /* add first row */
1171  lhs = -1.0;
1172  rhs = -1.0;
1173  SCIP_CALL( SCIPlpiAddRows(conshdlrdata->altlp, 1, &lhs, &rhs, NULL, 0, NULL, NULL, NULL) );
1174  conshdlrdata->nrows = 1;
1175 
1176  /* set parameters */
1178  SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_PRESOLVING, TRUE) );
1179  SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_SCALING, TRUE) );
1180  SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_FASTMIP, FALSE) );
1181 
1182  /* set constraint handler data */
1183  SCIPconshdlrSetData(conshdlr, conshdlrdata);
1184 
1185  /* uncomment the following for debugging */
1186  /* SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_LPINFO, TRUE) ); */
1187 
1188  return SCIP_OKAY;
1189 }
1190 
1191 
1192 /** Check whether the bounds int given (alternative) LP are set correctly (for debugging) */
1193 #ifndef NDEBUG
1194 static
1196  SCIP* scip, /**< SCIP pointer */
1197  SCIP_LPI* lp, /**< LP for which bounds should be checked */
1198  int nconss, /**< number of constraints */
1199  SCIP_CONS** conss /**< constraints */
1200  )
1201 {
1202  SCIP_Real* lb;
1203  SCIP_Real* ub;
1204  SCIP_Bool* covered;
1205  int nCols;
1206  int j;
1207 
1208  assert( scip != NULL );
1209  assert( lp != NULL );
1210 
1211  SCIP_CALL( SCIPlpiGetNCols(lp, &nCols) );
1212 
1213  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nCols) );
1214  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nCols) );
1215  SCIP_CALL( SCIPallocBufferArray(scip, &covered, nCols) );
1216 
1217  for (j = 0; j < nCols; ++j)
1218  covered[j] = FALSE;
1219 
1220  /* check columns used by constraints */
1221  SCIP_CALL( SCIPlpiGetBounds(lp, 0, nCols-1, lb, ub) );
1222  for (j = 0; j < nconss; ++j)
1223  {
1224  SCIP_CONSDATA* consdata;
1225  int ind;
1226 
1227  assert( conss[j] != NULL );
1228  consdata = SCIPconsGetData(conss[j]);
1229  assert( consdata != NULL );
1230  ind = consdata->colindex;
1231 
1232  if ( ind >= 0 )
1233  {
1234  assert( ind < nCols );
1235  covered[ind] = TRUE;
1236  if ( ! SCIPisFeasZero(scip, lb[ind]) || ! SCIPlpiIsInfinity(lp, ub[ind]) )
1237  {
1238  SCIPABORT();
1239  }
1240  }
1241  }
1242 
1243  /* check other columns */
1244  for (j = 0; j < nCols; ++j)
1245  {
1246  if (! covered[j] )
1247  {
1248  /* some columns can be fixed to 0, since they correspond to disabled constraints */
1249  if ( ( ! SCIPlpiIsInfinity(lp, -lb[j]) && ! SCIPisFeasZero(scip, lb[j])) || (! SCIPlpiIsInfinity(lp, ub[j]) && ! SCIPisFeasZero(scip, ub[j])) )
1250  {
1251  SCIPABORT();
1252  }
1253  }
1254  }
1255 
1256  SCIPfreeBufferArray(scip, &covered);
1257  SCIPfreeBufferArray(scip, &lb);
1258  SCIPfreeBufferArray(scip, &ub);
1259 
1260  return SCIP_OKAY;
1261 }
1262 #endif
1263 
1264 
1265 /** Set the alternative system objective function
1266  *
1267  * We assume that the objective function coefficients of the variables other than the binary
1268  * indicators are always 0 and hence do not have to be changed.
1269  *
1270  * We already use the tranformation \f$y' = 1 - y\f$.
1271  */
1272 static
1274  SCIP* scip, /**< SCIP pointer */
1275  SCIP_LPI* lp, /**< alternative LP */
1276  SCIP_SOL* sol, /**< solution to be dealt with */
1277  int nconss, /**< number of constraints */
1278  SCIP_CONS** conss /**< indicator constraints */
1279  )
1280 {
1281  int j;
1282  SCIP_Real* obj = NULL;
1283  int* indices = NULL;
1284  int cnt = 0;
1285 
1286  assert( scip != NULL );
1287  assert( lp != NULL );
1288  assert( conss != NULL );
1289 
1290  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nconss) );
1291  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1292 
1293  for (j = 0; j < nconss; ++j)
1294  {
1295  SCIP_CONSDATA* consdata;
1296 
1297  assert( conss[j] != NULL );
1298  consdata = SCIPconsGetData(conss[j]);
1299  assert( consdata != NULL );
1300 
1301  if ( consdata->colindex >= 0 )
1302  {
1303  SCIP_Real val = SCIPgetSolVal(scip, sol, consdata->binvar);
1304  if ( SCIPisFeasEQ(scip, val, 1.0) )
1305  obj[cnt] = OBJEPSILON; /* set objective to some small number to get small IISs */
1306  else
1307  obj[cnt] = 1.0 - val;
1308  indices[cnt++] = consdata->colindex;
1309  }
1310  }
1311 
1312  if ( cnt > 0 )
1313  {
1314  SCIP_CALL( SCIPlpiChgObj(lp, cnt, indices, obj) );
1315  }
1316 
1317  SCIPfreeBufferArray(scip, &indices);
1318  SCIPfreeBufferArray(scip, &obj);
1319 
1320  return SCIP_OKAY;
1321 }
1322 
1323 
1324 /** Set the alternative system objective function to some small value */
1325 static
1327  SCIP* scip, /**< SCIP pointer */
1328  SCIP_LPI* lp, /**< alternative LP */
1329  int nconss, /**< number of constraints */
1330  SCIP_CONS** conss /**< indicator constraints */
1331  )
1332 {
1333  int j;
1334  SCIP_Real* obj = NULL;
1335  int* indices = NULL;
1336  int cnt = 0;
1337 
1338  assert( scip != NULL );
1339  assert( lp != NULL );
1340  assert( conss != NULL );
1341 
1342  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nconss) );
1343  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1344 
1345  for (j = 0; j < nconss; ++j)
1346  {
1347  SCIP_CONSDATA* consdata;
1348 
1349  assert( conss[j] != NULL );
1350  consdata = SCIPconsGetData(conss[j]);
1351  assert( consdata != NULL );
1352 
1353  if ( consdata->colindex >= 0 )
1354  {
1355  obj[cnt] = OBJEPSILON;
1356  indices[cnt++] = consdata->colindex;
1357  }
1358  }
1359 
1360  if ( cnt > 0 )
1361  {
1362  SCIP_CALL( SCIPlpiChgObj(lp, cnt, indices, obj) );
1363  }
1364 
1365  SCIPfreeBufferArray(scip, &indices);
1366  SCIPfreeBufferArray(scip, &obj);
1367 
1368  return SCIP_OKAY;
1369 }
1370 
1371 
1372 /** Fix variable given by @a S to 0 */
1373 static
1375  SCIP* scip, /**< SCIP pointer */
1376  SCIP_LPI* lp, /**< alternative LP */
1377  int nconss, /**< number of constraints */
1378  SCIP_CONS** conss, /**< indicator constraints */
1379  SCIP_Bool* S /**< bitset of variables */
1380  )
1381 {
1382  SCIP_Real* lb = NULL;
1383  SCIP_Real* ub = NULL;
1384  int* indices = NULL;
1385  int cnt = 0;
1386  int j;
1387 
1388  assert( scip != NULL );
1389  assert( lp != NULL );
1390  assert( conss != NULL );
1391 
1392  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nconss) );
1393  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nconss) );
1394  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1395 
1396  /* collect bounds to be changed */
1397  for (j = 0; j < nconss; ++j)
1398  {
1399  SCIP_CONSDATA* consdata;
1400 
1401  assert( conss[j] != NULL );
1402  consdata = SCIPconsGetData(conss[j]);
1403  assert( consdata != NULL );
1404 
1405  if ( consdata->colindex >= 0 )
1406  {
1407  if ( S[j] )
1408  {
1409  indices[cnt] = consdata->colindex;
1410  lb[cnt] = 0.0;
1411  ub[cnt] = 0.0;
1412  ++cnt;
1413  }
1414  }
1415  }
1416 
1417  /* change bounds */
1418  if ( cnt > 0 )
1419  {
1420  SCIP_CALL( SCIPlpiChgBounds(lp, cnt, indices, lb, ub) );
1421  }
1422 
1423  SCIPfreeBufferArray(scip, &indices);
1424  SCIPfreeBufferArray(scip, &ub);
1425  SCIPfreeBufferArray(scip, &lb);
1426 
1427  return SCIP_OKAY;
1428 }
1429 
1430 
1431 /** Fix variable @a ind to 0 */
1432 static
1434  SCIP_LPI* lp, /**< alternative LP */
1435  int ind /**< variable that should be fixed to 0 */
1436  )
1437 {
1438  SCIP_Real lb;
1439  SCIP_Real ub;
1440 
1441  lb = 0.0;
1442  ub = 0.0;
1443 
1444  /* change bounds */
1445  SCIP_CALL( SCIPlpiChgBounds(lp, 1, &ind, &lb, &ub) );
1446 
1447  return SCIP_OKAY;
1448 }
1449 
1450 
1451 /** unfix variable @a ind to 0 */
1452 static
1454  SCIP_LPI* lp, /**< alternative LP */
1455  int ind /**< variable that should be fixed to 0 */
1456  )
1457 {
1458  SCIP_Real lb = 0.0;
1459  SCIP_Real ub = SCIPlpiInfinity(lp);
1460 
1461  /* change bounds */
1462  SCIP_CALL( SCIPlpiChgBounds(lp, 1, &ind, &lb, &ub) );
1463 
1464  return SCIP_OKAY;
1465 }
1466 
1467 /** unfix variable given by @a S to 0 */
1468 static
1470  SCIP* scip, /**< SCIP pointer */
1471  SCIP_LPI* lp, /**< alternative LP */
1472  int nconss, /**< number of constraints */
1473  SCIP_CONS** conss, /**< indicator constraints */
1474  SCIP_Bool* S /**< bitset of variables */
1475  )
1476 {
1477  SCIP_Real* lb = NULL;
1478  SCIP_Real* ub = NULL;
1479  int* indices = NULL;
1480  int cnt = 0;
1481  int j;
1482 
1483  assert( scip != NULL );
1484  assert( lp != NULL );
1485  assert( conss != NULL );
1486 
1487  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nconss) );
1488  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nconss) );
1489  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1490 
1491  /* collect bounds to be changed */
1492  for (j = 0; j < nconss; ++j)
1493  {
1494  if ( S[j] )
1495  {
1496  SCIP_CONSDATA* consdata;
1497 
1498  assert( conss[j] != NULL );
1499  consdata = SCIPconsGetData(conss[j]);
1500  assert( consdata != NULL );
1501 
1502  if ( consdata->colindex >= 0 )
1503  {
1504  indices[cnt] = consdata->colindex;
1505  lb[cnt] = 0.0;
1506  ub[cnt] = SCIPlpiInfinity(lp);
1507  ++cnt;
1508  }
1509  }
1510  }
1511 
1512  /* change bounds */
1513  if ( cnt > 0 )
1514  {
1515  SCIP_CALL( SCIPlpiChgBounds(lp, cnt, indices, lb, ub) );
1516  }
1517 
1518  SCIPfreeBufferArray(scip, &indices);
1519  SCIPfreeBufferArray(scip, &ub);
1520  SCIPfreeBufferArray(scip, &lb);
1521 
1522  return SCIP_OKAY;
1523 }
1524 
1525 
1526 /** update bounds in first row to the current ones */
1527 static
1529  SCIP* scip, /**< SCIP pointer */
1530  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
1531  )
1532 {
1533  SCIP_HASHMAP* lbhash;
1534  SCIP_HASHMAP* ubhash;
1535  SCIP_VAR** vars;
1536  SCIP_LPI* altlp;
1537  int nvars;
1538  int cnt;
1539  int v;
1540 
1541  assert( scip != NULL );
1542  assert( conshdlrdata != NULL );
1543 
1544  altlp = conshdlrdata->altlp;
1545  lbhash = conshdlrdata->lbhash;
1546  ubhash = conshdlrdata->ubhash;
1547  assert( lbhash != NULL && ubhash != NULL );
1548 
1549  /* check all variables */
1550  vars = SCIPgetVars(scip);
1551  nvars = SCIPgetNVars(scip);
1552  cnt = 0;
1553 
1554  for (v = 0; v < nvars; ++v)
1555  {
1556  SCIP_VAR* var;
1557  var = vars[v];
1558  if ( SCIPhashmapExists(lbhash, var) )
1559  {
1560  int col;
1561 
1562  col = (int) (size_t) SCIPhashmapGetImage(lbhash, var);
1563  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, -SCIPvarGetLbLocal(var)) );
1564  if ( ! SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var)) )
1565  ++cnt;
1566  }
1567  if ( SCIPhashmapExists(ubhash, var) )
1568  {
1569  int col;
1570 
1571  col = (int) (size_t) SCIPhashmapGetImage(ubhash, var);
1572  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, SCIPvarGetUbLocal(var)) );
1573  if ( ! SCIPisEQ(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var)) )
1574  ++cnt;
1575  }
1576  }
1577  if ( cnt > 10 )
1578  {
1579  /* possible force a rescaling: */
1580  conshdlrdata->scaled = FALSE;
1581 
1582  /* SCIP_CALL( SCIPlpiWriteLP(altlp, "altChg.lp") ); */
1583  SCIPdebugMessage("Updated bounds of original variables: %d\n", cnt);
1584  }
1585 
1586  return SCIP_OKAY;
1587 }
1588 
1589 
1590 /** update bounds in first row to the global bounds */
1591 static
1593  SCIP* scip, /**< SCIP pointer */
1594  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
1595  )
1596 {
1597 
1598  SCIP_HASHMAP* lbhash;
1599  SCIP_HASHMAP* ubhash;
1600  SCIP_VAR** vars;
1601  SCIP_LPI* altlp;
1602  int nvars;
1603  int cnt;
1604  int v;
1605 
1606  assert( scip != NULL );
1607  assert( conshdlrdata != NULL );
1608 
1609  altlp = conshdlrdata->altlp;
1610  lbhash = conshdlrdata->lbhash;
1611  ubhash = conshdlrdata->ubhash;
1612  assert( lbhash != NULL && ubhash != NULL );
1613 
1614  /* check all variables */
1615  vars = SCIPgetVars(scip);
1616  nvars = SCIPgetNVars(scip);
1617  cnt = 0;
1618 
1619  for (v = 0; v < nvars; ++v)
1620  {
1621  SCIP_VAR* var;
1622  var = vars[v];
1623  if ( SCIPhashmapExists(lbhash, var) )
1624  {
1625  int col;
1626  col = (int) (size_t) SCIPhashmapGetImage(lbhash, var);
1627  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, -SCIPvarGetLbGlobal(var)) );
1628  ++cnt;
1629  }
1630  if ( SCIPhashmapExists(ubhash, var) )
1631  {
1632  int col;
1633  col = (int) (size_t) SCIPhashmapGetImage(ubhash, var);
1634  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, SCIPvarGetUbGlobal(var)) );
1635  ++cnt;
1636  }
1637  }
1638  if ( cnt > 0 )
1639  {
1640  /* SCIP_CALL( SCIPlpiWriteLP(altlp, "altChg.lp") ); */
1641  SCIPdebugMessage("Updated bounds of original variables: %d\n", cnt);
1642  }
1643 
1644  /* possible force a rescaling: */
1645  /* conshdlrdata->scaled = FALSE; */
1646 
1647  return SCIP_OKAY;
1648 }
1649 
1650 
1651 /** Check whether IIS defined by @a vector corresponds to a local cut */
1652 static
1654  SCIP* scip, /**< SCIP pointer */
1655  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler */
1656  SCIP_Real* vector, /**< solution to alternative LP defining IIS */
1657  SCIP_Bool* isLocal /**< whether the IIS uses local bounds different from the global ones */
1658  )
1659 {
1660  SCIP_HASHMAP* lbhash;
1661  SCIP_HASHMAP* ubhash;
1662  SCIP_VAR** vars;
1663 #ifndef NDEBUG
1664  int nCols;
1665 #endif
1666  int nvars;
1667  int v;
1668 
1669  assert( scip != NULL );
1670  assert( conshdlrdata != NULL );
1671  assert( vector != NULL );
1672  assert( isLocal != NULL );
1673 
1674  *isLocal = FALSE;
1675 
1676 #ifndef NDEBUG
1677  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &nCols) );
1678 #endif
1679 
1680  lbhash = conshdlrdata->lbhash;
1681  ubhash = conshdlrdata->ubhash;
1682  assert( lbhash != NULL && ubhash != NULL );
1683 
1684  /* get all variables */
1685  vars = SCIPgetVars(scip);
1686  nvars = SCIPgetNVars(scip);
1687 
1688  /* check all variables */
1689  for (v = 0; v < nvars; ++v)
1690  {
1691  SCIP_VAR* var;
1692  var = vars[v];
1693 
1694  /* if local bound is different from global bound */
1695  if ( ! SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var)) )
1696  {
1697  /* check whether the variable corresponding to the lower bounds has been used */
1698  if ( SCIPhashmapExists(lbhash, var) )
1699  {
1700  int col;
1701 
1702  col = (int) (size_t) SCIPhashmapGetImage(lbhash, var);
1703  assert( 0 <= col && col < nCols );
1704  if ( ! SCIPisFeasZero(scip, vector[col]) )
1705  {
1706  *isLocal = FALSE;
1707  return SCIP_OKAY;
1708  }
1709  }
1710  }
1711 
1712  /* if local bound is different from global bound */
1713  if ( ! SCIPisEQ(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var)) )
1714  {
1715  /* check whether the variable corresponding to the upper bounds has been used */
1716  if ( SCIPhashmapExists(ubhash, var) )
1717  {
1718  int col;
1719 
1720  col = (int) (size_t) SCIPhashmapGetImage(ubhash, var);
1721  assert( 0 <= col && col < nCols );
1722  if ( ! SCIPisFeasZero(scip, vector[col]) )
1723  {
1724  *isLocal = FALSE;
1725  return SCIP_OKAY;
1726  }
1727  }
1728  }
1729  }
1730 
1731  return SCIP_OKAY;
1732 }
1733 
1734 
1735 /** compute scaling for first row
1736  *
1737  * If the coefficients in the first row are large, a right hand side of -1 might not be
1738  * adequate. Here, we replace the right hand side by the sum of the coefficients divided by the
1739  * number of nonzeros.
1740  */
1741 static
1743  SCIP* scip, /**< SCIP pointer */
1744  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
1745  )
1746 {
1747  SCIP_LPI* altlp;
1748  SCIP_Real* val;
1749  SCIP_Real sum = 0.0;
1750  int j;
1751  int nCols;
1752  int cnt;
1753  int beg;
1754  int* ind;
1755 
1756  assert( scip != NULL );
1757  assert( conshdlrdata != NULL );
1758 
1759  if ( ! conshdlrdata->scaled )
1760  {
1761  altlp = conshdlrdata->altlp;
1762  SCIP_CALL( SCIPlpiGetNCols(altlp, &nCols) );
1763  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nCols) );
1764  SCIP_CALL( SCIPallocBufferArray(scip, &val, nCols) );
1765 
1766  SCIP_CALL( SCIPlpiGetRows(altlp, 0, 0, NULL, NULL, &cnt, &beg, ind, val) );
1767 
1768  if ( cnt > 0 )
1769  {
1770  /* compute sum */
1771  for (j = 0; j < cnt; ++j)
1772  sum += REALABS(val[j]);
1773 
1774  /* set rhs */
1775  sum = - REALABS(sum) / ((double) cnt);
1776  j = 0;
1777  SCIP_CALL( SCIPlpiChgSides(altlp, 1, &j, &sum, &sum) );
1778  }
1779 
1780  SCIPfreeBufferArray(scip, &val);
1781  SCIPfreeBufferArray(scip, &ind);
1782 
1783  conshdlrdata->scaled = TRUE;
1784  }
1785 
1786  return SCIP_OKAY;
1787 }
1788 
1789 
1790 /** add column corresponding to constraint to alternative LP
1791  *
1792  * See the description at the top of the file for more information.
1793  */
1794 static
1796  SCIP* scip, /**< SCIP pointer */
1797  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1798  SCIP_CONS* lincons, /**< linear constraint */
1799  SCIP_VAR* slackvar, /**< slack variable or NULL */
1800  SCIP_Real objcoef, /**< objective coefficient */
1801  int* colindex /**< index of new column */
1802  )
1803 {
1804  SCIP_CONSHDLRDATA* conshdlrdata;
1805  SCIP_VAR** newVars;
1806  SCIP_VAR** linvars;
1807  SCIP_Real* linvals;
1808  SCIP_Real linrhs;
1809  SCIP_Real linlhs;
1810  SCIP_Real val;
1811  SCIP_Real sign;
1812  int* matbeg;
1813  int* matind;
1814  SCIP_Real* matval;
1815  SCIP_Bool* newRowsSlack;
1816  SCIP_Real* obj;
1817  SCIP_Real* lb;
1818  SCIP_Real* ub;
1819  int nlinvars;
1820  int nNewVars;
1821  int nNewCols;
1822  int nNewRows;
1823  int nCols;
1824  int cnt;
1825  int v;
1826 
1827  assert( scip != NULL );
1828  assert( conshdlr != NULL );
1829  assert( lincons != NULL );
1830  assert( colindex != NULL );
1831 
1832  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1833 
1834  *colindex = -1;
1835  sign = 1.0;
1836  nNewVars = 0;
1837  nNewRows = 0;
1838  cnt = 0;
1839 
1840  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1841  assert( conshdlrdata != NULL );
1842 
1843  /* if the slack variable is aggregated (multi-aggregation should not happen) */
1844  assert( slackvar == NULL || SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
1845  if ( slackvar != NULL && SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
1846  {
1847  SCIP_VAR* var;
1848  SCIP_Real scalar;
1849  SCIP_Real constant;
1850 
1851  var = slackvar;
1852  scalar = 1.0;
1853  constant = 0.0;
1854 
1855  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
1856 
1857  SCIPdebugMessage("slack variable aggregated (scalar: %f, constant: %f)\n", scalar, constant);
1858 
1859  /* if the slack variable is fixed */
1860  if ( SCIPisZero(scip, scalar) && ! SCIPconsIsActive(lincons) )
1861  return SCIP_OKAY;
1862 
1863  /* otherwise construct a linear constraint */
1864  SCIP_CALL( SCIPallocBufferArray(scip, &linvars, 1) );
1865  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, 1) );
1866  linvars[0] = var;
1867  linvals[0] = scalar;
1868  nlinvars = 1;
1869  linlhs = -SCIPinfinity(scip);
1870  linrhs = constant;
1871  }
1872  else
1873  {
1874  /* exit if linear constraint is not active */
1875  if ( ! SCIPconsIsActive(lincons) && slackvar != NULL )
1876  return SCIP_OKAY;
1877 
1878  /* in this case, the linear constraint is directly usable */
1879  linvars = SCIPgetVarsLinear(scip, lincons);
1880  linvals = SCIPgetValsLinear(scip, lincons);
1881  nlinvars = SCIPgetNVarsLinear(scip, lincons);
1882  linlhs = SCIPgetLhsLinear(scip, lincons);
1883  linrhs = SCIPgetRhsLinear(scip, lincons);
1884  }
1885 
1886  if ( conshdlrdata->altlp == NULL )
1887  {
1888  SCIP_CALL( initAlternativeLP(scip, conshdlr) );
1889  }
1890  assert( conshdlrdata->varhash != NULL );
1891  assert( conshdlrdata->lbhash != NULL );
1892  assert( conshdlrdata->ubhash != NULL );
1893  assert( conshdlrdata->slackhash != NULL );
1894 
1895 #ifndef NDEBUG
1896  {
1897  int nrows;
1898  SCIP_CALL( SCIPlpiGetNRows(conshdlrdata->altlp, &nrows) );
1899  assert( nrows == conshdlrdata->nrows );
1900  }
1901 #endif
1902 
1903  SCIP_CALL( SCIPallocBufferArray(scip, &matbeg, nlinvars) );
1904  SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4*nlinvars) );
1905  SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4*nlinvars) );
1906  SCIP_CALL( SCIPallocBufferArray(scip, &obj, 2*nlinvars) );
1907  SCIP_CALL( SCIPallocBufferArray(scip, &lb, 2*nlinvars) );
1908  SCIP_CALL( SCIPallocBufferArray(scip, &ub, 2*nlinvars) );
1909  SCIP_CALL( SCIPallocBufferArray(scip, &newVars, nlinvars) );
1910  SCIP_CALL( SCIPallocBufferArray(scip, &newRowsSlack, 2 * nlinvars) );
1911 
1912  /* store index of column in constraint */
1913  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &nCols) );
1914  *colindex = nCols;
1915 
1916  /* adapt rhs of linear constraint */
1917  val = linrhs;
1918  if ( SCIPisInfinity(scip, val) )
1919  {
1920  val = linlhs;
1921  assert( val > -SCIPinfinity(scip) );
1922  sign = -1.0;
1923  }
1924 
1925  /* handle first row */
1926  if (! SCIPisFeasZero(scip, val) )
1927  {
1928  matind[cnt] = 0;
1929  matval[cnt] = sign * val;
1930  assert( ! SCIPisInfinity(scip, val) && ! SCIPisInfinity(scip, -val) );
1931  ++cnt;
1932  }
1933 
1934  /* set up column (recognize new original variables) */
1935  for (v = 0; v < nlinvars; ++v)
1936  {
1937  SCIP_VAR* var;
1938  var = linvars[v];
1939  assert( var != NULL );
1940 
1941  /* if variable is a slack variable */
1942  if ( SCIPhashmapExists(conshdlrdata->slackhash, var) )
1943  {
1944  /* to avoid trivial rows: only add row corresponding to slack variable if it appears outside its own constraint */
1945  if ( var != slackvar )
1946  {
1947  int ind;
1948 
1949  ind = (int) (size_t) SCIPhashmapGetImage(conshdlrdata->slackhash, var);
1950 
1951  if ( ind < INT_MAX )
1952  matind[cnt] = ind;
1953  else
1954  {
1955  /* add variable in map and array and remember to add a new row */
1956  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->slackhash, var, (void*) (size_t) conshdlrdata->nrows) );
1957  assert( conshdlrdata->nrows == (int) (size_t) SCIPhashmapGetImage(conshdlrdata->slackhash, var) );
1958  SCIPdebugMessage("Inserted slack variable <%s> into hashmap (row: %d).\n", SCIPvarGetName(var), conshdlrdata->nrows);
1959  matind[cnt] = (conshdlrdata->nrows)++;
1960 
1961  /* store new variables */
1962  newRowsSlack[nNewRows++] = TRUE;
1963  }
1964  assert( conshdlrdata->nrows >= (int) (size_t) SCIPhashmapGetImage(conshdlrdata->slackhash, var) );
1965  matval[cnt] = sign * linvals[v];
1966  ++cnt;
1967  }
1968  }
1969  else
1970  {
1971  /* if variable exists */
1972  if ( SCIPhashmapExists(conshdlrdata->varhash, var) )
1973  matind[cnt] = (int) (size_t) SCIPhashmapGetImage(conshdlrdata->varhash, var);
1974  else
1975  {
1976  /* add variable in map and array and remember to add a new row */
1977  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->varhash, var, (void*) (size_t) conshdlrdata->nrows) );
1978  assert( conshdlrdata->nrows == (int) (size_t) SCIPhashmapGetImage(conshdlrdata->varhash, var) );
1979  SCIPdebugMessage("Inserted variable <%s> into hashmap (row: %d).\n", SCIPvarGetName(var), conshdlrdata->nrows);
1980  matind[cnt] = (conshdlrdata->nrows)++;
1981 
1982  /* store new variables */
1983  newRowsSlack[nNewRows++] = FALSE;
1984  newVars[nNewVars++] = var;
1985  }
1986  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
1987  matval[cnt] = sign * linvals[v];
1988  ++cnt;
1989  }
1990  }
1991 
1992  /* add new rows */
1993  if ( nNewRows > 0 )
1994  {
1995  SCIP_Real* lhs;
1996  SCIP_Real* rhs;
1997  int i;
1998 
1999  SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nNewRows) );
2000  SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nNewRows) );
2001  for (i = 0; i < nNewRows; ++i)
2002  {
2003  if ( newRowsSlack[i] )
2004  lhs[i] = -SCIPlpiInfinity(conshdlrdata->altlp);
2005  else
2006  lhs[i] = 0.0;
2007  rhs[i] = 0.0;
2008  }
2009  /* add new rows */
2010  SCIP_CALL( SCIPlpiAddRows(conshdlrdata->altlp, nNewRows, lhs, rhs, NULL, 0, NULL, NULL, NULL) );
2011 
2012  SCIPfreeBufferArray(scip, &lhs);
2013  SCIPfreeBufferArray(scip, &rhs);
2014  }
2015 
2016  /* now add column */
2017  obj[0] = objcoef;
2018  lb[0] = 0.0;
2019  ub[0] = SCIPlpiInfinity(conshdlrdata->altlp);
2020  matbeg[0] = 0;
2021 
2022  /* create a free variable for equations -> should only happen for additional linear constraints */
2023  if ( SCIPisEQ(scip, linlhs, linrhs) )
2024  {
2025  assert( slackvar == NULL );
2026  lb[0] = -SCIPlpiInfinity(conshdlrdata->altlp);
2027  }
2028 
2029  SCIP_CALL( SCIPlpiAddCols(conshdlrdata->altlp, 1, obj, lb, ub, NULL, cnt, matbeg, matind, matval) );
2030 
2031  /* add columns corresponding to bounds of original variables - no bounds needed for slack vars */
2032  cnt = 0;
2033  nNewCols = 0;
2034  for (v = 0; v < nNewVars; ++v)
2035  {
2036  SCIP_VAR* var = newVars[v];
2037 
2038  /* if the lower bound is finite */
2039  val = SCIPvarGetLbGlobal(var);
2040  if ( ! SCIPisInfinity(scip, -val) )
2041  {
2042  matbeg[nNewCols] = cnt;
2043  if ( ! SCIPisZero(scip, val) )
2044  {
2045  matind[cnt] = 0;
2046  matval[cnt] = -val;
2047  ++cnt;
2048  }
2049  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2050  matind[cnt] = (int) (size_t) SCIPhashmapGetImage(conshdlrdata->varhash, var);
2051  matval[cnt] = -1.0;
2052  ++cnt;
2053  obj[nNewCols] = 0.0;
2054  lb[nNewCols] = 0.0;
2055  ub[nNewCols] = SCIPlpiInfinity(conshdlrdata->altlp);
2056  ++conshdlrdata->nlbbounds;
2057  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->lbhash, var, (void*) (size_t) (nCols + 1 + nNewCols)) );
2058  assert( SCIPhashmapExists(conshdlrdata->lbhash, var) );
2059  SCIPdebugMessage("added column corr. to lower bound (%f) of variable <%s> to alternative polyhedron (col: %d).\n",
2060  val, SCIPvarGetName(var), nCols + 1 + nNewCols);
2061  ++nNewCols;
2062  }
2063 
2064  /* if the upper bound is finite */
2065  val = SCIPvarGetUbGlobal(var);
2066  if ( ! SCIPisInfinity(scip, val) )
2067  {
2068  matbeg[nNewCols] = cnt;
2069  if ( ! SCIPisZero(scip, val) )
2070  {
2071  matind[cnt] = 0;
2072  matval[cnt] = val;
2073  ++cnt;
2074  }
2075  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2076  matind[cnt] = (int) (size_t) SCIPhashmapGetImage(conshdlrdata->varhash, var);
2077  matval[cnt] = 1.0;
2078  ++cnt;
2079  obj[nNewCols] = 0.0;
2080  lb[nNewCols] = 0.0;
2081  ub[nNewCols] = SCIPlpiInfinity(conshdlrdata->altlp);
2082  ++conshdlrdata->nubbounds;
2083  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->ubhash, var, (void*) (size_t) (nCols + 1 + nNewCols)) );
2084  assert( SCIPhashmapExists(conshdlrdata->ubhash, var) );
2085  SCIPdebugMessage("added column corr. to upper bound (%f) of variable <%s> to alternative polyhedron (col: %d).\n",
2086  val, SCIPvarGetName(var), nCols + 1 + nNewCols);
2087  ++nNewCols;
2088  }
2089  }
2090 
2091  /* add columns if necessary */
2092  if ( nNewCols > 0 )
2093  {
2094  SCIP_CALL( SCIPlpiAddCols(conshdlrdata->altlp, nNewCols, obj, lb, ub, NULL, cnt, matbeg, matind, matval) );
2095  }
2096 
2097 #ifndef NDEBUG
2098  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &cnt) );
2099  assert( cnt == nCols + nNewCols + 1 );
2100 #endif
2101 
2102  SCIPfreeBufferArray(scip, &ub);
2103  SCIPfreeBufferArray(scip, &lb);
2104  SCIPfreeBufferArray(scip, &obj);
2105  SCIPfreeBufferArray(scip, &matind);
2106  SCIPfreeBufferArray(scip, &matval);
2107  SCIPfreeBufferArray(scip, &matbeg);
2108  SCIPfreeBufferArray(scip, &newVars);
2109  SCIPfreeBufferArray(scip, &newRowsSlack);
2110 
2111  if ( slackvar != NULL && SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
2112  {
2113  SCIPfreeBufferArray(scip, &linvals);
2114  SCIPfreeBufferArray(scip, &linvars);
2115  }
2116  conshdlrdata->scaled = FALSE;
2117 
2118 #ifdef SCIP_OUTPUT
2119  SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "alt.lp") );
2120 #endif
2121 
2122  return SCIP_OKAY;
2123 }
2124 
2125 
2126 /** add column corresponding to row to alternative LP
2127  *
2128  * See the description at the top of the file for more information.
2129  */
2130 static
2132  SCIP* scip, /**< SCIP pointer */
2133  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2134  SCIP_ROW* row, /**< row to add */
2135  SCIP_Real objcoef, /**< objective coefficient */
2136  int* colindex /**< index of new column */
2137  )
2138 {
2139  SCIP_CONSHDLRDATA* conshdlrdata;
2140  SCIP_VAR** newVars;
2141  SCIP_COL** rowcols;
2142  SCIP_Real* rowvals;
2143  SCIP_Real rowrhs;
2144  SCIP_Real rowlhs;
2145  SCIP_Real val;
2146  SCIP_Real sign;
2147  int* matbeg;
2148  int* matind;
2149  SCIP_Real* matval;
2150  SCIP_Bool* newRowsSlack;
2151  SCIP_Real* obj;
2152  SCIP_Real* lb;
2153  SCIP_Real* ub;
2154  int nrowcols;
2155  int nNewVars;
2156  int nNewCols;
2157  int nNewRows;
2158  int nCols;
2159  int cnt;
2160  int v;
2161 
2162  assert( scip != NULL );
2163  assert( conshdlr != NULL );
2164  assert( row != NULL );
2165  assert( colindex != NULL );
2166 
2167  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2168 
2169  /* exit if row is not global */
2170  if ( SCIProwIsLocal(row) )
2171  return SCIP_OKAY;
2172 
2173  /* initialize data */
2174  *colindex = -1;
2175  sign = 1.0;
2176  nNewVars = 0;
2177  nNewRows = 0;
2178  cnt = 0;
2179 
2180  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2181  assert( conshdlrdata != NULL );
2182 
2183  if ( conshdlrdata->altlp == NULL )
2184  {
2185  SCIP_CALL( initAlternativeLP(scip, conshdlr) );
2186  }
2187  assert( conshdlrdata->varhash != NULL );
2188  assert( conshdlrdata->lbhash != NULL );
2189  assert( conshdlrdata->ubhash != NULL );
2190  assert( conshdlrdata->slackhash != NULL );
2191 
2192 #ifndef NDEBUG
2193  {
2194  int nrows;
2195  SCIP_CALL( SCIPlpiGetNRows(conshdlrdata->altlp, &nrows) );
2196  assert( nrows == conshdlrdata->nrows );
2197  }
2198 #endif
2199 
2200  /* get row data */
2201  rowcols = SCIProwGetCols(row);
2202  rowvals = SCIProwGetVals(row);
2203  nrowcols = SCIProwGetNNonz(row);
2204  rowlhs = SCIProwGetLhs(row) - SCIProwGetConstant(row);
2205  rowrhs = SCIProwGetRhs(row) - SCIProwGetConstant(row);
2206 
2207  SCIP_CALL( SCIPallocBufferArray(scip, &matbeg, nrowcols) );
2208  SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4*nrowcols) );
2209  SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4*nrowcols) );
2210  SCIP_CALL( SCIPallocBufferArray(scip, &obj, 2*nrowcols) );
2211  SCIP_CALL( SCIPallocBufferArray(scip, &lb, 2*nrowcols) );
2212  SCIP_CALL( SCIPallocBufferArray(scip, &ub, 2*nrowcols) );
2213  SCIP_CALL( SCIPallocBufferArray(scip, &newVars, nrowcols) );
2214  SCIP_CALL( SCIPallocBufferArray(scip, &newRowsSlack, 2 * nrowcols) );
2215 
2216  /* store index of column in constraint */
2217  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &nCols) );
2218  *colindex = nCols;
2219 
2220  /* adapt rhs of linear constraint */
2221  val = rowrhs;
2222  if ( SCIPisInfinity(scip, val) )
2223  {
2224  val = rowlhs;
2225  assert( val > -SCIPinfinity(scip) );
2226  sign = -1.0;
2227  }
2228 
2229  /* handle first row in alternative LP */
2230  if (! SCIPisFeasZero(scip, val) )
2231  {
2232  matind[cnt] = 0;
2233  matval[cnt] = sign * val;
2234  assert( ! SCIPisInfinity(scip, val) && ! SCIPisInfinity(scip, -val) );
2235  ++cnt;
2236  }
2237 
2238  /* set up column (recognize new original variables) */
2239  for (v = 0; v < nrowcols; ++v)
2240  {
2241  SCIP_VAR* var;
2242  assert( rowcols[v] != NULL );
2243  var = SCIPcolGetVar(rowcols[v]);
2244  assert( var != NULL );
2245 
2246  /* if variable is a slack variable */
2247  if ( SCIPhashmapExists(conshdlrdata->slackhash, var) )
2248  {
2249  int ind;
2250 
2251  ind = (int) (size_t) SCIPhashmapGetImage(conshdlrdata->slackhash, var);
2252 
2253  if ( ind < INT_MAX )
2254  matind[cnt] = ind;
2255  else
2256  {
2257  /* add variable in map and array and remember to add a new row */
2258  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->slackhash, var, (void*) (size_t) conshdlrdata->nrows) );
2259  assert( conshdlrdata->nrows == (int) (size_t) SCIPhashmapGetImage(conshdlrdata->slackhash, var) );
2260  SCIPdebugMessage("Inserted slack variable <%s> into hashmap (row: %d).\n", SCIPvarGetName(var), conshdlrdata->nrows);
2261  matind[cnt] = (conshdlrdata->nrows)++;
2262 
2263  /* store new variables */
2264  newRowsSlack[nNewRows++] = TRUE;
2265  }
2266  assert( conshdlrdata->nrows >= (int) (size_t) SCIPhashmapGetImage(conshdlrdata->slackhash, var) );
2267  matval[cnt] = sign * rowvals[v];
2268  ++cnt;
2269  }
2270  else
2271  {
2272  /* if variable exists */
2273  if ( SCIPhashmapExists(conshdlrdata->varhash, var) )
2274  matind[cnt] = (int) (size_t) SCIPhashmapGetImage(conshdlrdata->varhash, var);
2275  else
2276  {
2277  /* add variable in map and array and remember to add a new row */
2278  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->varhash, var, (void*) (size_t) conshdlrdata->nrows) );
2279  assert( conshdlrdata->nrows == (int) (size_t) SCIPhashmapGetImage(conshdlrdata->varhash, var) );
2280  SCIPdebugMessage("Inserted variable <%s> into hashmap (row: %d).\n", SCIPvarGetName(var), conshdlrdata->nrows);
2281  matind[cnt] = (conshdlrdata->nrows)++;
2282 
2283  /* store new variables */
2284  newRowsSlack[nNewRows++] = FALSE;
2285  newVars[nNewVars++] = var;
2286  }
2287  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2288  matval[cnt] = sign * rowvals[v];
2289  ++cnt;
2290  }
2291  }
2292 
2293  /* add new rows */
2294  if ( nNewRows > 0 )
2295  {
2296  SCIP_Real* lhs;
2297  SCIP_Real* rhs;
2298  int i;
2299 
2300  SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nNewRows) );
2301  SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nNewRows) );
2302  for (i = 0; i < nNewRows; ++i)
2303  {
2304  if ( newRowsSlack[i] )
2305  lhs[i] = -SCIPlpiInfinity(conshdlrdata->altlp);
2306  else
2307  lhs[i] = 0.0;
2308  rhs[i] = 0.0;
2309  }
2310  /* add new rows */
2311  SCIP_CALL( SCIPlpiAddRows(conshdlrdata->altlp, nNewRows, lhs, rhs, NULL, 0, NULL, NULL, NULL) );
2312 
2313  SCIPfreeBufferArray(scip, &lhs);
2314  SCIPfreeBufferArray(scip, &rhs);
2315  }
2316 
2317  /* now add column */
2318  obj[0] = objcoef;
2319  lb[0] = 0.0;
2320  ub[0] = SCIPlpiInfinity(conshdlrdata->altlp);
2321  matbeg[0] = 0;
2322 
2323  /* create a free variable for equations */
2324  if ( SCIPisEQ(scip, rowlhs, rowrhs) )
2325  {
2326  lb[0] = -SCIPlpiInfinity(conshdlrdata->altlp);
2327  }
2328 
2329  SCIP_CALL( SCIPlpiAddCols(conshdlrdata->altlp, 1, obj, lb, ub, NULL, cnt, matbeg, matind, matval) );
2330 
2331  /* add columns corresponding to bounds of original variables - no bounds needed for slack vars */
2332  cnt = 0;
2333  nNewCols = 0;
2334  for (v = 0; v < nNewVars; ++v)
2335  {
2336  SCIP_VAR* var = newVars[v];
2337 
2338  /* if the lower bound is finite */
2339  val = SCIPvarGetLbGlobal(var);
2340  if ( ! SCIPisInfinity(scip, -val) )
2341  {
2342  matbeg[nNewCols] = cnt;
2343  if ( ! SCIPisZero(scip, val) )
2344  {
2345  matind[cnt] = 0;
2346  matval[cnt] = -val;
2347  ++cnt;
2348  }
2349  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2350  matind[cnt] = (int) (size_t) SCIPhashmapGetImage(conshdlrdata->varhash, var);
2351  matval[cnt] = -1.0;
2352  ++cnt;
2353  obj[nNewCols] = 0.0;
2354  lb[nNewCols] = 0.0;
2355  ub[nNewCols] = SCIPlpiInfinity(conshdlrdata->altlp);
2356  ++conshdlrdata->nlbbounds;
2357  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->lbhash, var, (void*) (size_t) (nCols + 1 + nNewCols)) );
2358  assert( SCIPhashmapExists(conshdlrdata->lbhash, var) );
2359  SCIPdebugMessage("added column corr. to lower bound (%f) of variable <%s> to alternative polyhedron (col: %d).\n",
2360  val, SCIPvarGetName(var), nCols + 1 + nNewCols);
2361  ++nNewCols;
2362  }
2363 
2364  /* if the upper bound is finite */
2365  val = SCIPvarGetUbGlobal(var);
2366  if ( ! SCIPisInfinity(scip, val) )
2367  {
2368  matbeg[nNewCols] = cnt;
2369  if ( ! SCIPisZero(scip, val) )
2370  {
2371  matind[cnt] = 0;
2372  matval[cnt] = val;
2373  ++cnt;
2374  }
2375  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2376  matind[cnt] = (int) (size_t) SCIPhashmapGetImage(conshdlrdata->varhash, var);
2377  matval[cnt] = 1.0;
2378  ++cnt;
2379  obj[nNewCols] = 0.0;
2380  lb[nNewCols] = 0.0;
2381  ub[nNewCols] = SCIPlpiInfinity(conshdlrdata->altlp);
2382  ++conshdlrdata->nubbounds;
2383  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->ubhash, var, (void*) (size_t) (nCols + 1 + nNewCols)) );
2384  assert( SCIPhashmapExists(conshdlrdata->ubhash, var) );
2385  SCIPdebugMessage("added column corr. to upper bound (%f) of variable <%s> to alternative polyhedron (col: %d).\n",
2386  val, SCIPvarGetName(var), nCols + 1 + nNewCols);
2387  ++nNewCols;
2388  }
2389  }
2390 
2391  /* add columns if necessary */
2392  if ( nNewCols > 0 )
2393  {
2394  SCIP_CALL( SCIPlpiAddCols(conshdlrdata->altlp, nNewCols, obj, lb, ub, NULL, cnt, matbeg, matind, matval) );
2395  }
2396 
2397 #ifndef NDEBUG
2398  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &cnt) );
2399  assert( cnt == nCols + nNewCols + 1 );
2400 #endif
2401 
2402  SCIPfreeBufferArray(scip, &ub);
2403  SCIPfreeBufferArray(scip, &lb);
2404  SCIPfreeBufferArray(scip, &obj);
2405  SCIPfreeBufferArray(scip, &matind);
2406  SCIPfreeBufferArray(scip, &matval);
2407  SCIPfreeBufferArray(scip, &matbeg);
2408  SCIPfreeBufferArray(scip, &newVars);
2409  SCIPfreeBufferArray(scip, &newRowsSlack);
2410 
2411  conshdlrdata->scaled = FALSE;
2412 
2413 #ifdef SCIP_OUTPUT
2414  SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "alt.lp") );
2415 #endif
2416 
2417  return SCIP_OKAY;
2418 }
2419 
2420 
2421 /** delete column corresponding to constraint in alternative LP
2422  *
2423  * We currently just fix the corresponding variable to 0.
2424  */
2425 static
2427  SCIP* scip, /**< SCIP pointer */
2428  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2429  SCIP_CONS* cons /**< indicator constraint */
2430  )
2431 {
2432  SCIP_CONSHDLRDATA* conshdlrdata;
2433 
2434  assert( scip != NULL );
2435  assert( conshdlr != NULL );
2436  assert( cons != NULL );
2437 
2438  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2439 
2440  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2441  assert( conshdlrdata != NULL );
2442 
2443  if ( conshdlrdata->altlp != NULL )
2444  {
2445  SCIP_CONSDATA* consdata;
2446 
2447  SCIPdebugMessage("Deleting column from alternative LP ...\n");
2448 
2449  consdata = SCIPconsGetData(cons);
2450  assert( consdata != NULL );
2451 
2452  if ( consdata->colindex >= 0 )
2453  {
2454  SCIP_CALL( fixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
2455  }
2456  consdata->colindex = -1;
2457  }
2458  conshdlrdata->scaled = FALSE;
2459 
2460  return SCIP_OKAY;
2461 }
2462 
2463 
2464 /** Check whether the given LP is infeasible
2465  *
2466  * If @a primal is false we assume that the problem is <em>dual feasible</em>, e.g., the problem
2467  * was only changed by fixing bounds!
2468  *
2469  * This is the workhorse for all methods that have to solve the alternative LP. We try in several
2470  * ways to recover from possible stability problems.
2471  *
2472  * @pre It is assumed that all parameters for the alternative LP are set.
2473  */
2474 static
2476  SCIP* scip, /**< SCIP pointer */
2477  SCIP_LPI* lp, /**< LP */
2478  SCIP_Real maxcondition, /**< maximal allowed condition of LP solution basis matrix */
2479  SCIP_Bool primal, /**< whether we are using the primal or dual simplex */
2480  SCIP_Bool* infeasible, /**< output: whether the LP is infeasible */
2481  SCIP_Bool* error /**< output: whether an error occured */
2482  )
2483 {
2484  SCIP_RETCODE retcode;
2485  SCIP_Real condition;
2486 
2487  assert( scip != NULL );
2488  assert( lp != NULL );
2489  assert( infeasible != NULL );
2490  assert( error != NULL );
2491 
2492  *error = FALSE;
2493 
2494  /* solve LP */
2495  if ( primal )
2496  retcode = SCIPlpiSolvePrimal(lp); /* use primal simplex */
2497  else
2498  retcode = SCIPlpiSolveDual(lp); /* use dual simplex */
2499  if ( retcode == SCIP_LPERROR )
2500  {
2501  *error = TRUE;
2502  return SCIP_OKAY;
2503  }
2504  SCIP_CALL( retcode );
2505 
2506  /* resolve if LP is not stable */
2507  if ( ! SCIPlpiIsStable(lp) )
2508  {
2511  SCIPwarningMessage(scip, "Numerical problems, retrying ...\n");
2512 
2513  /* re-solve LP */
2514  if ( primal )
2515  retcode = SCIPlpiSolvePrimal(lp); /* use primal simplex */
2516  else
2517  retcode = SCIPlpiSolveDual(lp); /* use dual simplex */
2518 
2519  if ( retcode == SCIP_LPERROR )
2520  {
2521  /* reset parameters */
2524 
2525  *error = TRUE;
2526  return SCIP_OKAY;
2527  }
2528  SCIP_CALL( retcode );
2529 
2530  /* reset parameters */
2533  }
2534 
2535  /* check whether we want to ignore the result, because the condition number is too large */
2536  if ( maxcondition > 0.0 )
2537  {
2538  /* check estimated condition number of basis matrix */
2540  if ( condition != SCIP_INVALID && condition > maxcondition ) /*lint !e777*/
2541  {
2542  SCIPdebugMessage("estim. condition number of basis matrix (%e) exceeds maximal allowance (%e).\n", condition, maxcondition);
2543 
2544  *error = TRUE;
2545 
2546  return SCIP_OKAY;
2547  }
2548  else if ( condition != SCIP_INVALID ) /*lint !e777*/
2549  {
2550  SCIPdebugMessage("estim. condition number of basis matrix (%e) is below maximal allowance (%e).\n", condition, maxcondition);
2551  }
2552  else
2553  {
2554  SCIPdebugMessage("estim. condition number of basis matrix not available.\n");
2555  }
2556  }
2557 
2558  /* check whether we are in the paradoxical situation that
2559  * - the primal is not infeasible
2560  * - the primal is not unbounded
2561  * - the LP is not optimal
2562  * - we have a primal ray
2563  *
2564  * If we ran the dual simplex algorithm, then we run again with the primal simplex
2565  */
2567  ! SCIPlpiIsOptimal(lp) && SCIPlpiExistsPrimalRay(lp) && !primal )
2568  {
2569  SCIPwarningMessage(scip, "The dual simplex produced a primal ray. Retrying with primal ...\n");
2570  /* the following settings might be changed: */
2574 
2575  SCIP_CALL( SCIPlpiSolvePrimal(lp) ); /* use primal simplex */
2576 
2577  /* reset parameters */
2581  }
2582 
2583  /* examine LP solution status */
2584  if ( SCIPlpiIsPrimalInfeasible(lp) ) /* the LP is provably infeasible */
2585  {
2586  assert( ! SCIPlpiIsPrimalUnbounded(lp) ); /* can't be unbounded or optimal */
2587  assert( ! SCIPlpiIsOptimal(lp) ); /* if it is infeasible! */
2588  *infeasible = TRUE; /* LP is infeasible */
2589  return SCIP_OKAY;
2590  }
2591  else
2592  {
2593  /* By assumption the dual is feasible if the dual simplex is run, therefore
2594  * the status has to be primal unbounded or optimal. */
2595  if ( ! SCIPlpiIsPrimalUnbounded(lp) && ! SCIPlpiIsOptimal(lp) )
2596  {
2597  /* We have a status different from unbounded or optimal. This should not be the case ... */
2598  if (primal)
2599  {
2600  SCIPwarningMessage(scip, "Primal simplex returned with unknown status: %d\n", SCIPlpiGetInternalStatus(lp));
2601  }
2602  else
2603  {
2604  SCIPwarningMessage(scip, "Dual simplex returned with unknown status: %d\n", SCIPlpiGetInternalStatus(lp));
2605  }
2606  /* SCIP_CALL( SCIPlpiWriteLP(lp, "debug.lp") ); */
2607  *error = TRUE;
2608  return SCIP_OKAY;
2609  }
2610  }
2611 
2612  /* at this point we have a feasible solution */
2613  *infeasible = FALSE;
2614  return SCIP_OKAY;
2615 }
2616 
2617 
2618 /** Tries to extend a given set of variables to a cover.
2619  *
2620  * At each step we include a variable which covers a new IIS. Ties are broken according to the
2621  * number of IISs a variable is contained in. The corresponding IIS inequalities are added to the
2622  * LP if this not already happened.
2623  *
2624  * @pre It is assumed that all parameters for the alternative LP are set and that the variables
2625  * corresponding to @a S are fixed. Furthermore @c xVal_ should contain the current LP solution.
2626  */
2627 static
2629  SCIP* scip, /**< SCIP pointer */
2630  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2631  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler */
2632  SCIP_LPI* lp, /**< LP */
2633  SCIP_SOL* sol, /**< solution to be separated */
2634  SCIP_Bool removable, /**< whether cuts should be removable */
2635  SCIP_Bool genlogicor, /**< should logicor constraints be generated? */
2636  int nconss, /**< number of constraints */
2637  SCIP_CONS** conss, /**< indicator constraints */
2638  SCIP_Bool* S, /**< bitset of variables */
2639  int* size, /**< size of S */
2640  SCIP_Real* value, /**< objective value of S */
2641  SCIP_Bool* error, /**< output: whether an error occured */
2642  int* nGen /**< number of generated cuts */
2643  )
2644 {
2645  SCIP_Real* primsol;
2646  int step;
2647  int nCols;
2648 
2649  assert( scip != NULL );
2650  assert( lp != NULL );
2651  assert( conss != NULL );
2652  assert( S != NULL );
2653  assert( size != NULL );
2654  assert( value != NULL );
2655  assert( nGen != NULL );
2656 
2657  SCIP_CALL( SCIPlpiGetNCols(lp, &nCols) );
2658  SCIP_CALL( SCIPallocBufferArray(scip, &primsol, nCols) );
2659  assert( nconss <= nCols );
2660 
2661  step = 0;
2662  *nGen = 0;
2663  *error = FALSE;
2664  do
2665  {
2666  SCIP_Bool infeasible;
2667  SCIP_Real sum;
2668  int sizeIIS;
2669  int candidate;
2670  int candIndex;
2671  SCIP_Real candObj;
2672  int j;
2673 
2674  sum = 0.0;
2675  sizeIIS = 0;
2676  candidate = -1;
2677  candIndex = -1;
2678  candObj = -1.0;
2679 
2680  if ( step == 0 )
2681  {
2682  /* the first LP is solved without warm start, after that we use a warmstart. */
2684  SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, TRUE, &infeasible, error) );
2686  }
2687  else
2688  SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, FALSE, &infeasible, error) );
2689 
2690  if ( *error )
2691  break;
2692 
2693  /* if the alternative polyhedron is infeasible, we found a cover */
2694  if ( infeasible )
2695  {
2696  if ( conshdlrdata->trysolfromcover )
2697  {
2698  /* Check whether we want to try to construct a feasible solution: there should be no integer/binary variables
2699  * except the indicator variables. Thus, there should be no integral variables and the number of indicator
2700  * variables should at least (actually equal to) the number of binary variables. */
2701  if ( SCIPgetNIntVars(scip) == 0 && nconss >= SCIPgetNBinVars(scip) )
2702  {
2703  SCIP_Bool lperror;
2704  SCIP_Bool cutoff;
2705 
2706  SCIP_CALL( SCIPstartProbing(scip) );
2707 
2708  /* fix variables */
2709  for (j = 0; j < nconss; ++j)
2710  {
2711  SCIP_CONSDATA* consdata;
2712  SCIP_VAR* binvar;
2713 
2714  assert( SCIPconsIsActive(conss[j]) );
2715  consdata = SCIPconsGetData(conss[j]);
2716  assert( consdata != NULL );
2717  binvar = consdata->binvar;
2718  assert( binvar != NULL );
2719 
2720  /* Fix binary variables not in cover to 1 and corresponding slack variables to 0. The other binary variables
2721  * are fixed to 0 */
2722  if ( ! S[j] )
2723  {
2724  SCIP_VAR* slackvar;
2725 
2726  /* to be sure check for non-fixed variables */
2727  if ( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 )
2728  {
2729  SCIP_CALL( SCIPchgVarLbProbing(scip, binvar, 1.0) );
2730  }
2731 
2732  /* also fix slack variables to 0, because we cannot propagate below */
2733  slackvar = consdata->slackvar;
2734  assert( slackvar != NULL );
2735  if ( SCIPisFeasPositive(scip, SCIPvarGetUbLocal(slackvar)) )
2736  {
2737  SCIP_CALL( SCIPchgVarUbProbing(scip, slackvar, 0.0) );
2738  }
2739  }
2740  else
2741  {
2742  if ( SCIPvarGetUbLocal(binvar) > 0.5 && SCIPvarGetLbLocal(binvar) < 0.5 )
2743  {
2744  SCIP_CALL( SCIPchgVarUbProbing(scip, binvar, 0.0) );
2745  }
2746  }
2747  }
2748 
2749  /* Cannot call SCIPpropagateProbing() within separation - thus, we had to fix the slack variables above. */
2750  SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &cutoff) );
2751 
2752  /* the lp often reaches the objective limit - we currently do not use such solutions */
2753  if ( ! lperror && ! cutoff && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
2754  {
2755  SCIP_HEUR* trysol;
2756  SCIP_Bool stored;
2757  SCIP_SOL* psol;
2758 
2759  trysol = SCIPfindHeur(scip, "trysol");
2760  SCIP_CALL( SCIPcreateSol(scip, &psol, trysol) );
2761 
2762  /* copy the current LP solution to the working solution */
2763  SCIP_CALL( SCIPlinkLPSol(scip, psol) );
2764 
2765  /* check solution for feasibility, and add it to solution store if possible neither integrality nor
2766  * feasibility of LP rows has to be checked, because this is already done in the intshifting heuristic
2767  * itself and due to the LP resolve */
2768  SCIP_CALL( SCIPtrySol(scip, psol, TRUE, FALSE, TRUE, FALSE, &stored) );
2769 
2770  if ( stored )
2771  {
2772  SCIPdebugMessage("found feasible shifted solution:\n");
2773  SCIPdebug( SCIP_CALL( SCIPprintSol(scip, psol, NULL, FALSE) ) );
2774  }
2775  SCIP_CALL( SCIPfreeSol(scip, &psol) );
2776  }
2777 
2778  SCIP_CALL( SCIPendProbing(scip) );
2779  }
2780  }
2781  break;
2782  }
2783 
2784  /* get solution of alternative LP */
2785  SCIP_CALL( SCIPlpiGetSol(lp, NULL, primsol, NULL, NULL, NULL) );
2786 
2787  /* get value of cut and find candidate for variable to add */
2788  for (j = 0; j < nconss; ++j)
2789  {
2790  SCIP_CONSDATA* consdata;
2791  int ind;
2792 
2793  consdata = SCIPconsGetData(conss[j]);
2794  assert( consdata != NULL );
2795  ind = consdata->colindex;
2796 
2797  if ( ind >= 0 )
2798  {
2799  assert( ind < nCols );
2800 
2801  /* check support of the solution, i.e., the corresponding IIS */
2802  if ( ! SCIPisFeasZero(scip, primsol[ind]) )
2803  {
2804  assert( ! S[j] );
2805  ++sizeIIS;
2806  sum += SCIPgetSolVal(scip, sol, consdata->binvar);
2807  /* take first element */
2808  if ( candidate < 0 )
2809  {
2810  candidate = j;
2811  candIndex = ind;
2812  candObj = varGetObjDelta(consdata->binvar);
2813  }
2814  }
2815  }
2816  }
2817 
2818  /* check for error */
2819  if ( candidate < 0 )
2820  {
2821  /* Because of numerical problem it might happen that the solution primsol above is zero
2822  * within the tolerances. In this case we quit. */
2823  break;
2824  }
2825  assert( candidate >= 0 );
2826  assert( ! S[candidate] );
2827 
2828  /* update new set S */
2829  SCIPdebugMessage(" size: %4d add %4d with objective value %f and alt-LP solution value %g (IIS size: %d)\n", *size, candidate, candObj, primsol[SCIPconsGetData(conss[candidate])->colindex], sizeIIS);
2830  S[candidate] = TRUE;
2831  ++(*size);
2832  *value += candObj;
2833 
2834  /* fix chosen variable to 0 */
2835  SCIP_CALL( fixAltLPVariable(lp, candIndex) );
2836 
2837  /* if cut is violated, i.e., sum - sizeIIS + 1 > 0 */
2838  if ( SCIPisEfficacious(scip, sum - (SCIP_Real) (sizeIIS - 1)) )
2839  {
2840  SCIP_Bool isLocal;
2841 
2842 #ifdef SCIP_ENABLE_IISCHECK
2843  /* check whether we really have an infeasible subsystem */
2844  SCIP_CALL( checkIIS(scip, nconss, conss, primsol) );
2845 #endif
2846 
2847  /* check whether IIS corresponds to a local cut */
2848  SCIP_CALL( checkIISlocal(scip, conshdlrdata, primsol, &isLocal) );
2849 
2850  if ( genlogicor )
2851  {
2852  SCIP_CONS* cons;
2853  SCIP_VAR** vars;
2854  int cnt;
2855 
2856  cnt = 0;
2857 
2858  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nconss) );
2859 
2860  /* collect variables corresponding to support to cut */
2861  for (j = 0; j < nconss; ++j)
2862  {
2863  int ind;
2864  SCIP_CONSDATA* consdata;
2865 
2866  consdata = SCIPconsGetData(conss[j]);
2867  ind = consdata->colindex;
2868 
2869  if ( ind >= 0 )
2870  {
2871  assert( ind < nCols );
2872  assert( consdata->binvar != NULL );
2873 
2874  /* check support of the solution, i.e., the corresponding IIS */
2875  if ( ! SCIPisFeasZero(scip, primsol[ind]) )
2876  {
2877  SCIP_VAR* var;
2878  SCIP_CALL( SCIPgetNegatedVar(scip, consdata->binvar, &var) );
2879  vars[cnt++] = var;
2880  }
2881  }
2882  }
2883  assert( cnt == sizeIIS );
2884 
2885  SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, "iis", cnt, vars, FALSE, TRUE, TRUE, TRUE, TRUE, isLocal, FALSE, TRUE, removable, FALSE) );
2886 
2887 #ifdef SCIP_OUTPUT
2888  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2889  SCIPinfoMessage(scip, NULL, ";\n");
2890 #endif
2891 
2892  SCIP_CALL( SCIPaddCons(scip, cons) );
2893  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2894 
2895  SCIPfreeBufferArray(scip, &vars);
2896  ++(*nGen);
2897  }
2898  else
2899  {
2900  SCIP_ROW* row;
2901  SCIP_Bool rowinfeasible;
2902 
2903  /* create row */
2904  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conshdlr, "iis", -SCIPinfinity(scip), (SCIP_Real) (sizeIIS - 1), isLocal, FALSE, removable) );
2905  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
2906 
2907  /* add variables corresponding to support to cut */
2908  for (j = 0; j < nconss; ++j)
2909  {
2910  int ind;
2911  SCIP_CONSDATA* consdata;
2912 
2913  consdata = SCIPconsGetData(conss[j]);
2914  ind = consdata->colindex;
2915 
2916  if ( ind >= 0 )
2917  {
2918  assert( ind < nCols );
2919  assert( consdata->binvar != NULL );
2920 
2921  /* check support of the solution, i.e., the corresponding IIS */
2922  if ( ! SCIPisFeasZero(scip, primsol[ind]) )
2923  {
2924  SCIP_VAR* var = consdata->binvar;
2925  SCIP_CALL( SCIPaddVarToRow(scip, row, var, 1.0) );
2926  }
2927  }
2928  }
2929  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
2930 #ifdef SCIP_OUTPUT
2931  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
2932 #endif
2933  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, &rowinfeasible) );
2934  assert( ! rowinfeasible );
2935 
2936  /* cut should be violated: */
2937  assert( SCIPisFeasNegative(scip, SCIPgetRowSolFeasibility(scip, row, sol)) );
2938 
2939  /* add cuts to pool if they are globally valid */
2940  if ( ! isLocal )
2941  SCIP_CALL( SCIPaddPoolCut(scip, row) );
2942  SCIP_CALL( SCIPreleaseRow(scip, &row));
2943  ++(*nGen);
2944  }
2945  }
2946  ++step;
2947  }
2948  while (step < nconss);
2949 
2950  SCIPfreeBufferArray(scip, &primsol);
2951 
2952  return SCIP_OKAY;
2953 }
2954 
2955 
2956 /* ---------------------------- constraint handler local methods ----------------------*/
2957 
2958 /** creates and initializes consdata */
2959 static
2961  SCIP* scip, /**< SCIP data structure */
2962  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2963  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
2964  const char* consname, /**< name of constraint (or NULL) */
2965  SCIP_CONSDATA** consdata, /**< pointer to linear constraint data */
2966  SCIP_EVENTHDLR* eventhdlrbound, /**< event handler for bound change events */
2967  SCIP_EVENTHDLR* eventhdlrrestart, /**< event handler for handling restarts */
2968  SCIP_VAR* binvar, /**< binary variable (or NULL) */
2969  SCIP_VAR* slackvar, /**< slack variable */
2970  SCIP_CONS* lincons, /**< linear constraint (or NULL) */
2971  SCIP_Bool linconsactive /**< whether the linear constraint is active */
2972  )
2973 {
2974  assert( scip != NULL );
2975  assert( conshdlr != NULL );
2976  assert( conshdlrdata != NULL );
2977  assert( consdata != NULL );
2978  assert( slackvar != NULL );
2979  assert( eventhdlrbound != NULL );
2980  assert( eventhdlrrestart != NULL );
2981 
2982  /* create constraint data */
2983  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
2984  (*consdata)->nfixednonzero = 0;
2985  (*consdata)->colindex = -1;
2986  (*consdata)->linconsactive = linconsactive;
2987  (*consdata)->binvar = binvar;
2988  (*consdata)->slackvar = slackvar;
2989  (*consdata)->lincons = lincons;
2990  (*consdata)->implicationadded = FALSE;
2991  (*consdata)->slacktypechecked = FALSE;
2992 
2993  /* if we are transformed, obtain transformed variables and catch events */
2994  if ( SCIPisTransformed(scip) )
2995  {
2996  SCIP_VAR* var;
2997 
2998  /* handle binary variable */
2999  if ( binvar != NULL )
3000  {
3001  SCIP_CALL( SCIPgetTransformedVar(scip, binvar, &var) );
3002  assert( var != NULL );
3003  (*consdata)->binvar = var;
3004 
3005  /* check type */
3006  if ( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY )
3007  {
3008  SCIPerrorMessage("Indicator variable <%s> is not binary %d.\n", SCIPvarGetName(var), SCIPvarGetType(var));
3009  return SCIP_ERROR;
3010  }
3011 
3012  /* catch local bound change events on binary variable */
3013  if ( linconsactive )
3014  {
3015  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlrbound, (SCIP_EVENTDATA*)*consdata, NULL) );
3016  }
3017 
3018  /* catch global bound change events on binary variable */
3019  if ( conshdlrdata->forcerestart )
3020  {
3021  SCIPdebugMessage("Catching GBDCHANGED event for <%s>.\n", SCIPvarGetName(var));
3022  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
3023  }
3024 
3025  /* if binary variable is fixed to be nonzero */
3026  if ( SCIPvarGetLbLocal(var) > 0.5 )
3027  ++((*consdata)->nfixednonzero);
3028  }
3029 
3030  /* handle slack variable */
3031  SCIP_CALL( SCIPgetTransformedVar(scip, slackvar, &var) );
3032  assert( var != NULL );
3033  (*consdata)->slackvar = var;
3034 
3035  /* catch bound change events on slack variable and adjust nfixednonzero */
3036  if ( linconsactive )
3037  {
3038  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlrbound, (SCIP_EVENTDATA*)*consdata, NULL) );
3039 
3040  /* if slack variable is fixed to be nonzero */
3041  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) )
3042  ++((*consdata)->nfixednonzero);
3043  }
3044 
3045  /* add corresponding column to alternative LP if the constraint is new */
3046  if ( conshdlrdata->sepaalternativelp && SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && lincons != NULL )
3047  {
3048  assert( lincons != NULL );
3049  assert( consname != NULL );
3050  SCIPdebugMessage("Adding column for <%s> to alternative LP ...\n", consname);
3051 #ifdef SCIP_OUTPUT
3052  SCIP_CALL( SCIPprintCons(scip, lincons, NULL) );
3053  SCIPinfoMessage(scip, NULL, ";\n");
3054 #endif
3055  SCIP_CALL( addAltLPConstraint(scip, conshdlr, lincons, var, 1.0, &(*consdata)->colindex) );
3056  SCIPdebugMessage("Colum index for <%s>: %d\n", consname, (*consdata)->colindex);
3057  }
3058 
3059 #ifdef SCIP_DEBUG
3060  if ( (*consdata)->nfixednonzero > 0 )
3061  {
3062  SCIPdebugMessage("constraint <%s> has %d variables fixed to be nonzero.\n", consname, (*consdata)->nfixednonzero);
3063  }
3064 #endif
3065  }
3066 
3067  /* capture slack variable and linear constraint */
3068  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->slackvar) );
3069  SCIP_CALL( SCIPcaptureCons(scip, (*consdata)->lincons) );
3070 
3071  return SCIP_OKAY;
3072 }
3073 
3074 
3075 /** create variable upper bounds for constraints */
3076 static
3078  SCIP* scip, /**< SCIP pointer */
3079  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3080  SCIP_CONS** conss, /**< constraints */
3081  int nconss, /**< number of constraints */
3082  int* ngen /**< number of successful operations */
3083  )
3084 {
3085  char name[50];
3086  int c;
3087 
3088  assert( scip != NULL );
3089  assert( conshdlrdata != NULL );
3090  assert( ngen != NULL );
3091 
3092  *ngen = 0;
3093 
3094  /* check each constraint */
3095  for (c = 0; c < nconss; ++c)
3096  {
3097  SCIP_CONSDATA* consdata;
3098  SCIP_Real ub;
3099 
3100  consdata = SCIPconsGetData(conss[c]);
3101  assert( consdata != NULL );
3102 
3103  ub = SCIPvarGetUbGlobal(consdata->slackvar);
3104  assert( ! SCIPisNegative(scip, ub) );
3105 
3106  /* insert corresponding row if helpful and coefficient is not too large */
3107  if ( ub <= conshdlrdata->maxcouplingvalue )
3108  {
3109  SCIP_CONS* cons;
3110 
3111 #ifndef NDEBUG
3112  (void) SCIPsnprintf(name, 50, "couple%d", c);
3113 #else
3114  name[0] = '\0';
3115 #endif
3116 
3117  SCIPdebugMessage("Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
3118 
3119  /* add variable upper bound:
3120  * - check constraint if we remove the indicator constraint afterwards
3121  * - constraint is dynamic if we do not remove indicator constraints
3122  * - constraint is removable if we do not remove indicator constraints
3123  */
3124  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
3125  TRUE, TRUE, TRUE, conshdlrdata->removeindicators, TRUE, FALSE, FALSE,
3126  !conshdlrdata->removeindicators, !conshdlrdata->removeindicators, FALSE) );
3127 
3128  SCIP_CALL( SCIPaddCons(scip, cons) );
3129  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3130 
3131  /* remove indicator constraint if required */
3132  if ( conshdlrdata->removeindicators )
3133  {
3134  SCIPdebugMessage("Removing indicator constraint <%s>.\n", SCIPconsGetName(conss[c]));
3135  assert( ! SCIPconsIsModifiable(conss[c]) );
3136 
3137  /* mark linear constraint to be upgrade-able */
3138  if ( SCIPconsIsActive(consdata->lincons) )
3139  {
3140  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3141  assert(SCIPconsGetNUpgradeLocks(consdata->lincons) == 0);
3142  }
3143 
3144  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
3145  }
3146 
3147  ++(*ngen);
3148  }
3149  }
3150 
3151  return SCIP_OKAY;
3152 }
3153 
3154 
3155 /** perform one presolving round */
3156 static
3158  SCIP* scip, /**< SCIP pointer */
3159  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3160  SCIP_CONS* cons, /**< constraint */
3161  SCIP_CONSDATA* consdata, /**< constraint data */
3162  SCIP_Bool dualreductions, /**< should dual reductions be performed? */
3163  SCIP_Bool* cutoff, /**< whether a cutoff happened */
3164  SCIP_Bool* success, /**< whether we performed a successful reduction */
3165  int* ndelconss, /**< number of deleted constraints */
3166  int* nfixedvars /**< number of fixed variables */
3167  )
3168 {
3169  SCIP_Bool infeasible;
3170  SCIP_Bool fixed;
3171 
3172  assert( scip != NULL );
3173  assert( cons != NULL );
3174  assert( consdata != NULL );
3175  assert( cutoff != NULL );
3176  assert( success != NULL );
3177  assert( ndelconss != NULL );
3178  assert( nfixedvars != NULL );
3179  assert( consdata->binvar != NULL );
3180  assert( consdata->slackvar != NULL );
3181 
3182  *cutoff = FALSE;
3183  *success = FALSE;
3184 
3185  /* if the binary variable is fixed to nonzero */
3186  if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3187  {
3188  SCIPdebugMessage("Presolving <%s>: Binary variable fixed to 1.\n", SCIPconsGetName(cons));
3189 
3190  /* if slack variable is fixed to nonzero, we are infeasible */
3191  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3192  {
3193  SCIPdebugMessage("The problem is infeasible: binary and slack variable are fixed to be nonzero.\n");
3194  *cutoff = TRUE;
3195  return SCIP_OKAY;
3196  }
3197 
3198  /* otherwise fix slack variable to 0 */
3199  SCIPdebugMessage("Fix slack variable to 0 and delete constraint.\n");
3200  SCIP_CALL( SCIPfixVar(scip, consdata->slackvar, 0.0, &infeasible, &fixed) );
3201  assert( ! infeasible );
3202  if ( fixed )
3203  ++(*nfixedvars);
3204 
3205  /* mark linear constraint to be update-able */
3206  if ( SCIPconsIsActive(consdata->lincons) )
3207  {
3208  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3209  assert(SCIPconsGetNUpgradeLocks(consdata->lincons) == 0);
3210  }
3211 
3212  /* delete indicator constraint (leave linear constraint) */
3213  assert( ! SCIPconsIsModifiable(cons) );
3214  SCIP_CALL( SCIPdelCons(scip, cons) );
3215  ++(*ndelconss);
3216  *success = TRUE;
3217  return SCIP_OKAY;
3218  }
3219 
3220  /* if the binary variable is fixed to zero */
3221  if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
3222  {
3223  SCIPdebugMessage("Presolving <%s>: Binary variable fixed to 0, deleting indicator constraint.\n", SCIPconsGetName(cons));
3224 
3225  /* mark linear constraint to be update-able */
3226  if ( SCIPconsIsActive(consdata->lincons) )
3227  {
3228  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3229  assert(SCIPconsGetNUpgradeLocks(consdata->lincons) == 0);
3230  }
3231 
3232  /* delete indicator constraint */
3233  assert( ! SCIPconsIsModifiable(cons) );
3234  SCIP_CALL( SCIPdelCons(scip, cons) );
3235  ++(*ndelconss);
3236  *success = TRUE;
3237  return SCIP_OKAY;
3238  }
3239 
3240  /* if the slack variable is fixed to nonzero */
3241  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3242  {
3243  SCIPdebugMessage("Presolving <%s>: Slack variable fixed to nonzero.\n", SCIPconsGetName(cons));
3244 
3245  /* if binary variable is fixed to nonzero, we are infeasible */
3246  if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3247  {
3248  SCIPdebugMessage("The problem is infeasible: binary and slack variable are fixed to be nonzero.\n");
3249  *cutoff = TRUE;
3250  return SCIP_OKAY;
3251  }
3252 
3253  /* otherwise fix binary variable to 0 */
3254  SCIPdebugMessage("Fix binary variable to 0 and delete indicator constraint.\n");
3255  SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
3256  assert( ! infeasible );
3257  if ( fixed )
3258  ++(*nfixedvars);
3259 
3260  /* mark linear constraint to be update-able */
3261  if ( SCIPconsIsActive(consdata->lincons) )
3262  {
3263  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3264  assert(SCIPconsGetNUpgradeLocks(consdata->lincons) == 0);
3265  }
3266 
3267  /* delete constraint */
3268  assert( ! SCIPconsIsModifiable(cons) );
3269  SCIP_CALL( SCIPdelCons(scip, cons) );
3270  ++(*ndelconss);
3271  *success = TRUE;
3272  return SCIP_OKAY;
3273  }
3274 
3275  /* if the slack variable is fixed to zero */
3276  if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3277  {
3278  /* perform dual reductions - if required */
3279  if ( dualreductions )
3280  {
3281  SCIP_VAR* binvar;
3282  SCIP_Real obj;
3283 
3284  /* check objective of binary variable */
3285  binvar = consdata->binvar;
3286  obj = varGetObjDelta(binvar);
3287 
3288  /* if obj = 0, we prefer fixing the binary variable to 1 (if possible) */
3289  if ( obj <= 0.0 )
3290  {
3291  /* In this case we would like to fix the binary variable to 1, if it is not locked up
3292  except by this indicator constraint. If more than one indicator constraint is
3293  effected, we have to hope that they are all fulfilled - in this case the last
3294  constraint will fix the binary variable to 1. */
3295  if ( SCIPvarGetNLocksUp(binvar) <= 1 )
3296  {
3297  if ( SCIPvarGetUbGlobal(binvar) > 0.5 )
3298  {
3299  SCIPdebugMessage("Presolving <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
3300  SCIP_CALL( SCIPfixVar(scip, binvar, 1.0, &infeasible, &fixed) );
3301  assert( ! infeasible );
3302  if ( fixed )
3303  ++(*nfixedvars);
3304  /* make sure that the other case does not occur */
3305  obj = -1.0;
3306  }
3307  }
3308  }
3309  if ( obj >= 0.0 )
3310  {
3311  /* In this case we would like to fix the binary variable to 0, if it is not locked down
3312  (should also have been performed by other dual reductions). */
3313  if ( SCIPvarGetNLocksDown(binvar) == 0 )
3314  {
3315  if ( SCIPvarGetLbGlobal(binvar) < 0.5 )
3316  {
3317  SCIPdebugMessage("Presolving <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
3318  SCIP_CALL( SCIPfixVar(scip, binvar, 0.0, &infeasible, &fixed) );
3319  assert( ! infeasible );
3320  if ( fixed )
3321  ++(*nfixedvars);
3322  }
3323  }
3324  }
3325  }
3326 
3327  SCIPdebugMessage("Presolving <%s>: Slack variable fixed to zero, delete redundant indicator constraint.\n", SCIPconsGetName(cons));
3328 
3329  /* mark linear constraint to be upgrade-able */
3330  if ( SCIPconsIsActive(consdata->lincons) )
3331  {
3332  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3333  assert(SCIPconsGetNUpgradeLocks(consdata->lincons) == 0);
3334  }
3335 
3336  /* delete constraint */
3337  assert( ! SCIPconsIsModifiable(cons) );
3338  SCIP_CALL( SCIPdelCons(scip, cons) );
3339  ++(*ndelconss);
3340  *success = TRUE;
3341  return SCIP_OKAY;
3342  }
3343 
3344  /* check whether indicator variable is aggregated */
3345  if ( SCIPvarGetStatus(consdata->binvar) == SCIP_VARSTATUS_AGGREGATED )
3346  {
3347  SCIP_Bool negated = FALSE;
3348  SCIP_VAR* var;
3349 
3350  /* possibly get representation of indicator variable by active variable */
3351  var = consdata->binvar;
3352  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
3353  assert( var == consdata->binvar || SCIPvarIsActive(var) || SCIPvarIsNegated(var) );
3354 
3355  /* we can replace the binary variable by the active variable if it is not negated */
3356  if ( var != consdata->binvar && ! negated )
3357  {
3358  SCIPdebugMessage("Indicator variable <%s> is aggregated and replaced by active/negated variable <%s>.\n", SCIPvarGetName(consdata->binvar), SCIPvarGetName(var) );
3359 
3360  /* we need to update the events and locks */
3361  assert( conshdlrdata->eventhdlrbound != NULL );
3362  SCIP_CALL( SCIPdropVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, -1) );
3363  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, NULL) );
3364 
3365  SCIP_CALL( SCIPaddVarLocks(scip, consdata->binvar, 0, -1) );
3366  SCIP_CALL( SCIPaddVarLocks(scip, var, 0, 1) );
3367 
3368  /* change binvary variable */
3369  consdata->binvar = var;
3370  }
3371  }
3372 
3373  /* check whether slack variable is aggregated */
3374  if ( SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_AGGREGATED )
3375  {
3377  SCIP_Real bound;
3378  SCIP_VAR* var;
3379 
3380  /* possibly get representation of slack variable by active variable */
3381  var = consdata->slackvar;
3382  bound = SCIPvarGetLbGlobal(var);
3383 
3384  SCIP_CALL( SCIPvarGetProbvarBound(&var, &bound, &boundtype) );
3385 
3386  /* we can replace the binary variable by the active variable if it is also a >= variable */
3387  if ( var != consdata->slackvar && boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisGE(scip, bound, 0.0) )
3388  {
3389  assert( SCIPvarIsActive(var) );
3390  SCIPdebugMessage("Slack variable <%s> is aggregated and replaced by active variable <%s>.\n", SCIPvarGetName(consdata->slackvar), SCIPvarGetName(var) );
3391 
3392  /* we need to update the events, locks, and captures */
3393  assert( conshdlrdata->eventhdlrbound != NULL );
3394  SCIP_CALL( SCIPdropVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, -1) );
3395  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, NULL) );
3396 
3397  SCIP_CALL( SCIPaddVarLocks(scip, consdata->slackvar, 0, -1) );
3398  SCIP_CALL( SCIPaddVarLocks(scip, var, 0, 1) );
3399 
3400  SCIP_CALL( SCIPreleaseVar(scip, &consdata->slackvar) );
3401  SCIP_CALL( SCIPcaptureVar(scip, var) );
3402 
3403  /* change slack variable */
3404  consdata->slackvar = var;
3405  }
3406  else if ( var == consdata->binvar )
3407  {
3408  /* check special case that aggregating variable is equal to the indicator variable */
3409  assert( SCIPisEQ(scip, bound, 0.0) || SCIPisEQ(scip, bound, 1.0) );
3410 
3411  /* if the lower bound is transformed to an upper bound, we have "y = 1 -> 1 - y = 0", i.e., the constraint is redundant */
3412  if ( boundtype == SCIP_BOUNDTYPE_UPPER )
3413  {
3414  SCIPdebugMessage("Slack variable <%s> is aggregated to negated indicator variable <%s> -> constraint redundant.\n",
3415  SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3416  assert( SCIPisEQ(scip, bound, 1.0) );
3417 
3418  /* delete constraint */
3419  assert( ! SCIPconsIsModifiable(cons) );
3420  SCIP_CALL( SCIPdelCons(scip, cons) );
3421  ++(*ndelconss);
3422  *success = TRUE;
3423  return SCIP_OKAY;
3424  }
3425  else
3426  {
3427  /* 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 */
3428  SCIPdebugMessage("Slack variable <%s> is aggregated to the indicator variable <%s> -> fix indicator variable to 0.\n",
3429  SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3430  assert( boundtype == SCIP_BOUNDTYPE_LOWER );
3431  assert( SCIPisEQ(scip, bound, 0.0) );
3432 
3433  SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
3434  assert( ! infeasible );
3435 
3436  if ( fixed )
3437  ++(*nfixedvars);
3438 
3439  SCIP_CALL( SCIPdelCons(scip, cons) );
3440 
3441  ++(*ndelconss);
3442  *success = TRUE;
3443 
3444  return SCIP_OKAY;
3445  }
3446  }
3447  }
3448 
3449  /* Note that because of possible multi-aggregation we cannot simply remove the indicator
3450  * constraint if the linear constraint is not active or disabled - see the note in @ref
3451  * PREPROC.
3452  */
3453 
3454  return SCIP_OKAY;
3455 }
3456 
3457 
3458 /** propagate indicator constraint */
3459 static
3461  SCIP* scip, /**< SCIP pointer */
3462  SCIP_CONS* cons, /**< constraint */
3463  SCIP_CONSDATA* consdata, /**< constraint data */
3464  SCIP_Bool dualreductions, /**< should dual reductions be performed? */
3465  SCIP_Bool addopposite, /**< add opposite inequalities if binary var = 0? */
3466  SCIP_Bool* cutoff, /**< whether a cutoff happened */
3467  int* nGen /**< number of domain changes */
3468  )
3469 {
3470  SCIP_Bool infeasible;
3471  SCIP_Bool tightened;
3472 
3473  assert( scip != NULL );
3474  assert( cons != NULL );
3475  assert( consdata != NULL );
3476  assert( cutoff != NULL );
3477  assert( nGen != NULL );
3478 
3479  *cutoff = FALSE;
3480  *nGen = 0;
3481 
3482  /* if the linear constraint has not been generated, we do nothing */
3483  if ( ! consdata->linconsactive )
3484  return SCIP_OKAY;
3485 
3486  assert( consdata->slackvar != NULL );
3487  assert( consdata->binvar != NULL );
3488  assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(consdata->slackvar), 0.0) );
3489 
3490  /* if both slackvar and binvar are fixed to be nonzero */
3491  if ( consdata->nfixednonzero > 1 )
3492  {
3493  SCIPdebugMessage("the node is infeasible, both the slack variable and the binary variable are fixed to be nonzero.\n");
3494  *cutoff = TRUE;
3495 
3496  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3497  assert( SCIPvarGetLbLocal(consdata->binvar) > 0.5 );
3498  assert( SCIPisPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) );
3499 
3500  /* check if conflict analysis is turned on */
3501  if ( ! SCIPisConflictAnalysisApplicable(scip) )
3502  return SCIP_OKAY;
3503 
3504  /* conflict analysis can only be applied in solving stage */
3505  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
3506 
3507  /* perform conflict analysis */
3509  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->binvar) );
3510  SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, NULL) );
3511  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
3512 
3513  return SCIP_OKAY;
3514  }
3515 
3516  /* if exactly one of the variables is fixed to be nonzero */
3517  if ( consdata->nfixednonzero == 1 )
3518  {
3519  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
3520  if ( !SCIPinRepropagation(scip) )
3521  SCIP_CALL( SCIPincConsAge(scip, cons) );
3522 
3523  /* if binvar is fixed to be nonzero */
3524  if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3525  {
3526  assert( SCIPvarGetStatus(consdata->slackvar) != SCIP_VARSTATUS_MULTAGGR );
3527 
3528  /* if slack variable is not already fixed to 0 */
3529  if ( ! SCIPisZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3530  {
3531  SCIPdebugMessage("binary variable <%s> is fixed to be nonzero, fixing slack variable <%s> to 0.\n",
3532  SCIPvarGetName(consdata->binvar), SCIPvarGetName(consdata->slackvar));
3533 
3534  /* fix slack variable to 0 */
3535  SCIP_CALL( SCIPinferVarUbCons(scip, consdata->slackvar, 0.0, cons, 0, FALSE, &infeasible, &tightened) );
3536  assert( ! infeasible );
3537  if ( tightened )
3538  ++(*nGen);
3539  }
3540  }
3541 
3542  /* if slackvar is fixed to be nonzero */
3543  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3544  {
3545  /* if binary variable is not yet fixed to 0 */
3546  if ( SCIPvarGetUbLocal(consdata->binvar) > 0.5 )
3547  {
3548  SCIPdebugMessage("slack variable <%s> is fixed to be nonzero, fixing binary variable <%s> to 0.\n",
3549  SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3550 
3551  /* fix binary variable to 0 */
3552  SCIP_CALL( SCIPinferVarUbCons(scip, consdata->binvar, 0.0, cons, 1, FALSE, &infeasible, &tightened) );
3553  assert( ! infeasible );
3554  if ( tightened )
3555  ++(*nGen);
3556  }
3557  }
3558 
3559  /* reset constraint age counter */
3560  if ( *nGen > 0 )
3561  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3562 
3563  /* delete constraint locally */
3564  assert( !SCIPconsIsModifiable(cons) );
3565 
3566  /* mark linear constraint to be update-able */
3567  if ( SCIPgetDepth(scip) == 0 && SCIPconsIsActive(consdata->lincons) )
3568  {
3569  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3570  assert(SCIPconsGetNUpgradeLocks(consdata->lincons) == 0);
3571  }
3572 
3573  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3574  }
3575  else
3576  {
3577  /* if the binary variable is fixed to zero */
3578  if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
3579  {
3580  if ( addopposite && consdata->linconsactive )
3581  {
3582  char name[SCIP_MAXSTRLEN];
3583  SCIP_CONS* reversecons;
3584  SCIP_VAR** linvars;
3585  SCIP_Real* linvals;
3586  SCIP_Bool allintegral = TRUE;
3587  SCIP_VAR* slackvar;
3588  SCIP_VAR** vars;
3589  SCIP_Real* vals;
3590  SCIP_Real lhs;
3591  SCIP_Real rhs;
3592  int nlinvars;
3593  int nvars = 0;
3594  int j;
3595 
3596  /* determine lhs/rhs (first exchange lhs/rhs) */
3597  lhs = SCIPgetRhsLinear(scip, consdata->lincons);
3598  if ( SCIPisInfinity(scip, lhs) )
3599  lhs = -SCIPinfinity(scip);
3600  rhs = SCIPgetRhsLinear(scip, consdata->lincons);
3601  if ( SCIPisInfinity(scip, -rhs) )
3602  rhs = SCIPinfinity(scip);
3603 
3604  assert( ! SCIPisInfinity(scip, lhs) );
3605  assert( ! SCIPisInfinity(scip, -rhs) );
3606 
3607  /* consider only finite lhs/rhs */
3608  if ( ! SCIPisInfinity(scip, -lhs) || ! SCIPisInfinity(scip, rhs) )
3609  {
3610  /* ignore equations (cannot add opposite constraint) */
3611  if ( ! SCIPisEQ(scip, lhs, rhs) )
3612  {
3613  assert( consdata->lincons != NULL );
3614  nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
3615  linvars = SCIPgetVarsLinear(scip, consdata->lincons);
3616  linvals = SCIPgetValsLinear(scip, consdata->lincons);
3617  slackvar = consdata->slackvar;
3618  assert( slackvar != NULL );
3619 
3620  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlinvars) );
3621  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlinvars) );
3622 
3623  /* copy data and check whether the linear constraint is integral */
3624  for (j = 0; j < nlinvars; ++j)
3625  {
3626  if ( linvars[j] != slackvar )
3627  {
3628  if (! SCIPvarIsIntegral(linvars[j]) || ! SCIPisIntegral(scip, linvals[j]) )
3629  allintegral = FALSE;
3630 
3631  vars[nvars] = linvars[j];
3632  vals[nvars++] = linvals[j];
3633  }
3634  }
3635  assert( nlinvars == nvars + 1 );
3636 
3637  /* possibly adjust lhs/rhs */
3638  if ( allintegral && ! SCIPisInfinity(scip, REALABS(lhs)) )
3639  lhs += 1.0;
3640 
3641  if ( allintegral && ! SCIPisInfinity(scip, REALABS(rhs)) )
3642  rhs -= 1.0;
3643 
3644  /* create reverse constraint */
3645  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "reverse_%s", SCIPconsGetName(consdata->lincons));
3646 
3647  /* constraint is initial, separated, not enforced, not checked, propagated, local, not modifiable, dynamic, removable */
3648  SCIP_CALL( SCIPcreateConsLinear(scip, &reversecons, name, nvars, vars, vals, lhs, rhs,
3649  TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE) );
3650 
3651  SCIPdebugMessage("Binary variable <%s> fixed to 0. Adding opposite linear inequality.\n", SCIPvarGetName(consdata->binvar));
3652  SCIPdebugPrintCons(scip, reversecons, NULL);
3653 
3654  /* add constraint */
3655  SCIP_CALL( SCIPaddCons(scip, reversecons) );
3656  SCIP_CALL( SCIPreleaseCons(scip, &reversecons) );
3657 
3658  SCIPfreeBufferArray(scip, &vals);
3659  SCIPfreeBufferArray(scip, &vars);
3660  }
3661  }
3662  }
3663 
3664  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3665  }
3666 
3667  /* if the slack variable is fixed to zero */
3668  if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3669  {
3670  /* perform dual reduction - if required */
3671  if ( dualreductions )
3672  {
3673  SCIP_VAR* binvar;
3674  SCIP_Real obj;
3675 
3676  /* check objective of binary variable */
3677  binvar = consdata->binvar;
3678  obj = varGetObjDelta(binvar);
3679 
3680  /* if obj = 0, we prefer setting the binary variable to 1 (if possible) */
3681  if ( obj <= 0.0 )
3682  {
3683  /* In this case we would like to fix the binary variable to 1, if it is not locked up
3684  except by this indicator constraint. If more than one indicator constraint is
3685  effected, we have to hope that they are all fulfilled - in this case the last
3686  constraint will fix the binary variable to 1. */
3687  if ( SCIPvarGetNLocksUp(binvar) <= 1 )
3688  {
3689  if ( SCIPvarGetUbLocal(binvar) > 0.5 )
3690  {
3691  SCIPdebugMessage("Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
3692  SCIP_CALL( SCIPinferVarLbCons(scip, binvar, 1.0, cons, 2, FALSE, &infeasible, &tightened) );
3693  assert( ! infeasible );
3694  if ( tightened )
3695  ++(*nGen);
3696  /* Make sure that the other case does not occur, since we are not sure whether SCIPinferVarLbCons() directly changes the bounds. */
3697  obj = -1.0;
3698  }
3699  }
3700  }
3701  if ( obj >= 0.0 )
3702  {
3703  /* In this case we would like to fix the binary variable to 0, if it is not locked down
3704  (should also have been performed by other dual reductions). */
3705  if ( SCIPvarGetNLocksDown(binvar) == 0 )
3706  {
3707  if ( SCIPvarGetLbLocal(binvar) < 0.5 )
3708  {
3709  SCIPdebugMessage("Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
3710  SCIP_CALL( SCIPinferVarUbCons(scip, binvar, 0.0, cons, 2, FALSE, &infeasible, &tightened) );
3711  assert( ! infeasible );
3712  if ( tightened )
3713  ++(*nGen);
3714  }
3715  }
3716  }
3717  }
3718 
3719  SCIPdebugMessage("Slack variable fixed to zero, delete redundant indicator constraint <%s>.\n", SCIPconsGetName(cons));
3720 
3721  /* delete constraint */
3722  assert( ! SCIPconsIsModifiable(cons) );
3723 
3724  /* mark linear constraint to be update-able */
3725  if ( SCIPgetDepth(scip) == 0 && SCIPconsIsActive(consdata->lincons) )
3726  {
3727  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3728  assert(SCIPconsGetNUpgradeLocks(consdata->lincons) == 0);
3729  }
3730 
3731  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3732  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3733  ++(*nGen);
3734  }
3735 
3736  /* Note that because of possible multi-aggregation we cannot simply remove the indicator
3737  * constraint if the linear constraint is not active or disabled - see the note in @ref
3738  * PREPROC and consPresolIndicator(). Moreover, it would drastically increase memory
3739  * consumption, because the linear constraints have to be stored in each node. */
3740  }
3741 
3742  return SCIP_OKAY;
3743 }
3744 
3745 
3746 /** enforcement method that produces cuts if possible
3747  *
3748  * This is a variant of the enforcement method that generates cuts/constraints via the alternative
3749  * LP, if possible.
3750  */
3751 static
3753  SCIP* scip, /**< SCIP pointer */
3754  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3755  int nconss, /**< number of constraints */
3756  SCIP_CONS** conss, /**< indicator constraints */
3757  SCIP_SOL* sol, /**< solution to be enforced */
3758  SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
3759  int* nGen /**< number of cuts generated */
3760 )
3761 {
3762  SCIP_CONSHDLRDATA* conshdlrdata;
3763  SCIP_LPI* lp;
3764  SCIP_Bool* S;
3765  SCIP_Real value;
3766  SCIP_Bool error;
3767  int size;
3768  int nCuts;
3769  int j;
3770 
3771  assert( scip != NULL );
3772  assert( conshdlr != NULL );
3773  assert( conss != NULL );
3774  assert( nGen != NULL );
3775 
3776  SCIPdebugMessage("Enforcing via cuts ...\n");
3777  *nGen = 0;
3778 
3779  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3780  assert( conshdlrdata != NULL );
3781  lp = conshdlrdata->altlp;
3782  assert( lp != NULL );
3783 
3784 #ifndef NDEBUG
3785  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
3786 #endif
3787 
3788  /* change coefficients of bounds in alternative LP */
3789  if ( conshdlrdata->updatebounds )
3790  SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
3791 
3792  /* scale first row if necessary */
3793  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
3794 
3795  /* set objective function to current solution */
3796  SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
3797 
3798  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
3799 
3800  /* set up variables fixed to 1 */
3801  size = 0;
3802  value = 0.0;
3803  for (j = 0; j < nconss; ++j)
3804  {
3805  SCIP_CONSDATA* consdata;
3806 
3807  assert( conss[j] != NULL );
3808  consdata = SCIPconsGetData(conss[j]);
3809  assert( consdata != NULL );
3810 
3811  assert( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
3812  if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
3813  {
3814  ++size;
3815  value += varGetObjDelta(consdata->binvar);
3816  S[j] = TRUE;
3817  }
3818  else
3819  S[j] = FALSE;
3820  }
3821 
3822  /* fix the variables in S */
3823  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
3824 
3825  /* extend set S to a cover and generate cuts */
3826  error = FALSE;
3827  SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, conshdlrdata->removable, genlogicor, nconss, conss, S, &size, &value, &error, &nCuts) );
3828  *nGen = nCuts;
3829 
3830  /* return with an error if no cuts have been produced and and error occured in extendToCover() */
3831  if ( nCuts == 0 && error )
3832  return SCIP_LPERROR;
3833 
3834  SCIPdebugMessage("Generated %d IIS-cuts.\n", nCuts);
3835 
3836  /* reset bounds */
3837  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
3838 
3839 #ifndef NDEBUG
3840  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
3841 #endif
3842 
3843  SCIPfreeBufferArray(scip, &S);
3844 
3845  return SCIP_OKAY;
3846 }
3847 
3848 
3849 /** enforcement method
3850  *
3851  * We check whether the current solution is feasible, i.e., if binvar = 1
3852  * implies that slackvar = 0. If not, we branch as follows:
3853  *
3854  * In one branch we fix binvar = 1 and slackvar = 0. In the other branch
3855  * we fix binvar = 0 and leave slackvar unchanged.
3856  */
3857 static
3859  SCIP* scip, /**< SCIP pointer */
3860  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3861  int nconss, /**< number of constraints */
3862  SCIP_CONS** conss, /**< indicator constraints */
3863  SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
3864  SCIP_RESULT* result /**< result */
3865  )
3866 {
3867  SCIP_CONSDATA* consdata;
3868  SCIP_CONSHDLRDATA* conshdlrdata;
3869  SCIP_NODE* node1;
3870  SCIP_NODE* node2;
3871  SCIP_VAR* slackvar;
3872  SCIP_VAR* binvar;
3874  SCIP_Real maxSlack = -1.0;
3875  SCIP_Bool someLinconsNotActive = FALSE;
3876  int c;
3877 
3878  assert( scip != NULL );
3879  assert( conshdlr != NULL );
3880  assert( conss != NULL );
3881  assert( result != NULL );
3882 
3883  *result = SCIP_FEASIBLE;
3884 
3885  SCIPdebugMessage("Enforcing indicator constraints <%s>.\n", SCIPconshdlrGetName(conshdlr) );
3886 
3887  /* get constraint handler data */
3888  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3889  assert( conshdlrdata != NULL );
3890 
3891 #ifdef SCIP_OUTPUT
3892  SCIP_CALL( SCIPwriteTransProblem(scip, "ind.cip", "cip", FALSE) );
3893 #endif
3894 
3895  /* check each constraint */
3896  for (c = 0; c < nconss; ++c)
3897  {
3898  SCIP_Bool cutoff;
3899  SCIP_Real valSlack;
3900  int cnt;
3901 
3902  assert( conss[c] != NULL );
3903  consdata = SCIPconsGetData(conss[c]);
3904  assert( consdata != NULL );
3905  assert( consdata->lincons != NULL );
3906 
3907  /* if the linear constraint has not been generated, we do nothing */
3908  if ( ! consdata->linconsactive )
3909  {
3910  someLinconsNotActive = TRUE;
3911  continue;
3912  }
3913 
3914  /* first perform propagation (it might happen that standard propagation is turned off) */
3915  SCIP_CALL( propIndicator(scip, conss[c], consdata, conshdlrdata->dualreductions, conshdlrdata->addopposite, &cutoff, &cnt) );
3916  if ( cutoff )
3917  {
3918  SCIPdebugMessage("propagation in enforcing <%s> detected cutoff.\n", SCIPconsGetName(conss[c]));
3919  *result = SCIP_CUTOFF;
3920  return SCIP_OKAY;
3921  }
3922  if ( cnt > 0 )
3923  {
3924  SCIPdebugMessage("propagation in enforcing <%s> reduced domains: %d.\n", SCIPconsGetName(conss[c]), cnt);
3925  *result = SCIP_REDUCEDDOM;
3926  return SCIP_OKAY;
3927  }
3928 
3929  /* check whether constraint is infeasible */
3930  binvar = consdata->binvar;
3931  valSlack = SCIPgetSolVal(scip, NULL, consdata->slackvar);
3932  assert( ! SCIPisFeasNegative(scip, valSlack) );
3933  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, NULL, binvar)) && ! SCIPisFeasZero(scip, valSlack) )
3934  {
3935  /* binary variable is not fixed - otherwise we would not be infeasible */
3936  assert( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 );
3937 
3938  if ( valSlack > maxSlack )
3939  {
3940  maxSlack = valSlack;
3941  branchCons = conss[c];
3942 #ifdef SCIP_OUTPUT
3943  SCIPinfoMessage(scip, NULL, "Violated indicator constraint:\n");
3944  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
3945  SCIPinfoMessage(scip, NULL, ";\n");
3946  SCIPinfoMessage(scip, NULL, "Corresponding linear constraint:\n");
3947  SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
3948  SCIPinfoMessage(scip, NULL, ";\n");
3949 #endif
3950  }
3951  }
3952  }
3953 
3954  /* if some constraint has a linear constraint that is not active, we need to check feasibility via the alternative polyhedron */
3955  if ( (someLinconsNotActive || conshdlrdata->enforcecuts) && conshdlrdata->sepaalternativelp )
3956  {
3957  int nGen;
3958 
3959  SCIP_CALL( enforceCuts(scip, conshdlr, nconss, conss, NULL, genlogicor, &nGen) );
3960  if ( nGen > 0 )
3961  {
3962  if ( genlogicor )
3963  {
3964  SCIPdebugMessage("Generated %d constraints.\n", nGen);
3965  *result = SCIP_CONSADDED;
3966  }
3967  else
3968  {
3969  SCIPdebugMessage("Generated %d cuts.\n", nGen);
3970  *result = SCIP_SEPARATED;
3971  }
3972  return SCIP_OKAY;
3973  }
3974  SCIPdebugMessage("Enforcing produced no cuts.\n");
3975 
3976  assert( ! someLinconsNotActive || branchCons == NULL );
3977  }
3978 
3979  /* if all constraints are feasible */
3980  if ( branchCons == NULL )
3981  {
3982  SCIPdebugMessage("All indicator constraints are feasible.\n");
3983  return SCIP_OKAY;
3984  }
3985 
3986  /* skip branching if required */
3987  if ( ! conshdlrdata->branchindicators )
3988  {
3989  *result = SCIP_INFEASIBLE;
3990  return SCIP_OKAY;
3991  }
3992 
3993  /* otherwise create branches */
3994  SCIPdebugMessage("Branching on constraint <%s> (slack value: %f).\n", SCIPconsGetName(branchCons), maxSlack);
3995  consdata = SCIPconsGetData(branchCons);
3996  assert( consdata != NULL );
3997  binvar = consdata->binvar;
3998  slackvar = consdata->slackvar;
3999 
4000  /* node1: binvar = 1, slackvar = 0 */
4001  SCIP_CALL( SCIPcreateChild(scip, &node1, 0.0, SCIPcalcChildEstimate(scip, binvar, 1.0) ) );
4002 
4003  if ( SCIPvarGetLbLocal(binvar) < 0.5 )
4004  {
4005  SCIP_CALL( SCIPchgVarLbNode(scip, node1, binvar, 1.0) );
4006  }
4007 
4008  /* if slack-variable is multi-aggregated */
4009  assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
4010  if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(slackvar)) )
4011  {
4012  SCIP_CALL( SCIPchgVarUbNode(scip, node1, slackvar, 0.0) );
4013  }
4014 
4015  /* node2: binvar = 0, no restriction on slackvar */
4016  SCIP_CALL( SCIPcreateChild(scip, &node2, 0.0, SCIPcalcChildEstimate(scip, binvar, 0.0) ) );
4017 
4018  if ( SCIPvarGetUbLocal(binvar) > 0.5 )
4019  {
4020  SCIP_CALL( SCIPchgVarUbNode(scip, node2, binvar, 0.0) );
4021  }
4022 
4023  SCIP_CALL( SCIPresetConsAge(scip, branchCons) );
4024  *result = SCIP_BRANCHED;
4025 
4026  return SCIP_OKAY;
4027 }
4028 
4029 
4030 /** separate IIS-cuts via rounding
4031  *
4032  * @todo Check whether the cover produced at the end is a feasible solution.
4033  */
4034 static
4036  SCIP* scip, /**< SCIP pointer */
4037  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4038  SCIP_SOL* sol, /**< solution to be separated */
4039  int nconss, /**< number of constraints */
4040  SCIP_CONS** conss, /**< indicator constraints */
4041  int maxsepacuts, /**< maximal number of cuts to be generated */
4042  int* nGen /**< number of domain changes */
4043  )
4044 {
4045  SCIP_CONSHDLRDATA* conshdlrdata;
4046  SCIP_LPI* lp;
4047  int rounds;
4048  SCIP_Real threshold;
4049  SCIP_Bool* S;
4050  SCIP_Bool error;
4051  int oldsize = -1;
4052  int nGenOld;
4053 
4054  assert( scip != NULL );
4055  assert( conshdlr != NULL );
4056  assert( conss != NULL );
4057  assert( nGen != NULL );
4058 
4059  if ( *nGen >= maxsepacuts )
4060  return SCIP_OKAY;
4061 
4062  rounds = 0;
4063 
4064  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4065  assert( conshdlrdata != NULL );
4066  lp = conshdlrdata->altlp;
4067  assert( lp != NULL );
4068 
4069  nGenOld = *nGen;
4070  SCIPdebugMessage("Separating IIS-cuts by rounding ...\n");
4071 
4072 #ifndef NDEBUG
4073  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4074 #endif
4075 
4076  /* change coefficients of bounds in alternative LP */
4077  if ( conshdlrdata->updatebounds )
4078  {
4079  /* update to local bounds */
4080  SCIP_CALL( updateFirstRow(scip, conshdlrdata) );
4081  }
4082 
4083  /* scale first row if necessary */
4084  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
4085 
4086  /* set objective function to current solution */
4087  SCIP_CALL( setAltLPObj(scip, lp, sol, nconss, conss) );
4088 
4089  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
4090 
4091  /* loop through the possible thresholds */
4092  for (threshold = conshdlrdata->roundingmaxthres;
4093  rounds < conshdlrdata->roundingrounds && threshold >= conshdlrdata->roundingminthres && *nGen < maxsepacuts;
4094  threshold -= conshdlrdata->roundingoffset)
4095  {
4096  SCIP_Real value;
4097  int size;
4098  int nCuts;
4099  int j;
4100 
4101  value = 0.0;
4102  size = 0;
4103  nCuts = 0;
4104 
4105  SCIPdebugMessage("Threshold: %f\n", threshold);
4106 
4107  /* choose variables that have a value < current threshold value */
4108  for (j = 0; j < nconss; ++j)
4109  {
4110  SCIP_CONSDATA* consdata;
4111 
4112  assert( conss[j] != NULL );
4113  consdata = SCIPconsGetData(conss[j]);
4114  assert( consdata != NULL );
4115 
4116  if ( SCIPisFeasLT(scip, SCIPgetVarSol(scip, consdata->binvar), threshold) )
4117  {
4118  S[j] = TRUE;
4119  value += varGetObjDelta(consdata->binvar);
4120  ++size;
4121  }
4122  else
4123  S[j] = FALSE;
4124  }
4125 
4126  if (size == nconss)
4127  {
4128  SCIPdebugMessage("All variables in the set. Continue ...\n");
4129  continue;
4130  }
4131 
4132  /* skip computation if size has not changed (computation is likely the same) */
4133  if ( size == oldsize )
4134  {
4135  SCIPdebugMessage("Skipping computation: size support has not changed.\n");
4136  continue;
4137  }
4138  oldsize = size;
4139 
4140  /* fix the variables in S */
4141  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
4142 
4143  /* extend set S to a cover and generate cuts */
4144  SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, conshdlrdata->removable, conshdlrdata->genlogicor, nconss, conss, S, &size, &value, &error, &nCuts) );
4145 
4146  /* we ignore errors in extendToCover */
4147  if ( nCuts > 0 )
4148  {
4149  *nGen += nCuts;
4150  ++rounds;
4151  }
4152 
4153  /* Note: checking for a primal solution is done in extendToCover(). */
4154  SCIPdebugMessage("Produced cover of size %d with value %f\n", size, value);
4155 
4156  /* reset bounds */
4157  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
4158  }
4159  SCIPdebugMessage("Generated %d IISs.\n", *nGen - nGenOld);
4160 
4161 #ifndef NDEBUG
4162  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4163 #endif
4164 
4165  SCIPfreeBufferArray(scip, &S);
4166 
4167  return SCIP_OKAY;
4168 }
4169 
4170 
4171 /** separation method
4172  *
4173  * We first check whether coupling inequalities can be separated (if required). If not enough of
4174  * these could be generated, we check whether IIS inequalities can be separated.
4175  */
4176 static
4178  SCIP* scip, /**< SCIP pointer */
4179  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4180  int nconss, /**< number of constraints */
4181  int nusefulconss, /**< number of usefull constraints */
4182  SCIP_CONS** conss, /**< indicator constraints */
4183  SCIP_SOL* sol, /**< solution to be separated */
4184  SCIP_RESULT* result /**< result */
4185  )
4186 {
4187  SCIP_CONSHDLRDATA* conshdlrdata;
4188  int maxsepacuts;
4189  int ncuts;
4190 
4191  assert( scip != NULL );
4192  assert( conshdlr != NULL );
4193  assert( conss != NULL );
4194  assert( result != NULL );
4195 
4196  *result = SCIP_DIDNOTRUN;
4197 
4198  if ( nconss == 0 )
4199  return SCIP_OKAY;
4200 
4201  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4202  assert( conshdlrdata != NULL );
4203  ncuts = 0;
4204 
4205  /* get the maximal number of cuts allowed in a separation round */
4206  if ( SCIPgetDepth(scip) == 0 )
4207  maxsepacuts = conshdlrdata->maxsepacutsroot;
4208  else
4209  maxsepacuts = conshdlrdata->maxsepacuts;
4210 
4211  /* first separate coupling inequalities (if required) */
4212  if ( conshdlrdata->sepacouplingcuts )
4213  {
4214  int c;
4215 
4216  *result = SCIP_DIDNOTFIND;
4217 
4218  /* check each constraint */
4219  for (c = 0; c < nusefulconss && ncuts < maxsepacuts; ++c)
4220  {
4221  SCIP_CONSDATA* consdata;
4222  SCIP_Bool islocal;
4223  SCIP_Real ub;
4224 
4225  assert( conss != NULL );
4226  assert( conss[c] != NULL );
4227  consdata = SCIPconsGetData(conss[c]);
4228  assert( consdata != NULL );
4229  assert( consdata->slackvar != NULL );
4230  assert( consdata->binvar != NULL );
4231 
4232  /* get upper bound for slack variable in linear constraint */
4233  islocal = FALSE;
4234  if ( conshdlrdata->sepacouplinglocal )
4235  {
4236  ub = SCIPvarGetUbLocal(consdata->slackvar);
4237  if ( ub < SCIPvarGetUbGlobal(consdata->slackvar) )
4238  islocal = TRUE;
4239  }
4240  else
4241  ub = SCIPvarGetUbGlobal(consdata->slackvar);
4242  assert( ! SCIPisFeasNegative(scip, ub) );
4243 
4244  /* only use coefficients that are not too large */
4245  if ( ub <= conshdlrdata->sepacouplingvalue )
4246  {
4247  SCIP_Real activity;
4248 
4249  activity = SCIPgetSolVal(scip, sol, consdata->slackvar) + ub * SCIPgetSolVal(scip, sol, consdata->binvar) - ub;
4250  if ( SCIPisEfficacious(scip, activity) )
4251  {
4252  SCIP_ROW* row;
4253  SCIP_Bool infeasible;
4254  char name[50];
4255 #ifndef NDEBUG
4256  (void) SCIPsnprintf(name, 50, "couple%d", c);
4257 #else
4258  name[0] = '\0';
4259 #endif
4260 
4261  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), name, -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
4262  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4263 
4264  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
4265  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
4266  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4267 
4268  SCIPdebugMessage("Separated coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
4269 #ifdef SCIP_OUTPUT
4270  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
4271 #endif
4272  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, &infeasible) );
4273  assert( ! infeasible );
4274  SCIP_CALL( SCIPreleaseRow(scip, &row));
4275 
4276  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
4277 
4278  ++ncuts;
4279  }
4280  }
4281  }
4282  SCIPdebugMessage("Separated coupling inequalities: %d\n", ncuts);
4283  }
4284 
4285  /* separated cuts from the alternative lp (if required) */
4286  if ( conshdlrdata->sepaalternativelp && ncuts < SEPAALTTHRESHOLD )
4287  {
4288  int noldcuts;
4289 
4290  SCIPdebugMessage("Separating inequalities for indicator constraints.\n");
4291 
4292  noldcuts = ncuts;
4293  if ( *result == SCIP_DIDNOTRUN )
4294  *result = SCIP_DIDNOTFIND;
4295 
4296  /* start separation */
4297  SCIP_CALL( separateIISRounding(scip, conshdlr, sol, nconss, conss, maxsepacuts, &ncuts) );
4298  SCIPdebugMessage("Separated %d cuts from indicator constraints.\n", ncuts - noldcuts);
4299 
4300  if ( ncuts > noldcuts )
4301  {
4302  /* possibly overwrite result from separation above */
4303  if ( conshdlrdata->genlogicor )
4304  *result = SCIP_CONSADDED;
4305  else
4306  *result = SCIP_SEPARATED;
4307  }
4308  }
4309 
4310  return SCIP_OKAY;
4311 }
4312 
4313 /** initializes the constraint handler data */
4314 static
4316  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
4317  )
4318 {
4319  assert(conshdlrdata != NULL);
4320 
4321  conshdlrdata->removable = TRUE;
4322  conshdlrdata->scaled = FALSE;
4323  conshdlrdata->altlp = NULL;
4324  conshdlrdata->nrows = 0;
4325  conshdlrdata->varhash = NULL;
4326  conshdlrdata->slackhash = NULL;
4327  conshdlrdata->lbhash = NULL;
4328  conshdlrdata->ubhash = NULL;
4329  conshdlrdata->nlbbounds = 0;
4330  conshdlrdata->nubbounds = 0;
4331  conshdlrdata->nslackvars = 0;
4332  conshdlrdata->roundingminthres = 0.1;
4333  conshdlrdata->roundingmaxthres = 0.6;
4334  conshdlrdata->roundingrounds = 1;
4335  conshdlrdata->roundingoffset = 0.1;
4336  conshdlrdata->addedcouplingcons = FALSE;
4337  conshdlrdata->ninitconss = 0;
4338  conshdlrdata->nbinvarszero = 0;
4339  conshdlrdata->performedrestart = FALSE;
4340  conshdlrdata->objindicatoronly = FALSE;
4341  conshdlrdata->minabsobj = 0.0;
4342 }
4343 
4344 
4345 /* ---------------------------- constraint handler callback methods ----------------------*/
4346 
4347 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
4348 static
4349 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyIndicator)
4350 { /*lint --e{715}*/
4351  assert( scip != NULL );
4352  assert( conshdlr != NULL );
4353  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
4354  assert( valid != NULL );
4355 
4356  /* call inclusion method of constraint handler */
4358 
4359  *valid = TRUE;
4360 
4361  return SCIP_OKAY;
4362 }
4363 
4364 
4365 /** initialization method of constraint handler (called after problem was transformed) */
4366 static
4367 SCIP_DECL_CONSINIT(consInitIndicator)
4368 { /*lint --e{715}*/
4369  SCIP_CONSHDLRDATA* conshdlrdata;
4370 
4371  assert( scip != NULL );
4372  assert( conshdlr != NULL );
4373  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
4374 
4375  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4376  assert( conshdlrdata != NULL );
4377 
4378  initConshdlrData(conshdlrdata);
4379 
4380  /* find trysol heuristic */
4381  if ( conshdlrdata->trysolutions && conshdlrdata->heurtrysol == NULL )
4382  {
4383  conshdlrdata->heurtrysol = SCIPfindHeur(scip, "trysol");
4384  }
4385 
4386  return SCIP_OKAY;
4387 }
4388 
4389 
4390 /** deinitialization method of constraint handler (called before transformed problem is freed) */
4391 static
4392 SCIP_DECL_CONSEXIT(consExitIndicator)
4393 { /*lint --e{715}*/
4394  SCIP_CONSHDLRDATA* conshdlrdata;
4395 
4396  assert(scip != NULL);
4397  assert(conshdlr != NULL);
4398  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4399 
4400  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4401 
4402  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
4403  conshdlrdata->maxaddlincons = 0;
4404  conshdlrdata->naddlincons = 0;
4405  conshdlrdata->nrows = 0;
4406 
4407  return SCIP_OKAY;
4408 }
4409 
4410 
4411 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
4412 static
4413 SCIP_DECL_CONSFREE(consFreeIndicator)
4414 {
4415  SCIP_CONSHDLRDATA* conshdlrdata;
4416 
4417  assert( scip != NULL );
4418  assert( conshdlr != NULL );
4419  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
4420 
4421  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4422  assert( conshdlrdata != NULL );
4423  assert( conshdlrdata->altlp == NULL );
4424  assert( conshdlrdata->varhash == NULL );
4425  assert( conshdlrdata->lbhash == NULL );
4426  assert( conshdlrdata->ubhash == NULL );
4427  assert( conshdlrdata->slackhash == NULL );
4428 
4429  if( conshdlrdata->maxaddlincons > 0 )
4430  {
4431  /* if problem was not yet transformed the array may need to be freed, because we did not call the EXIT callback */
4432  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
4433  }
4434  assert(conshdlrdata->addlincons == NULL);
4435  conshdlrdata->naddlincons = 0;
4436  conshdlrdata->maxaddlincons = 0;
4437 
4438  SCIPfreeMemory(scip, &conshdlrdata);
4439 
4440  return SCIP_OKAY;
4441 }
4442 
4443 
4444 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
4445 static
4446 SCIP_DECL_CONSINITSOL(consInitsolIndicator)
4447 {
4448  SCIP_CONSHDLRDATA* conshdlrdata;
4449  int c;
4450 
4451  assert( scip != NULL );
4452  assert( conshdlr != NULL );
4453  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
4454 
4455  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4456  assert( conshdlrdata != NULL );
4457  assert( conshdlrdata->slackhash == NULL );
4458 
4459  if ( conshdlrdata->sepaalternativelp )
4460  {
4461  /* generate hash for storing all slack variables (size is just a guess) */
4462  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->slackhash, SCIPblkmem(scip), SCIPcalcHashtableSize(10 * SCIPgetNVars(scip))) );
4463  assert( conshdlrdata->slackhash != NULL );
4464 
4465  /* first initialize slack hash */
4466  for (c = 0; c < nconss; ++c)
4467  {
4468  SCIP_CONSDATA* consdata;
4469 
4470  assert( conss != NULL );
4471  assert( conss[c] != NULL );
4472  assert( SCIPconsIsTransformed(conss[c]) );
4473 
4474  consdata = SCIPconsGetData(conss[c]);
4475  assert( consdata != NULL );
4476 
4477  assert( consdata->slackvar != NULL );
4478 
4479  /* insert slack variable into hash */
4480  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->slackhash, consdata->slackvar, (void*) (size_t) (INT_MAX)) );
4481  assert( SCIPhashmapExists(conshdlrdata->slackhash, consdata->slackvar) );
4482  ++conshdlrdata->nslackvars;
4483  }
4484  }
4485 
4486  /* check each constraint */
4487  for (c = 0; c < nconss; ++c)
4488  {
4489  SCIP_CONSDATA* consdata;
4490 
4491  assert( conss != NULL );
4492  assert( conss[c] != NULL );
4493  assert( SCIPconsIsTransformed(conss[c]) );
4494 
4495  consdata = SCIPconsGetData(conss[c]);
4496  assert( consdata != NULL );
4497 
4498  /* SCIPdebugMessage("Initializing indicator constraint <%s>.\n", SCIPconsGetName(conss[c]) ); */
4499 
4500  /* deactivate */
4501  if ( ! consdata->linconsactive )
4502  {
4503  SCIP_CALL( SCIPdisableCons(scip, consdata->lincons) );
4504  }
4505  else
4506  {
4507  /* add constraint to alternative LP if not already done */
4508  if ( conshdlrdata->sepaalternativelp && consdata->colindex < 0 )
4509  {
4510  SCIPdebugMessage("Adding column for <%s> to alternative LP ...\n", SCIPconsGetName(conss[c]));
4511  SCIP_CALL( addAltLPConstraint(scip, conshdlr, consdata->lincons, consdata->slackvar, 1.0, &consdata->colindex) );
4512  SCIPdebugMessage("Column index for <%s>: %d\n", SCIPconsGetName(conss[c]), consdata->colindex);
4513 #ifdef SCIP_OUTPUT
4514  SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
4515  SCIPinfoMessage(scip, NULL, ";\n");
4516 #endif
4517  }
4518  }
4519 
4520  /* add nlrow representation to NLP, if NLP had been constructed
4521  *
4522  * Note, that we did not tell SCIP in exitpre that we have something to add to the NLP, thus
4523  * indicators are only available in the NLP for MINLPs, but not for MIPs with indicators.
4524  */
4525  if ( SCIPisNLPConstructed(scip) && SCIPconsIsChecked(conss[c]) )
4526  {
4527  SCIP_NLROW* nlrow;
4528  SCIP_VAR* quadvars[2];
4529  SCIP_QUADELEM quadelem;
4530 
4531  /* create nonlinear row binary variable * slack variable = 0 */
4532  quadvars[0] = consdata->binvar;
4533  quadvars[1] = consdata->slackvar;
4534  quadelem.idx1 = 0;
4535  quadelem.idx2 = 1;
4536  quadelem.coef = 1.0;
4537 
4538  SCIP_CALL( SCIPcreateNlRow(scip, &nlrow, SCIPconsGetName(conss[c]), 0.0, 0, NULL, NULL, 2, quadvars, 1, &quadelem, NULL, 0.0, 0.0) );
4539 
4540  /* add row to NLP and forget about it */
4541  SCIP_CALL( SCIPaddNlRow(scip, nlrow) );
4542  SCIP_CALL( SCIPreleaseNlRow(scip, &nlrow) );
4543  }
4544  }
4545 
4546  SCIPdebugMessage("Initialized %d indicator constraints.\n", nconss);
4547 
4548  /* check additional constraints */
4549  if ( conshdlrdata->sepaalternativelp )
4550  {
4551  SCIP_CONS* cons;
4552  int colindex;
4553  int cnt = 0;
4554 
4555  /* add stored linear constraints if they exist */
4556  if ( conshdlrdata->naddlincons > 0 )
4557  {
4558  for (c = 0; c < conshdlrdata->naddlincons; ++c)
4559  {
4560  cons = conshdlrdata->addlincons[c];
4561 
4562  /* get transformed constraint - since it is needed only here, we do not store the information */
4563  if ( ! SCIPconsIsTransformed(cons) )
4564  {
4565  SCIP_CALL( SCIPgetTransformedCons(scip, conshdlrdata->addlincons[c], &cons) );
4566 
4567  /* @todo check when exactly the transformed constraint does not exist - SCIPisActive() does not suffice */
4568  if ( cons == NULL )
4569  continue;
4570  }
4571  SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
4572  ++cnt;
4573 
4574 #ifdef SCIP_OUTPUT
4575  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
4576  SCIPinfoMessage(scip, NULL, ";\n");
4577 #endif
4578  }
4579  SCIPdebugMessage("Added %d additional columns to alternative LP.\n", cnt);
4580  }
4581  else
4582  {
4583  /* if no stored linear constraints are available, possibly collect other linear constraints; we only use linear
4584  * constraints, since most other constraints involve integral variables, and in this context we will likely
4585  * benefit much more from continuous variables. */
4586  if ( conshdlrdata->useotherconss )
4587  {
4588  const char* conshdlrname;
4589  SCIP_CONS** allconss;
4590  int nallconss;
4591 
4592  nallconss = SCIPgetNConss(scip);
4593  allconss = SCIPgetConss(scip);
4594 
4595  /* loop through all constraints */
4596  for (c = 0; c < nallconss; ++c)
4597  {
4598  /* get constraint */
4599  cons = allconss[c];
4600  assert( cons != NULL );
4601  assert( SCIPconsIsTransformed(cons) );
4602 
4603  /* get constraint handler name */
4604  conshdlrname = SCIPconshdlrGetName(SCIPconsGetHdlr(cons));
4605 
4606  /* check type of constraint (only take linear constraints) */
4607  if ( strcmp(conshdlrname, "linear") == 0 )
4608  {
4609  /* avoid adding linear constraints that correspond to indicator constraints */
4610  if ( strncmp(SCIPconsGetName(cons), "indlin", 6) != 0 )
4611  {
4612  SCIPdebugMessage("Adding column for linear constraint <%s> to alternative LP ...\n", SCIPconsGetName(cons));
4613  SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
4614  ++cnt;
4615  }
4616  }
4617  }
4618  SCIPdebugMessage("Added %d additional columns from linear constraints to alternative LP.\n", cnt);
4619  }
4620  }
4621  }
4622 
4623  /* initialize event handler if restart should be forced */
4624  if ( conshdlrdata->forcerestart )
4625  {
4626  SCIP_Bool* covered;
4627  SCIP_VAR** vars;
4628  int nvars;
4629  int j;
4630 
4631  assert( conshdlrdata->eventhdlrrestart != NULL );
4632 
4633  /* store number of initial constraints */
4634  conshdlrdata->ninitconss = SCIPconshdlrGetNActiveConss(conshdlr);
4635 
4636  /* reset number of fixed binary variables */
4637  conshdlrdata->nbinvarszero = 0;
4638 
4639  /* loop through variables */
4640  nvars = SCIPgetNVars(scip);
4641  vars = SCIPgetVars(scip);
4642 
4643  conshdlrdata->objindicatoronly = FALSE;
4644  conshdlrdata->minabsobj = SCIP_REAL_MAX;
4645 
4646  /* unmark all variables */
4647  SCIP_CALL( SCIPallocBufferArray(scip, &covered, nvars) );
4648  for (j = 0; j < nvars; ++j)
4649  covered[j] = FALSE;
4650 
4651  /* mark indicator variables */
4652  for (c = 0; c < nconss; ++c)
4653  {
4654  SCIP_CONSDATA* consdata;
4655  int probindex;
4656 
4657  assert( conss != NULL );
4658  assert( conss[c] != NULL );
4659 
4660  /* avoid non-active indicator constraints */
4661  if ( ! SCIPconsIsActive(conss[c]) )
4662  continue;
4663 
4664  consdata = SCIPconsGetData(conss[c]);
4665  assert( consdata != NULL );
4666  assert( consdata->binvar != NULL );
4667 
4668  if ( SCIPvarIsNegated(consdata->binvar) )
4669  {
4670  assert( SCIPvarGetNegatedVar(consdata->binvar) != NULL );
4671  probindex = SCIPvarGetProbindex(SCIPvarGetNegatedVar(consdata->binvar));
4672  }
4673  else
4674  probindex = SCIPvarGetProbindex(consdata->binvar);
4675 
4676  /* if presolving detected infeasibility it might be that the binary variables are not active */
4677  if ( probindex < 0 )
4678  continue;
4679 
4680  assert( 0 <= probindex && probindex < nvars );
4681  covered[probindex] = TRUE;
4682  }
4683 
4684  /* check all variables */
4685  for (j = 0; j < nvars; ++j)
4686  {
4687  SCIP_Real obj;
4688 
4689  obj = SCIPvarGetObj(vars[j]);
4690  if ( ! SCIPisZero(scip, obj) )
4691  {
4692  if ( ! covered[j] )
4693  break;
4694  if ( ! SCIPisIntegral(scip, obj) )
4695  break;
4696  if ( REALABS(obj) < conshdlrdata->minabsobj )
4697  conshdlrdata->minabsobj = REALABS(obj);
4698  }
4699  }
4700 
4701  /* if all variables have integral objective and only indicator variables have nonzero objective */
4702  if ( j >= nvars )
4703  {
4704  /* if there are variables with nonerzo objective */
4705  if ( conshdlrdata->minabsobj < SCIP_REAL_MAX )
4706  {
4707  assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
4708  assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0) );
4709 
4710  conshdlrdata->objindicatoronly = TRUE;
4711 
4712  assert( conshdlrdata->eventhdlrrestart != NULL );
4713  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
4714  }
4715  }
4716 
4717  SCIPfreeBufferArray(scip, &covered);
4718  }
4719 
4720  return SCIP_OKAY;
4721 }
4722 
4723 
4724 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
4725 static
4726 SCIP_DECL_CONSEXITSOL(consExitsolIndicator)
4727 { /*lint --e{715}*/
4728  SCIP_CONSHDLRDATA* conshdlrdata;
4729  int c;
4730 
4731  assert( scip != NULL );
4732  assert( conshdlr != NULL );
4733  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
4734 
4735  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4736  assert( conshdlrdata != NULL );
4737 
4738  if ( conshdlrdata->sepaalternativelp )
4739  {
4740  assert( conshdlrdata->altlp != NULL || nconss == 0 );
4741  assert( conshdlrdata->slackhash != NULL );
4742 
4743 #ifdef SCIP_DEBUG
4744  SCIPinfoMessage(scip, NULL, "\nStatistics for slack hash:\n");
4745  SCIPhashmapPrintStatistics(conshdlrdata->slackhash, SCIPgetMessagehdlr(scip));
4746 #endif
4747 
4748  if ( conshdlrdata->altlp != NULL )
4749  {
4750  assert( conshdlrdata->varhash != NULL );
4751  assert( conshdlrdata->lbhash != NULL );
4752  assert( conshdlrdata->ubhash != NULL );
4753 
4754 #ifdef SCIP_DEBUG
4755  SCIPinfoMessage(scip, NULL, "\nStatistics for var hash:\n");
4756  SCIPhashmapPrintStatistics(conshdlrdata->varhash, SCIPgetMessagehdlr(scip));
4757  SCIPinfoMessage(scip, NULL, "\nStatistics for slack hash:\n");
4758  SCIPhashmapPrintStatistics(conshdlrdata->slackhash, SCIPgetMessagehdlr(scip));
4759  SCIPinfoMessage(scip, NULL, "\nStatistics for lower bound hash:\n");
4760  SCIPhashmapPrintStatistics(conshdlrdata->lbhash, SCIPgetMessagehdlr(scip));
4761  SCIPinfoMessage(scip, NULL, "\nStatistics for upper bound hash:\n");
4762  SCIPhashmapPrintStatistics(conshdlrdata->ubhash, SCIPgetMessagehdlr(scip));
4763 #endif
4764 
4765  SCIPhashmapFree(&conshdlrdata->varhash);
4766  SCIPhashmapFree(&conshdlrdata->lbhash);
4767  SCIPhashmapFree(&conshdlrdata->ubhash);
4768 
4769  SCIP_CALL( SCIPlpiFree(&conshdlrdata->altlp) );
4770 
4771  /* save the information that the columns have been deleted */
4772  for (c = 0; c < nconss; ++c)
4773  {
4774  SCIP_CONSDATA* consdata;
4775 
4776  assert( conss != NULL );
4777  assert( conss[c] != NULL );
4778 
4779  consdata = SCIPconsGetData(conss[c]);
4780  assert( consdata != NULL );
4781  consdata->colindex = -1;
4782  }
4783  }
4784  SCIPhashmapFree(&conshdlrdata->slackhash);
4785  }
4786 
4787  return SCIP_OKAY;
4788 }
4789 
4790 
4791 /** frees specific constraint data */
4792 static
4793 SCIP_DECL_CONSDELETE(consDeleteIndicator)
4794 {
4795  assert( scip != NULL );
4796  assert( conshdlr != NULL );
4797  assert( cons != NULL );
4798  assert( consdata != NULL );
4799  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
4800 
4801  SCIPdebugMessage("Deleting indicator constraint <%s>.\n", SCIPconsGetName(cons) );
4802 
4803  /* drop events on transformed variables */
4804  if ( SCIPconsIsTransformed(cons) )
4805  {
4806  SCIP_CONSHDLRDATA* conshdlrdata;
4807 
4808  /* get constraint handler data */
4809  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4810  assert( conshdlrdata != NULL );
4811 
4812  if ( conshdlrdata->sepaalternativelp )
4813  {
4814  SCIP_CALL( deleteAltLPConstraint(scip, conshdlr, cons) );
4815  }
4816 
4817  assert( (*consdata)->slackvar != NULL );
4818  assert( (*consdata)->binvar != NULL );
4819 
4820  /* free events only in correct stages */
4822  {
4823  if ( (*consdata)->linconsactive )
4824  {
4825  assert( conshdlrdata->eventhdlrbound != NULL );
4826  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
4827  (SCIP_EVENTDATA*)*consdata, -1) );
4828  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
4829  (SCIP_EVENTDATA*)*consdata, -1) );
4830  }
4831  if ( conshdlrdata->forcerestart )
4832  {
4833  assert( conshdlrdata->eventhdlrrestart != NULL );
4834  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
4835  (SCIP_EVENTDATA*) conshdlrdata, -1) );
4836  }
4837  }
4838  }
4839 
4840  /* Can there be cases where lincons is NULL, e.g., if presolve found the problem infeasible? */
4841  assert( (*consdata)->lincons != NULL );
4842 
4843  /* release linear constraint and slack variable */
4844  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->slackvar) );
4845  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->lincons) );
4846 
4847  SCIPfreeBlockMemory(scip, consdata);
4848 
4849  return SCIP_OKAY;
4850 }
4851 
4852 
4853 /** transforms constraint data into data belonging to the transformed problem */
4854 static
4855 SCIP_DECL_CONSTRANS(consTransIndicator)
4856 {
4857  SCIP_CONSDATA* consdata;
4858  SCIP_CONSHDLRDATA* conshdlrdata;
4859  SCIP_CONSDATA* sourcedata;
4860  char s[SCIP_MAXSTRLEN];
4861 
4862  assert( scip != NULL );
4863  assert( conshdlr != NULL );
4864  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
4865  assert( sourcecons != NULL );
4866  assert( targetcons != NULL );
4867 
4868  /* get constraint handler data */
4869  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4870  assert( conshdlrdata != NULL );
4871  assert( conshdlrdata->eventhdlrbound != NULL );
4872 
4873  SCIPdebugMessage("Transforming indicator constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
4874 
4875  /* get data of original constraint */
4876  sourcedata = SCIPconsGetData(sourcecons);
4877  assert( sourcedata != NULL );
4878  assert( sourcedata->binvar != NULL );
4879 
4880  /* check for slackvar */
4881  if ( sourcedata->slackvar == NULL )
4882  {
4883  SCIPerrorMessage("The indicator constraint <%s> needs a slack variable.\n", SCIPconsGetName(sourcecons));
4884  return SCIP_INVALIDDATA;
4885  }
4886 
4887  /* check for linear constraint */
4888  if ( sourcedata->lincons == NULL )
4889  {
4890  SCIPerrorMessage("The indicator constraint <%s> needs a linear constraint variable.\n", SCIPconsGetName(sourcecons));
4891  return SCIP_INVALIDDATA;
4892  }
4893  assert( sourcedata->lincons != NULL );
4894  assert( sourcedata->slackvar != NULL );
4895 
4896  /* create constraint data */
4897  consdata = NULL;
4898  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, SCIPconsGetName(sourcecons), &consdata, conshdlrdata->eventhdlrbound,
4899  conshdlrdata->eventhdlrrestart, sourcedata->binvar, sourcedata->slackvar, sourcedata->lincons, sourcedata->linconsactive) );
4900  assert( consdata != NULL );
4901 
4902  /* create transformed constraint with the same flags */
4903  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
4904  SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
4905  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
4906  SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
4907  SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
4908  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
4909  SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
4910 
4911  return SCIP_OKAY;
4912 }
4913 
4914 
4915 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
4916 static
4917 SCIP_DECL_CONSINITPRE(consInitpreIndicator)
4918 { /*lint --e{715}*/
4919  SCIP_CONSHDLRDATA* conshdlrdata;
4920  int c;
4921 
4922  assert( scip != NULL );
4923  assert( conshdlr != NULL );
4924  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
4925 
4926  if ( SCIPgetStatus(scip) != SCIP_STATUS_UNKNOWN )
4927  return SCIP_OKAY;
4928 
4929  SCIPdebugMessage("Initpre method for indicator constraints.\n");
4930 
4931  /* check each constraint and get transformed linear constraint */
4932  for (c = 0; c < nconss; ++c)
4933  {
4934  SCIP_CONSDATA* consdata;
4935 
4936  assert( conss != NULL );
4937  assert( conss[c] != NULL );
4938  assert( SCIPconsIsTransformed(conss[c]) );
4939 
4940  consdata = SCIPconsGetData(conss[c]);
4941  assert( consdata != NULL );
4942 
4943  /* if not happened already, get transformed linear constraint */
4944  assert( consdata->lincons != NULL );
4945  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear") == 0 );
4946 
4947  /* in a restart the linear constraint might already be transformed */
4948  if ( ! SCIPconsIsTransformed(consdata->lincons) )
4949  {
4950  SCIP_CONS* translincons;
4951 
4952  SCIP_CALL( SCIPgetTransformedCons(scip, consdata->lincons, &translincons) );
4953  assert( translincons != NULL );
4954 
4955  SCIP_CALL( SCIPreleaseCons(scip, &consdata->lincons) );
4956  SCIP_CALL( SCIPcaptureCons(scip, translincons) );
4957  consdata->lincons = translincons;
4958  }
4959  }
4960 
4961  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4962  assert(conshdlrdata != NULL);
4963 
4964  /* reset flag, in case presolve was called for some problem before */
4965  conshdlrdata->addedcouplingcons = FALSE;
4966 
4967  return SCIP_OKAY;
4968 }
4969 
4970 
4971 /** presolving method of constraint handler
4972  *
4973  * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
4974  * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
4975  * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not
4976  * inserted. Depending on the parameter @a addcouplingcons we add a variable upper bound or a row
4977  * (in consInitlpIndicator()).
4978  *
4979  * @warning We can never delete linear constraints, because we need them to get the right values
4980  * for the slack variables!
4981  */
4982 static
4983 SCIP_DECL_CONSPRESOL(consPresolIndicator)
4984 { /*lint --e{715}*/
4985  SCIP_CONSHDLRDATA* conshdlrdata;
4986  SCIP_Bool noReductions;
4987  int oldnfixedvars;
4988  int oldndelconss;
4989  int removedvars = 0;
4990  int c;
4991 
4992  assert( scip != NULL );
4993  assert( conshdlr != NULL );
4994  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
4995  assert( result != NULL );
4996 
4997  *result = SCIP_DIDNOTRUN;
4998  oldnfixedvars = *nfixedvars;
4999  oldndelconss = *ndelconss;
5000 
5001  /* get constraint handler data */
5002  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5003  assert( conshdlrdata != NULL );
5004 
5005  SCIPdebugMessage("Presolving indicator constraints.\n");
5006 
5007  /* only run if success is possible */
5008  if( nrounds == 0 || nnewfixedvars > 0 || nnewchgbds > 0 || nnewaggrvars > 0 )
5009  {
5010  *result = SCIP_DIDNOTFIND;
5011 
5012  /* check each constraint */
5013  for (c = 0; c < nconss; ++c)
5014  {
5015  SCIP_CONSDATA* consdata;
5016  SCIP_CONS* cons;
5017  SCIP_Bool success;
5018  SCIP_Bool cutoff;
5019 
5020  assert( conss != NULL );
5021  assert( conss[c] != NULL );
5022  cons = conss[c];
5023  consdata = SCIPconsGetData(cons);
5024  assert( consdata != NULL );
5025  assert( consdata->binvar != NULL );
5026  assert( ! SCIPconsIsModifiable(cons) );
5027 
5028  /* SCIPdebugMessage("Presolving indicator constraint <%s>.\n", SCIPconsGetName(cons) ); */
5029 
5030  /* do nothing if the linear constraint is not active */
5031  if ( ! consdata->linconsactive )
5032  continue;
5033 
5034  assert( consdata->lincons != NULL );
5035  assert( consdata->slackvar != NULL );
5036  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear") == 0 );
5037  assert( SCIPconsIsTransformed(consdata->lincons) );
5038 
5039  /* add implications if not yet done */
5040  if ( ! consdata->implicationadded )
5041  {
5042  int nbnds = 0;
5043  SCIP_CALL( SCIPaddVarImplication(scip, consdata->binvar, TRUE, consdata->slackvar, SCIP_BOUNDTYPE_UPPER, 0.0,
5044  &cutoff, &nbnds) );
5045  *nchgbds += nbnds;
5046 
5047  /* cutoff/infeasible might be true if preprocessing was truncated */
5048  /* note: nbdchgs == 0 is not necessarily true, because preprocessing might be truncated. */
5049  consdata->implicationadded = TRUE;
5050  if ( cutoff )
5051  {
5052  *result = SCIP_CUTOFF;
5053  return SCIP_OKAY;
5054  }
5055  }
5056 
5057  /* check type of slack variable if not yet done */
5058  if ( ! consdata->slacktypechecked )
5059  {
5060  consdata->slacktypechecked = TRUE;
5061  /* check if slack variable can be made implicit integer. */
5062  if ( SCIPvarGetType(consdata->slackvar) != SCIP_VARTYPE_IMPLINT )
5063  {
5064  SCIP_Real* vals;
5065  SCIP_VAR** vars;
5066  SCIP_VAR* slackvar;
5067  SCIP_Bool foundslackvar;
5068  int nvars;
5069  int j;
5070 
5071  assert( consdata->lincons != NULL );
5072  vars = SCIPgetVarsLinear(scip, consdata->lincons);
5073  vals = SCIPgetValsLinear(scip, consdata->lincons);
5074  nvars = SCIPgetNVarsLinear(scip, consdata->lincons);
5075  slackvar = consdata->slackvar;
5076  assert( slackvar != NULL );
5077  foundslackvar = FALSE;
5078  for (j = 0; j < nvars; ++j)
5079  {
5080  if ( vars[j] == slackvar )
5081  foundslackvar = TRUE;
5082  else
5083  {
5084  if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, vals[j]))
5085  break;
5086  }
5087  }
5088  /* something is strange if the slack variable does not appear in the linear constraint (possibly because it is an artificial constraint) */
5089  if ( j == nvars && foundslackvar )
5090  {
5091  SCIP_Bool infeasible;
5092 
5093  SCIP_CALL( SCIPchgVarType(scip, consdata->slackvar, SCIP_VARTYPE_IMPLINT, &infeasible) );
5094  /* don't assert feasibility here because the presolver should detect infeasibility */
5095  }
5096  }
5097  }
5098 
5099  /* perform one presolving round */
5100  SCIP_CALL( presolRoundIndicator(scip, conshdlrdata, cons, consdata, conshdlrdata->dualreductions, &cutoff, &success, ndelconss, nfixedvars) );
5101 
5102  if ( cutoff )
5103  {
5104  *result = SCIP_CUTOFF;
5105  return SCIP_OKAY;
5106  }
5107  if ( success )
5108  *result = SCIP_SUCCESS;
5109  }
5110  }
5111 
5112  /* determine whether other methods have found reductions */
5113  noReductions = nnewfixedvars == 0 && nnewaggrvars == 0 && nnewchgvartypes == 0 && nnewchgbds == 0
5114  && nnewdelconss == 0 && nnewchgcoefs == 0 && nnewchgsides == 0;
5115 
5116  /* add variable upper bounds after bounds are likely to be strengthened */
5117  if ( noReductions && *result != SCIP_SUCCESS && conshdlrdata->addcouplingcons && ! conshdlrdata->addedcouplingcons )
5118  {
5119  int ngen;
5120 
5121  /* create variable upper bounds, possibly removing indicator constraints */
5122  SCIP_CALL( createVarUbs(scip, conshdlrdata, conss, nconss, &ngen) );
5123 
5124  if ( ngen > 0 )
5125  {
5126  *result = SCIP_SUCCESS;
5127  *nupgdconss += ngen;
5128  if ( conshdlrdata->removeindicators )
5129  *ndelconss += ngen;
5130  }
5131  conshdlrdata->addedcouplingcons = TRUE;
5132  }
5133 
5134  SCIPdebugMessage("Presolved %d constraints (fixed %d variables, removed %d variables, and deleted %d constraints).\n",
5135  nconss, *nfixedvars - oldnfixedvars, removedvars, *ndelconss - oldndelconss);
5136 
5137  return SCIP_OKAY;
5138 }
5139 
5140 
5141 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved)
5142  *
5143  * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
5144  * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
5145  * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not inserted.
5146  */
5147 static
5148 SCIP_DECL_CONSINITLP(consInitlpIndicator)
5149 {
5150  int c;
5151  SCIP_CONSHDLRDATA* conshdlrdata;
5152 
5153  assert( scip != NULL );
5154  assert( conshdlr != NULL );
5155  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5156 
5157  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5158  assert( conshdlrdata != NULL );
5159 
5160  /* check whether coupling constraints should be added */
5161  if ( ! conshdlrdata->addcoupling )
5162  return SCIP_OKAY;
5163 
5164  /* check whether coupling constraints have been added already */
5165  if ( conshdlrdata->addcouplingcons && conshdlrdata->addedcouplingcons )
5166  return SCIP_OKAY;
5167 
5168  /* check each constraint */
5169  for (c = 0; c < nconss; ++c)
5170  {
5171  SCIP_CONSDATA* consdata;
5172  SCIP_Real ub;
5173 
5174  assert( conss != NULL );
5175  assert( conss[c] != NULL );
5176  consdata = SCIPconsGetData(conss[c]);
5177  assert( consdata != NULL );
5178 
5179  /* do not add inequalities if there are no linear constraints (no slack variable available) */
5180  if ( ! consdata->linconsactive )
5181  continue;
5182 
5183  SCIPdebugMessage("Adding initial rows for indicator constraint <%s>.\n", SCIPconsGetName(conss[c]));
5184 
5185  /* get upper bound for slack variable in linear constraint */
5186  ub = SCIPvarGetUbGlobal(consdata->slackvar);
5187  assert( ! SCIPisNegative(scip, ub) );
5188 
5189  /* insert corresponding row if helpful and coefficient is not too large */
5190  if ( ub <= conshdlrdata->maxcouplingvalue )
5191  {
5192  char name[50];
5193 
5194 #ifndef NDEBUG
5195  (void) SCIPsnprintf(name, 50, "couple%d", c);
5196 #else
5197  name[0] = '\0';
5198 #endif
5199 
5200  /* add variable upper bound if required */
5201  if ( conshdlrdata->addcouplingcons )
5202  {
5203  SCIP_CONS* cons;
5204 
5205  assert( ! conshdlrdata->addedcouplingcons );
5206 
5207  SCIPdebugMessage("Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
5208 
5209  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
5210  TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
5211 
5212  SCIP_CALL( SCIPaddCons(scip, cons) );
5213  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
5214  }
5215  else
5216  {
5217  SCIP_ROW* row;
5218  SCIP_Bool infeasible;
5219 
5220  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conshdlr, name, -SCIPinfinity(scip), ub, FALSE, FALSE, FALSE) );
5221  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5222 
5223  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
5224  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
5225  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5226 
5227  SCIPdebugMessage("Insert coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
5228 #ifdef SCIP_OUTPUT
5229  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
5230 #endif
5231  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
5232  assert( ! infeasible );
5233 
5234  SCIP_CALL( SCIPaddPoolCut(scip, row) );
5235  SCIP_CALL( SCIPreleaseRow(scip, &row));
5236  }
5237  }
5238  }
5239 
5240  return SCIP_OKAY;
5241 }
5242 
5243 
5244 /** separation method of constraint handler for LP solutions */
5245 static
5246 SCIP_DECL_CONSSEPALP(consSepalpIndicator)
5247 { /*lint --e{715}*/
5248  assert( scip != NULL );
5249  assert( conshdlr != NULL );
5250  assert( conss != NULL );
5251  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5252  assert( result != NULL );
5253 
5254  /* perform separation */
5255  SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, NULL, result) );
5256 
5257  return SCIP_OKAY;
5258 }
5259 
5260 
5261 /** separation method of constraint handler for arbitrary primal solutions */
5262 static
5263 SCIP_DECL_CONSSEPASOL(consSepasolIndicator)
5264 { /*lint --e{715}*/
5265  assert( scip != NULL );
5266  assert( conshdlr != NULL );
5267  assert( conss != NULL );
5268  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5269  assert( result != NULL );
5270 
5271  /* perform separation */
5272  SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, sol, result) );
5273 
5274  return SCIP_OKAY;
5275 }
5276 
5277 
5278 /** constraint enforcing method of constraint handler for LP solutions */
5279 static
5280 SCIP_DECL_CONSENFOLP(consEnfolpIndicator)
5281 { /*lint --e{715}*/
5282  SCIP_CONSHDLRDATA* conshdlrdata;
5283 
5284  assert( scip != NULL );
5285  assert( conshdlr != NULL );
5286  assert( conss != NULL );
5287  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5288  assert( result != NULL );
5289 
5290  if ( solinfeasible )
5291  {
5292  *result = SCIP_FEASIBLE;
5293  return SCIP_OKAY;
5294  }
5295 
5296  /* get constraint handler data */
5297  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5298  assert( conshdlrdata != NULL );
5299 
5300  SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, conshdlrdata->genlogicor, result) );
5301 
5302  return SCIP_OKAY;
5303 }
5304 
5305 
5306 /** constraint enforcing method of constraint handler for pseudo solutions */
5307 static
5308 SCIP_DECL_CONSENFOPS(consEnfopsIndicator)
5309 { /*lint --e{715}*/
5310  assert( scip != NULL );
5311  assert( conshdlr != NULL );
5312  assert( conss != NULL );
5313  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5314  assert( result != NULL );
5315 
5316  if ( solinfeasible )
5317  {
5318  *result = SCIP_FEASIBLE;
5319  return SCIP_OKAY;
5320  }
5321 
5322  if ( objinfeasible )
5323  {
5324  *result = SCIP_DIDNOTRUN;
5325  return SCIP_OKAY;
5326  }
5327 
5328  SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, TRUE, result) );
5329 
5330  return SCIP_OKAY;
5331 }
5332 
5333 
5334 /** feasibility check method of constraint handler for integral solutions */
5335 static
5336 SCIP_DECL_CONSCHECK(consCheckIndicator)
5337 { /*lint --e{715}*/
5338  SCIP_SOL* trysol = NULL;
5339  SCIP_CONSHDLRDATA* conshdlrdata;
5340  SCIP_Bool someLinconsNotActive;
5341  SCIP_Bool changedSol;
5342  int c;
5343 
5344  assert( scip != NULL );
5345  assert( conshdlr != NULL );
5346  assert( conss != NULL );
5347  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5348  assert( result != NULL );
5349 
5350  SCIPdebugMessage("Checking %d indicator constraints <%s>.\n", nconss, SCIPconshdlrGetName(conshdlr) );
5351 
5352  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5353  assert( conshdlrdata != NULL );
5354 
5355  /* copy solution if it makes sense (will send solution to trysol heuristic in any case (see below) */
5356  if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM && SCIPgetStage(scip) < SCIP_STAGE_SOLVED && conshdlrdata->trysolutions && conshdlrdata->heurtrysol != NULL )
5357  {
5358  SCIP_CALL( SCIPcreateSolCopy(scip, &trysol, sol) );
5359  assert( trysol != NULL );
5360  SCIP_CALL( SCIPunlinkSol(scip, trysol) );
5361  }
5362 
5363  /* check each constraint */
5364  *result = SCIP_FEASIBLE;
5365  changedSol = FALSE;
5366  someLinconsNotActive = FALSE;
5367  for (c = 0; c < nconss; ++c)
5368  {
5369  SCIP_CONSDATA* consdata;
5370 
5371  assert( conss[c] != NULL );
5372  consdata = SCIPconsGetData(conss[c]);
5373  assert( consdata != NULL );
5374  assert( consdata->binvar != NULL );
5375 
5376  /* if the linear constraint has not been generated, we do nothing */
5377  if ( ! consdata->linconsactive )
5378  {
5379  someLinconsNotActive = TRUE;
5380  continue;
5381  }
5382 
5383  assert( consdata->slackvar != NULL );
5384  /* if printreason is true it can happen that non-integral solutions are checked */
5385  assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
5386 
5387  /* if constraint is infeasible */
5388  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) &&
5389  ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) )
5390  {
5391  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
5392  *result = SCIP_INFEASIBLE;
5393 
5394  if ( printreason )
5395  {
5396  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
5397  SCIPinfoMessage(scip, NULL, ";\nviolation: <%s> = %g and <%s> = %.15g\n",
5398  SCIPvarGetName(consdata->binvar), SCIPgetSolVal(scip, sol, consdata->binvar),
5399  SCIPvarGetName(consdata->slackvar), SCIPgetSolVal(scip, sol, consdata->slackvar));
5400  }
5401 
5402  /* try to make solution feasible if it makes sense - otherwise exit */
5403  if ( trysol != NULL )
5404  {
5405  SCIP_Bool changed;
5406  SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
5407  changedSol = changedSol || changed;
5408  }
5409  else
5410  {
5411  SCIPdebugMessage("Indicator constraints are not feasible.\n");
5412  return SCIP_OKAY;
5413  }
5414  }
5415  else
5416  {
5417  if ( trysol != NULL )
5418  {
5419  SCIP_Bool changed;
5420  SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
5421  changedSol = changedSol || changed;
5422  }
5423  }
5424  }
5425 
5426  /* if some linear constraints are not active, we need to check feasibility via the alternative polyhedron */
5427  if ( someLinconsNotActive )
5428  {
5429  SCIP_LPI* lp;
5430  SCIP_Bool infeasible;
5431  SCIP_Bool error;
5432  SCIP_Bool* S;
5433 
5434  lp = conshdlrdata->altlp;
5435  assert( conshdlrdata->sepaalternativelp );
5436 
5437  /* the check maybe called before we have build the alternative polyhedron -> return SCIP_INFEASIBLE */
5438  if ( lp != NULL )
5439  {
5440 #ifndef NDEBUG
5441  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
5442 #endif
5443 
5444  /* change coefficients of bounds in alternative LP */
5445  if ( conshdlrdata->updatebounds )
5446  {
5447  SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
5448  }
5449 
5450  /* scale first row if necessary */
5451  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
5452 
5453  /* set objective function to current solution */
5454  SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
5455 
5456  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
5457 
5458  /* set up variables fixed to 1 */
5459  for (c = 0; c < nconss; ++c)
5460  {
5461  SCIP_CONSDATA* consdata;
5462 
5463  assert( conss[c] != NULL );
5464  consdata = SCIPconsGetData(conss[c]);
5465  assert( consdata != NULL );
5466 
5467  /* if printreason is true it can happen that non-integral solutions are checked */
5468  assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
5469  if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
5470  S[c] = TRUE;
5471  else
5472  S[c] = FALSE;
5473  }
5474 
5475  /* fix the variables in S */
5476  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
5477 
5478  /* check feasibility */
5480  SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, TRUE, &infeasible, &error) );
5482 
5483  if ( error )
5484  return SCIP_LPERROR;
5485 
5486  if ( ! infeasible )
5487  *result = SCIP_INFEASIBLE;
5488 
5489  /* reset bounds */
5490  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
5491 
5492 #ifndef NDEBUG
5493  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
5494 #endif
5495 
5496  SCIPfreeBufferArray(scip, &S);
5497  }
5498  else
5499  *result = SCIP_INFEASIBLE;
5500  }
5501  else
5502  {
5503  /* tell heur_trysol about solution - it will pass it to SCIP */
5504  if ( trysol != NULL && changedSol )
5505  {
5506  assert(conshdlrdata->heurtrysol != NULL);
5507  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->heurtrysol, trysol) );
5508  }
5509  }
5510 
5511  if ( trysol != NULL )
5512  SCIP_CALL( SCIPfreeSol(scip, &trysol) );
5513 
5514  if ( *result == SCIP_INFEASIBLE )
5515  {
5516  SCIPdebugMessage("Indicator constraints are not feasible.\n");
5517  return SCIP_OKAY;
5518  }
5519 
5520  /* at this point we are feasible */
5521  SCIPdebugMessage("Indicator constraints are feasible.\n");
5522 
5523  return SCIP_OKAY;
5524 }
5525 
5526 
5527 /** domain propagation method of constraint handler */
5528 static
5529 SCIP_DECL_CONSPROP(consPropIndicator)
5530 { /*lint --e{715}*/
5531  SCIP_CONSHDLRDATA* conshdlrdata;
5532  int ngen;
5533  int c;
5534 
5535  assert( scip != NULL );
5536  assert( conshdlr != NULL );
5537  assert( conss != NULL );
5538  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5539  assert( result != NULL );
5540  *result = SCIP_DIDNOTRUN;
5541 
5542  assert( SCIPisTransformed(scip) );
5543 
5544  SCIPdebugMessage("Start propagation of constraint handler <%s>.\n", SCIPconshdlrGetName(conshdlr));
5545  ngen = 0;
5546 
5547  /* get constraint handler data */
5548  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5549  assert( conshdlrdata != NULL );
5550 
5551  /* check each constraint */
5552  for (c = 0; c < nconss; ++c)
5553  {
5554  SCIP_CONS* cons;
5555  SCIP_CONSDATA* consdata;
5556  SCIP_Bool cutoff;
5557  int cnt;
5558 
5559  *result = SCIP_DIDNOTFIND;
5560  assert( conss[c] != NULL );
5561  cons = conss[c];
5562  consdata = SCIPconsGetData(cons);
5563  assert( consdata != NULL );
5564  /* SCIPdebugMessage("Propagating indicator constraint <%s>.\n", SCIPconsGetName(cons) ); */
5565 
5566  *result = SCIP_DIDNOTFIND;
5567 
5568  SCIP_CALL( propIndicator(scip, cons, consdata, conshdlrdata->dualreductions, conshdlrdata->addopposite, &cutoff, &cnt) );
5569  if ( cutoff )
5570  {
5571  *result = SCIP_CUTOFF;
5572  return SCIP_OKAY;
5573  }
5574  ngen += cnt;
5575  }
5576  SCIPdebugMessage("Propagated %d domains in constraint handler <%s>.\n", ngen, SCIPconshdlrGetName(conshdlr));
5577  if ( ngen > 0 )
5578  *result = SCIP_REDUCEDDOM;
5579 
5580  return SCIP_OKAY;
5581 }
5582 
5583 
5584 /** propagation conflict resolving method of constraint handler
5585  *
5586  * We check which bound changes were the reason for infeasibility. We use that @a inferinfo is 0 if
5587  * the binary variable has bounds that fix it to be nonzero (these bounds are the reason). Likewise
5588  * @a inferinfo is 1 if the slack variable has bounds that fix it to be nonzero.
5589  */
5590 static
5591 SCIP_DECL_CONSRESPROP(consRespropIndicator)
5592 { /*lint --e{715}*/
5593  SCIP_CONSDATA* consdata;
5594 
5595  assert( scip != NULL );
5596  assert( cons != NULL );
5597  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5598  assert( infervar != NULL );
5599  assert( bdchgidx != NULL );
5600  assert( result != NULL );
5601 
5602  *result = SCIP_DIDNOTFIND;
5603  SCIPdebugMessage("Propagation resolution method of indicator constraint <%s>.\n", SCIPconsGetName(cons));
5604 
5605  consdata = SCIPconsGetData(cons);
5606  assert( consdata != NULL );
5607  assert( inferinfo == 0 || inferinfo == 1 || inferinfo == 2 );
5608  assert( consdata->linconsactive );
5609 
5610  /* if the binary variable was the reason */
5611  if ( inferinfo == 0 )
5612  {
5613  assert( SCIPvarGetLbAtIndex(consdata->binvar, bdchgidx, FALSE) > 0.5 );
5614  assert( infervar != consdata->binvar );
5615 
5616  SCIP_CALL( SCIPaddConflictLb(scip, consdata->binvar, bdchgidx) );
5617  }
5618  else if ( inferinfo == 1 )
5619  {
5620  /* if the slack variable fixed to a positive value was the reason */
5621  assert( infervar != consdata->slackvar );
5622  /* Use a weaker comparison to SCIPvarGetLbAtIndex here (i.e., SCIPisPositive instead of SCIPisFeasPositive),
5623  * because SCIPvarGetLbAtIndex might differ from the local bound at time bdchgidx by epsilon. */
5624  assert( SCIPisPositive(scip, SCIPvarGetLbAtIndex(consdata->slackvar, bdchgidx, FALSE)) );
5625  SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, bdchgidx) );
5626  }
5627  else
5628  {
5629  assert( inferinfo == 2 );
5630  assert( SCIPisFeasZero(scip, SCIPvarGetUbAtIndex(consdata->slackvar, bdchgidx, FALSE)) );
5631  assert( SCIPconshdlrGetData(conshdlr)->dualreductions );
5632  SCIP_CALL( SCIPaddConflictUb(scip, consdata->slackvar, bdchgidx) );
5633  }
5634  *result = SCIP_SUCCESS;
5635 
5636  return SCIP_OKAY;
5637 }
5638 
5639 
5640 /** variable rounding lock method of constraint handler
5641  *
5642  * The up-rounding of the binary and slack variable may violate the constraint. If the linear
5643  * constraint is not active, we lock all variables in the depending constraint - otherwise they
5644  * will be fixed by dual presolving methods.
5645  */
5646 static
5647 SCIP_DECL_CONSLOCK(consLockIndicator)
5648 {
5649  SCIP_CONSDATA* consdata;
5650 
5651  assert( scip != NULL );
5652  assert( conshdlr != NULL );
5653  assert( cons != NULL );
5654  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5655  consdata = SCIPconsGetData(cons);
5656  assert( consdata != NULL );
5657  assert( consdata->binvar != NULL );
5658 
5659  SCIPdebugMessage("%socking constraint <%s>.\n", (nlocksneg < 0) || (nlockspos < 0) ? "Unl" : "L", SCIPconsGetName(cons));
5660 
5661  SCIP_CALL( SCIPaddVarLocks(scip, consdata->binvar, nlocksneg, nlockspos) );
5662 
5663  if ( consdata->linconsactive )
5664  {
5665  assert( consdata->slackvar != NULL );
5666  SCIP_CALL( SCIPaddVarLocks(scip, consdata->slackvar, nlocksneg, nlockspos) );
5667  }
5668  else
5669  {
5670  SCIP_VAR** linvars;
5671  SCIP_Real* linvals;
5672  SCIP_Bool haslhs;
5673  SCIP_Bool hasrhs;
5674  int nlinvars;
5675  int j;
5676 
5677  assert( consdata->lincons != NULL );
5678  assert( consdata->slackvar == NULL );
5679 
5680  nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
5681  linvars = SCIPgetVarsLinear(scip, consdata->lincons);
5682  linvals = SCIPgetValsLinear(scip, consdata->lincons);
5683  haslhs = ! SCIPisInfinity(scip, REALABS(SCIPgetLhsLinear(scip, consdata->lincons)));
5684  hasrhs = ! SCIPisInfinity(scip, REALABS(SCIPgetRhsLinear(scip, consdata->lincons)));
5685 
5686  for (j = 0; j < nlinvars; ++j)
5687  {
5688  assert( ! SCIPisZero(scip, linvals[j]) );
5689  if ( SCIPisPositive(scip, linvals[j]) )
5690  {
5691  if ( haslhs )
5692  {
5693  SCIP_CALL( SCIPaddVarLocks(scip, linvars[j], nlockspos, nlocksneg) );
5694  }
5695  if ( hasrhs )
5696  {
5697  SCIP_CALL( SCIPaddVarLocks(scip, linvars[j], nlocksneg, nlockspos) );
5698  }
5699  }
5700  else
5701  {
5702  if ( haslhs )
5703  {
5704  SCIP_CALL( SCIPaddVarLocks(scip, linvars[j], nlocksneg, nlockspos) );
5705  }
5706  if ( hasrhs )
5707  {
5708  SCIP_CALL( SCIPaddVarLocks(scip, linvars[j], nlockspos, nlocksneg) );
5709  }
5710  }
5711  }
5712  }
5713 
5714  return SCIP_OKAY;
5715 }
5716 
5717 
5718 /** constraint display method of constraint handler */
5719 static
5720 SCIP_DECL_CONSPRINT(consPrintIndicator)
5721 {
5722  SCIP_CONSDATA* consdata;
5723  SCIP_VAR* binvar;
5724  int rhs;
5725 
5726  assert( scip != NULL );
5727  assert( conshdlr != NULL );
5728  assert( cons != NULL );
5729  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5730 
5731  consdata = SCIPconsGetData(cons);
5732  assert( consdata != NULL );
5733  assert( consdata->binvar != NULL );
5734 
5735  binvar = consdata->binvar;
5736  rhs = 1;
5737  if ( SCIPvarGetStatus(binvar) == SCIP_VARSTATUS_NEGATED )
5738  {
5739  rhs = 0;
5740  binvar = SCIPvarGetNegatedVar(binvar);
5741  }
5742  SCIPinfoMessage(scip, file, "<%s> = %d", SCIPvarGetName(binvar), rhs);
5743 
5744  assert( consdata->slackvar != NULL );
5745  assert( consdata->lincons != NULL );
5746  SCIPinfoMessage(scip, file, " -> <%s> = 0", SCIPvarGetName(consdata->slackvar));
5747 
5748  return SCIP_OKAY;
5749 }
5750 
5751 
5752 /** constraint copying method of constraint handler */
5753 static
5754 SCIP_DECL_CONSCOPY(consCopyIndicator)
5755 { /*lint --e{715}*/
5756  SCIP_CONSDATA* sourceconsdata;
5757  SCIP_CONS* targetlincons = NULL;
5758  SCIP_VAR* targetbinvar = NULL;
5759  SCIP_VAR* targetslackvar = NULL;
5760  SCIP_CONS* sourcelincons;
5761  SCIP_CONSHDLR* conshdlrlinear;
5762  const char* consname;
5763 
5764  assert( scip != NULL );
5765  assert( sourcescip != NULL );
5766  assert( sourcecons != NULL );
5767  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 );
5768 
5769  *valid = TRUE;
5770 
5771  if ( name != NULL )
5772  consname = name;
5773  else
5774  consname = SCIPconsGetName(sourcecons);
5775 
5776  SCIPdebugMessage("Copying indicator constraint <%s> ...\n", consname);
5777 
5778  if ( modifiable )
5779  {
5780  SCIPwarningMessage(scip, "cannot create modifiable indicator constraint when trying to copy constraint <%s>,\n", SCIPconsGetName(sourcecons));
5781  *valid = FALSE;
5782  return SCIP_OKAY;
5783  }
5784 
5785  sourceconsdata = SCIPconsGetData(sourcecons);
5786  assert( sourceconsdata != NULL );
5787 
5788  /* get linear constraint */
5789  sourcelincons = sourceconsdata->lincons;
5790 
5791  /* if the constraint has been deleted -> create empty constraint (multi-aggregation might still contain slack variable, so indicator is valid) */
5792  if ( SCIPconsIsDeleted(sourcelincons) )
5793  {
5794  SCIPdebugMessage("Linear constraint <%s> deleted! Create empty linear constraint.\n", SCIPconsGetName(sourceconsdata->lincons));
5795 
5796  SCIP_CALL( SCIPcreateConsLinear(scip, &targetlincons, "dummy", 0, NULL, NULL, 0.0, SCIPinfinity(scip),
5798  SCIP_CALL( SCIPaddCons(scip, targetlincons) );
5799  }
5800  else
5801  {
5802  /* get copied version of linear constraint */
5803  assert( sourcelincons != NULL );
5804  conshdlrlinear = SCIPfindConshdlr(sourcescip, "linear");
5805  assert( conshdlrlinear != NULL );
5806 
5807  /* if copying scip after transforming the original instance before presolving, we need to correct the linear
5808  * constraint pointer */
5809  if ( SCIPisTransformed(sourcescip) && ! SCIPconsIsTransformed(sourcelincons) )
5810  {
5811  SCIP_CONS* translincons;
5812 
5813  /* adjust the linear constraint in the original constraint (no need to release translincons) */
5814  SCIP_CALL( SCIPgetTransformedCons(sourcescip, sourcelincons, &translincons) );
5815  assert(translincons != NULL);
5816  SCIP_CALL( SCIPreleaseCons(sourcescip, &sourceconsdata->lincons) );
5817  SCIP_CALL( SCIPcaptureCons(sourcescip, translincons) );
5818  sourceconsdata->lincons = translincons;
5819  sourcelincons = translincons;
5820  }
5821 
5822  SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, sourcelincons, &targetlincons, conshdlrlinear, varmap, consmap, SCIPconsGetName(sourcelincons),
5823  SCIPconsIsInitial(sourcelincons), SCIPconsIsSeparated(sourcelincons), SCIPconsIsEnforced(sourcelincons), SCIPconsIsChecked(sourcelincons),
5824  SCIPconsIsPropagated(sourcelincons), SCIPconsIsLocal(sourcelincons), SCIPconsIsModifiable(sourcelincons), SCIPconsIsDynamic(sourcelincons),
5825  SCIPconsIsRemovable(sourcelincons), SCIPconsIsStickingAtNode(sourcelincons), global, valid) );
5826  }
5827 
5828  /* find copied variable corresponding to binvar */
5829  if ( *valid )
5830  {
5831  SCIP_VAR* sourcebinvar;
5832 
5833  sourcebinvar = sourceconsdata->binvar;
5834  assert( sourcebinvar != NULL );
5835 
5836  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcebinvar, &targetbinvar, varmap, consmap, global, valid) );
5837  }
5838 
5839  /* find copied variable corresponding to slackvar */
5840  if ( *valid )
5841  {
5842  SCIP_VAR* sourceslackvar;
5843 
5844  sourceslackvar = sourceconsdata->slackvar;
5845  assert( sourceslackvar != NULL );
5846 
5847  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourceslackvar, &targetslackvar, varmap, consmap, global, valid) );
5848  }
5849 
5850  /* create indicator constraint */
5851  if ( *valid )
5852  {
5853  assert( targetlincons != NULL );
5854  assert( targetbinvar != NULL );
5855  assert( targetslackvar != NULL );
5856 
5857  /* creates indicator constraint (and captures the linear constraint) */
5858  SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, consname, targetbinvar, targetlincons, targetslackvar,
5859  initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
5860  }
5861  else
5862  {
5863  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "could not copy linear constraint <%s>\n", SCIPconsGetName(sourcelincons));
5864  }
5865 
5866  /* relase copied linear constraint */
5867  if( targetlincons != NULL )
5868  {
5869  SCIP_CALL( SCIPreleaseCons(scip, &targetlincons) );
5870  }
5871 
5872  return SCIP_OKAY;
5873 }
5874 
5875 
5876 /** constraint parsing method of constraint handler */
5877 static
5878 SCIP_DECL_CONSPARSE(consParseIndicator)
5879 { /*lint --e{715}*/
5880  char binvarname[1024];
5881  char slackvarname[1024];
5882  SCIP_VAR* binvar;
5883  SCIP_VAR* slackvar;
5884  SCIP_CONS* lincons;
5885  const char* posstr;
5886  int zeroone;
5887  int nargs;
5888 
5889  *success = TRUE;
5890 
5891  /* read indicator constraint */
5892  nargs = sscanf(str, " <%1023[^>]> = %d -> <%1023[^>]> = 0", binvarname, &zeroone, slackvarname);
5893 
5894  if ( nargs != 3 )
5895  {
5896  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0.\n%s\n", str);
5897  *success = FALSE;
5898  return SCIP_OKAY;
5899  }
5900 
5901  if ( zeroone != 0 && zeroone != 1 )
5902  {
5903  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0.\n%s\n", str);
5904  *success = FALSE;
5905  return SCIP_OKAY;
5906  }
5907 
5908  /* get binary variable */
5909  binvar = SCIPfindVar(scip, binvarname);
5910  if ( binvar == NULL )
5911  {
5912  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", binvarname);
5913  *success = FALSE;
5914  return SCIP_OKAY;
5915  }
5916  /* check whether we need the complemented variable */
5917  if ( zeroone == 0 )
5918  SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
5919 
5920  /* get slack variable */
5921  slackvar = SCIPfindVar(scip, slackvarname);
5922  if ( slackvar == NULL )
5923  {
5924  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", slackvarname);
5925  *success = FALSE;
5926  return SCIP_OKAY;
5927  }
5928 
5929  /* find matching linear constraint */
5930  posstr = strstr(slackvarname, "indslack");
5931  if ( posstr == NULL )
5932  {
5933  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "strange slack variable name: <%s>\n", slackvarname);
5934  *success = FALSE;
5935  return SCIP_OKAY;
5936  }
5937 
5938  /* overwrite binvarname: set up name for linear constraint */
5939  (void) SCIPsnprintf(binvarname, 1023, "indlin%s", posstr+8);
5940 
5941  lincons = SCIPfindCons(scip, binvarname);
5942  if ( lincons == NULL )
5943  {
5944  /* if not found - check without indlin */
5945  (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+9);
5946  lincons = SCIPfindCons(scip, binvarname);
5947 
5948  if ( lincons == NULL )
5949  {
5950  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: unknown linear constraint <indlin_%s> or <%s>.\n",
5951  name, binvarname, binvarname);
5952  *success = FALSE;
5953  return SCIP_OKAY;
5954  }
5955  }
5956 
5957  /* create indicator constraint */
5958  SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
5959  initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
5960 
5961  return SCIP_OKAY;
5962 }
5963 
5964 
5965 /** constraint enabling notification method of constraint handler */
5966 static
5967 SCIP_DECL_CONSENABLE(consEnableIndicator)
5968 {
5969  SCIP_CONSHDLRDATA* conshdlrdata;
5970  SCIP_CONSDATA* consdata;
5971 
5972  assert( scip != NULL );
5973  assert( conshdlr != NULL );
5974  assert( cons != NULL );
5975  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5976 
5977  SCIPdebugMessage("Enabling constraint <%s>.\n", SCIPconsGetName(cons));
5978 
5979  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5980  assert( conshdlrdata != NULL );
5981 
5982  consdata = SCIPconsGetData(cons);
5983  assert( consdata != NULL );
5984 
5985  if ( conshdlrdata->altlp != NULL )
5986  {
5987  assert( conshdlrdata->sepaalternativelp );
5988 
5989  if ( consdata->colindex >= 0 )
5990  {
5991  SCIP_CALL( unfixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
5992  }
5993  }
5994 
5995  return SCIP_OKAY;
5996 }
5997 
5998 
5999 /** constraint disabling notification method of constraint handler */
6000 static
6001 SCIP_DECL_CONSDISABLE(consDisableIndicator)
6002 {
6003  SCIP_CONSHDLRDATA* conshdlrdata;
6004 
6005  assert( scip != NULL );
6006  assert( conshdlr != NULL );
6007  assert( cons != NULL );
6008  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6009 
6010  SCIPdebugMessage("Disabling constraint <%s>.\n", SCIPconsGetName(cons));
6011 
6012  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6013  assert( conshdlrdata != NULL );
6014 
6015  if ( conshdlrdata->altlp != NULL )
6016  {
6017  SCIP_CONSDATA* consdata;
6018 
6019  consdata = SCIPconsGetData(cons);
6020  assert( consdata != NULL );
6021  assert( conshdlrdata->sepaalternativelp );
6022 
6023  if ( consdata->colindex >= 0 )
6024  {
6025  SCIP_CALL( fixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
6026  }
6027  }
6028 
6029  return SCIP_OKAY;
6030 }
6031 
6032 
6033 /** constraint method of constraint handler which returns the variables (if possible) */
6034 static
6035 SCIP_DECL_CONSGETVARS(consGetVarsIndicator)
6036 { /*lint --e{715}*/
6037  SCIP_CONSDATA* consdata;
6038  int nvars = 0;
6039 
6040  assert( scip != NULL );
6041  assert( cons != NULL );
6042  assert( vars != NULL );
6043  assert( varssize >= 0 );
6044  assert( success != NULL );
6045 
6046  if ( varssize < 0 )
6047  return SCIP_INVALIDDATA;
6048 
6049  (*success) = TRUE;
6050 
6051  /* if indicator constraint is already deleted */
6052  if ( SCIPconsIsDeleted(cons) )
6053  return SCIP_OKAY;
6054 
6055  consdata = SCIPconsGetData(cons);
6056  assert( consdata != NULL );
6057  assert( consdata->lincons != NULL );
6058 
6059  if ( consdata->binvar != NULL )
6060  {
6061  assert( varssize > 0 );
6062  vars[nvars++] = consdata->binvar;
6063  }
6064  if ( consdata->slackvar != NULL )
6065  {
6066  assert( varssize > nvars );
6067  vars[nvars++] = consdata->slackvar;
6068  }
6069 
6070  /* if linear constraint of indicator is already deleted */
6071  if ( SCIPconsIsDeleted(consdata->lincons) )
6072  return SCIP_OKAY;
6073 
6074  SCIP_CALL( SCIPgetConsVars(scip, consdata->lincons, &(vars[nvars]), varssize - nvars, success) );
6075 
6076  return SCIP_OKAY;
6077 }
6078 
6079 /** constraint method of constraint handler which returns the number of variables (if possible) */
6080 static
6081 SCIP_DECL_CONSGETNVARS(consGetNVarsIndicator)
6082 { /*lint --e{715}*/
6083  SCIP_CONSDATA* consdata;
6084  int nlinvars;
6085 
6086  assert( scip != NULL );
6087  assert( cons != NULL );
6088  assert( nvars != NULL );
6089  assert( success != NULL );
6090 
6091  (*success) = TRUE;
6092  *nvars = 0;
6093 
6094  /* if indicator constraint is already deleted */
6095  if ( SCIPconsIsDeleted(cons) )
6096  return SCIP_OKAY;
6097 
6098  consdata = SCIPconsGetData(cons);
6099  assert( consdata != NULL );
6100  assert( consdata->lincons != NULL );
6101 
6102  if ( consdata->binvar != NULL )
6103  ++(*nvars);
6104  if ( consdata->slackvar != NULL )
6105  ++(*nvars);
6106 
6107  /* if linear constraint of indicator is already deleted */
6108  if ( SCIPconsIsDeleted(consdata->lincons) )
6109  return SCIP_OKAY;
6110 
6111  SCIP_CALL( SCIPgetConsNVars(scip, consdata->lincons, &nlinvars, success) );
6112 
6113  if ( *success )
6114  {
6115  assert( nlinvars >= 0 );
6116  *nvars += nlinvars;
6117  }
6118 
6119  return SCIP_OKAY;
6120 }
6121 
6122 /* ---------------- Constraint specific interface methods ---------------- */
6123 
6124 /** creates the handler for indicator constraints and includes it in SCIP */
6126  SCIP* scip /**< SCIP data structure */
6127  )
6128 {
6129  SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
6130  SCIP_CONFLICTHDLR* conflicthdlr;
6131  SCIP_CONSHDLRDATA* conshdlrdata;
6132  SCIP_CONSHDLR* conshdlr;
6133 
6134  /* create constraint handler data (used in conflicthdlrdata) */
6135  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
6136 
6137  conshdlrdata->eventhdlrbound = NULL;
6138  /* create event handler for bound change events */
6139  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlrbound),
6140  EVENTHDLR_BOUND_NAME, EVENTHDLR_BOUND_DESC, eventExecIndicatorBound, NULL) );
6141  assert(conshdlrdata->eventhdlrbound != NULL);
6142 
6143  conshdlrdata->eventhdlrrestart = NULL;
6144  /* create event handler for restart events */
6145  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlrrestart), EVENTHDLR_RESTART_NAME, EVENTHDLR_RESTART_DESC,
6146  eventExecIndicatorRestart, NULL) );
6147  assert(conshdlrdata->eventhdlrrestart != NULL);
6148 
6149  /* get event handler for bound change events */
6150  if ( conshdlrdata->eventhdlrbound == NULL )
6151  {
6152  SCIPerrorMessage("event handler for indicator constraints not found.\n");
6153  return SCIP_PLUGINNOTFOUND;
6154  }
6155 
6156  /* get event handler for bound change events */
6157  if ( conshdlrdata->eventhdlrrestart == NULL )
6158  {
6159  SCIPerrorMessage("event handler for restarting indicator constraints not found.\n");
6160  return SCIP_PLUGINNOTFOUND;
6161  }
6162 
6163  conshdlrdata->heurtrysol = NULL;
6164  conshdlrdata->sepaalternativelp = DEFAULT_SEPAALTERNATIVELP;
6165  conshdlrdata->nolinconscont = DEFAULT_NOLINCONSCONT;
6166  conshdlrdata->forcerestart = DEFAULT_FORCERESTART;
6167 
6168  /* initialize constraint handler data */
6169  initConshdlrData(conshdlrdata);
6170 
6171  /* the following three variables cannot be initialized in the above method, because initConshdlrData() is also called
6172  * in the CONSINIT callback, but these variables might be used even before the is ccallback is called, so we would
6173  * lose the data added before calling this callback
6174  */
6175  conshdlrdata->addlincons = NULL;
6176  conshdlrdata->naddlincons = 0;
6177  conshdlrdata->maxaddlincons = 0;
6178 
6179  /* include constraint handler */
6182  consEnfolpIndicator, consEnfopsIndicator, consCheckIndicator, consLockIndicator,
6183  conshdlrdata) );
6184 
6185  assert(conshdlr != NULL);
6186 
6187  /* set non-fundamental callbacks via specific setter functions */
6188  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyIndicator, consCopyIndicator) );
6189  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteIndicator) );
6190  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableIndicator) );
6191  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableIndicator) );
6192  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitIndicator) );
6193  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolIndicator) );
6194  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeIndicator) );
6195  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsIndicator) );
6196  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsIndicator) );
6197  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitIndicator) );
6198  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreIndicator) );
6199  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolIndicator) );
6200  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpIndicator) );
6201  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseIndicator) );
6202  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolIndicator, CONSHDLR_MAXPREROUNDS, CONSHDLR_DELAYPRESOL) );
6203  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintIndicator) );
6204  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropIndicator, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
6206  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropIndicator) );
6207  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpIndicator, consSepasolIndicator, CONSHDLR_SEPAFREQ,
6209  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransIndicator) );
6210 
6211  /* create conflict handler data */
6212  SCIP_CALL( SCIPallocMemory(scip, &conflicthdlrdata) );
6213  conflicthdlrdata->conshdlrdata = conshdlrdata;
6214  conflicthdlrdata->conshdlr = conshdlr;
6215  assert( conflicthdlrdata->conshdlr != NULL );
6216 
6217  /* create conflict handler for indicator constraints */
6219  conflictExecIndicator, conflicthdlrdata) );
6220 
6221  SCIP_CALL( SCIPsetConflicthdlrFree(scip, conflicthdlr, conflictFreeIndicator) );
6222 
6223  /* add indicator constraint handler parameters */
6225  "constraints/indicator/branchindicators",
6226  "Branch on indicator constraints in enforcing?",
6227  &conshdlrdata->branchindicators, TRUE, DEFAULT_BRANCHINDICATORS, NULL, NULL) );
6228 
6230  "constraints/indicator/genlogicor",
6231  "Generate logicor constraints instead of cuts?",
6232  &conshdlrdata->genlogicor, TRUE, DEFAULT_GENLOGICOR, NULL, NULL) );
6233 
6235  "constraints/indicator/addcoupling",
6236  "Add coupling constraints if big-M is small enough?",
6237  &conshdlrdata->addcoupling, TRUE, DEFAULT_ADDCOUPLING, NULL, NULL) );
6238 
6240  "constraints/indicator/maxcouplingvalue",
6241  "maximum coefficient for binary variable in coupling constraint",
6242  &conshdlrdata->maxcouplingvalue, TRUE, DEFAULT_MAXCOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
6243 
6245  "constraints/indicator/addcouplingcons",
6246  "Add initial coupling inequalities as linear constraints, if 'addcoupling' is true?",
6247  &conshdlrdata->addcouplingcons, TRUE, DEFAULT_ADDCOUPLINGCONS, NULL, NULL) );
6248 
6250  "constraints/indicator/sepacouplingcuts",
6251  "Should the coupling inequalities be separated dynamically?",
6252  &conshdlrdata->sepacouplingcuts, TRUE, DEFAULT_SEPACOUPLINGCUTS, NULL, NULL) );
6253 
6255  "constraints/indicator/sepacouplinglocal",
6256  "Allow to use local bounds in order to separated coupling inequalities?",
6257  &conshdlrdata->sepacouplinglocal, TRUE, DEFAULT_SEPACOUPLINGLOCAL, NULL, NULL) );
6258 
6260  "constraints/indicator/sepacouplingvalue",
6261  "maximum coefficient for binary variable in separated coupling constraint",
6262  &conshdlrdata->sepacouplingvalue, TRUE, DEFAULT_SEPACOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
6263 
6265  "constraints/indicator/updatebounds",
6266  "Update bounds of original variables for separation?",
6267  &conshdlrdata->updatebounds, TRUE, DEFAULT_UPDATEBOUNDS, NULL, NULL) );
6268 
6270  "constraints/indicator/maxconditionaltlp",
6271  "maximum estimated condition of the solution basis matrix of the alternative LP to be trustworthy (0.0 to disable check)",
6272  &conshdlrdata->maxconditionaltlp, TRUE, DEFAULT_MAXCONDITIONALTLP, 0.0, SCIP_REAL_MAX, NULL, NULL) );
6273 
6274  SCIP_CALL( SCIPaddIntParam(scip,
6275  "constraints/indicator/maxsepacuts",
6276  "maximal number of cuts separated per separation round",
6277  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
6278 
6279  SCIP_CALL( SCIPaddIntParam(scip,
6280  "constraints/indicator/maxsepacutsroot",
6281  "maximal number of cuts separated per separation round in the root node",
6282  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
6283 
6285  "constraints/indicator/removeindicators",
6286  "Remove indicator constraint if corresponding variable bound constraint has been added?",
6287  &conshdlrdata->removeindicators, TRUE, DEFAULT_REMOVEINDICATORS, NULL, NULL) );
6288 
6290  "constraints/indicator/generatebilinear",
6291  "Do not generate indicator constraint, but a bilinear constraint instead?",
6292  &conshdlrdata->generatebilinear, TRUE, DEFAULT_GENERATEBILINEAR, NULL, NULL) );
6293 
6295  "constraints/indicator/scaleslackvar",
6296  "Scale slack variable coefficient at construction time?",
6297  &conshdlrdata->scaleslackvar, TRUE, DEFAULT_SCALESLACKVAR, NULL, NULL) );
6298 
6300  "constraints/indicator/trysolutions",
6301  "Try to make solutions feasible by setting indicator variables?",
6302  &conshdlrdata->trysolutions, TRUE, DEFAULT_TRYSOLUTIONS, NULL, NULL) );
6303 
6305  "constraints/indicator/enforcecuts",
6306  "In enforcing try to generate cuts (only if sepaalternativelp is true)?",
6307  &conshdlrdata->enforcecuts, TRUE, DEFAULT_ENFORCECUTS, NULL, NULL) );
6308 
6310  "constraints/indicator/dualreductions",
6311  "should dual reduction steps be performed?",
6312  &conshdlrdata->dualreductions, TRUE, DEFAULT_DUALREDUCTIONS, NULL, NULL) );
6313 
6315  "constraints/indicator/addopposite",
6316  "Add opposite inequality in nodes in which the binary variable has been fixed to 0?",
6317  &conshdlrdata->addopposite, TRUE, DEFAULT_ADDOPPOSITE, NULL, NULL) );
6318 
6320  "constraints/indicator/conflictsupgrade",
6321  "Try to upgrade bounddisjunction conflicts by replacing slack variables?",
6322  &conshdlrdata->conflictsupgrade, TRUE, DEFAULT_CONFLICTSUPGRADE, NULL, NULL) );
6323 
6325  "constraints/indicator/restartfrac",
6326  "fraction of binary variables that need to be fixed before restart occurs (in forcerestart)",
6327  &conshdlrdata->restartfrac, TRUE, DEFAULT_RESTARTFRAC, 0.0, 1.0, NULL, NULL) );
6328 
6330  "constraints/indicator/useotherconss",
6331  "Collect other constraints to alternative LP?",
6332  &conshdlrdata->useotherconss, TRUE, DEFAULT_USEOTHERCONSS, NULL, NULL) );
6333 
6335  "constraints/indicator/trysolfromcover",
6336  "Try to construct a feasible solution from a cover?",
6337  &conshdlrdata->trysolfromcover, TRUE, DEFAULT_TRYSOLFROMCOVER, NULL, NULL) );
6338 
6339  /* parameters that should not be changed after problem stage: */
6341  "constraints/indicator/sepaalternativelp",
6342  "Separate using the alternative LP?",
6343  &conshdlrdata->sepaalternativelp_, TRUE, DEFAULT_SEPAALTERNATIVELP, paramChangedIndicator, NULL) );
6344 
6346  "constraints/indicator/forcerestart",
6347  "force restart if we have a max FS instance and gap is 1?",
6348  &conshdlrdata->forcerestart_, TRUE, DEFAULT_FORCERESTART, paramChangedIndicator, NULL) );
6349 
6351  "constraints/indicator/nolinconscont",
6352  "decompose problem - do not generate linear constraint if all variables are continuous",
6353  &conshdlrdata->nolinconscont_, TRUE, DEFAULT_NOLINCONSCONT, paramChangedIndicator, NULL) );
6354 
6355  return SCIP_OKAY;
6356 }
6357 
6358 
6359 /** creates and captures an indicator constraint
6360  *
6361  * @note @a binvar is checked to be binary only later. This enables a change of the type in
6362  * procedures reading an instance.
6363  *
6364  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
6365  */
6367  SCIP* scip, /**< SCIP data structure */
6368  SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
6369  const char* name, /**< name of constraint */
6370  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
6371  int nvars, /**< number of variables in the inequality */
6372  SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
6373  SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
6374  SCIP_Real rhs, /**< rhs of the inequality */
6375  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
6376  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
6377  * Usually set to TRUE. */
6378  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
6379  * TRUE for model constraints, FALSE for additional, redundant constraints. */
6380  SCIP_Bool check, /**< should the constraint be checked for feasibility?
6381  * TRUE for model constraints, FALSE for additional, redundant constraints. */
6382  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
6383  * Usually set to TRUE. */
6384  SCIP_Bool local, /**< is constraint only valid locally?
6385  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
6386  SCIP_Bool dynamic, /**< is constraint subject to aging?
6387  * Usually set to FALSE. Set to TRUE for own cuts which
6388  * are separated as constraints. */
6389  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
6390  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
6391  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
6392  * if it may be moved to a more global node?
6393  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
6394  )
6395 {
6396  SCIP_CONSHDLR* conshdlr;
6397  SCIP_CONSHDLRDATA* conshdlrdata;
6398  SCIP_CONSDATA* consdata;
6399  SCIP_CONS* lincons;
6400  SCIP_VAR* slackvar;
6401  SCIP_Bool modifiable;
6402  SCIP_Bool linconsactive;
6403  SCIP_VARTYPE slackvartype;
6404  SCIP_Real absvalsum = 0.0;
6405  char s[SCIP_MAXSTRLEN];
6406  int j;
6407 
6408  if ( nvars < 0 )
6409  {
6410  SCIPerrorMessage("Indicator constraint <%s> needs nonnegative number of variables in linear constraint.\n", name);
6411  return SCIP_INVALIDDATA;
6412  }
6413 
6414  modifiable = FALSE;
6415 
6416  /* find the indicator constraint handler */
6417  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
6418  if ( conshdlr == NULL )
6419  {
6420  SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
6421  return SCIP_PLUGINNOTFOUND;
6422  }
6423 
6424  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6425  assert( conshdlrdata != NULL );
6426 
6427  if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
6428  {
6429  SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
6430  return SCIP_INVALIDDATA;
6431  }
6432 
6433  if ( conshdlrdata->nolinconscont && conshdlrdata->generatebilinear )
6434  {
6435  SCIPerrorMessage("constraint handler <%s>: parameters <nolinconscont> and <generatebilinear> cannot both be true.\n", CONSHDLR_NAME);
6436  return SCIP_INVALIDDATA;
6437  }
6438 
6439  /* check if slack variable can be made implicit integer */
6440  slackvartype = SCIP_VARTYPE_IMPLINT;
6441  for (j = 0; j < nvars; ++j)
6442  {
6443  if ( conshdlrdata->scaleslackvar )
6444  absvalsum += REALABS(vals[j]);
6445  if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, vals[j]) )
6446  {
6447  slackvartype = SCIP_VARTYPE_CONTINUOUS;
6448  if ( ! conshdlrdata->scaleslackvar )
6449  break;
6450  }
6451  }
6452 
6453  /* create slack variable */
6454  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
6455  SCIP_CALL( SCIPcreateVar(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0, slackvartype, TRUE, FALSE,
6456  NULL, NULL, NULL, NULL, NULL) );
6457 
6458  SCIP_CALL( SCIPaddVar(scip, slackvar) );
6459 
6460  /* mark slack variable not to be multi-aggregated */
6461  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );
6462 
6463  /* if the problem should be decomposed if only non-integer variables are present */
6464  linconsactive = TRUE;
6465  if ( conshdlrdata->nolinconscont )
6466  {
6467  SCIP_Bool onlyCont = TRUE;
6468 
6469  assert( ! conshdlrdata->generatebilinear );
6470 
6471  /* check whether call variables are non-integer */
6472  for (j = 0; j < nvars; ++j)
6473  {
6474  SCIP_VARTYPE vartype;
6475 
6476  vartype = SCIPvarGetType(vars[j]);
6477  if ( vartype != SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_IMPLINT )
6478  {
6479  onlyCont = FALSE;
6480  break;
6481  }
6482  }
6483 
6484  if ( onlyCont )
6485  linconsactive = FALSE;
6486  }
6487 
6488  /* create linear constraint */
6489  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indlin_%s", name);
6490 
6491  /* if the linear constraint should be activated (lincons is captured) */
6492  if ( linconsactive )
6493  {
6494  /* the constraint is initial if initial is true, enforced, separated, and checked */
6495  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, s, nvars, vars, vals, -SCIPinfinity(scip), rhs,
6496  initial, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
6497  }
6498  else
6499  {
6500  /* create non-active linear constraint, which is neither initial, nor enforced, nor separated, nor checked */
6501  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, s, nvars, vars, vals, -SCIPinfinity(scip), rhs,
6503  }
6504 
6505  /* mark linear constraint not to be upgraded - otherwise we loose control over it */
6506  SCIPconsAddUpgradeLocks(lincons, 1);
6507  assert(SCIPconsGetNUpgradeLocks(lincons) > 0);
6508 
6509  /* add slack variable */
6510  if ( conshdlrdata->scaleslackvar )
6511  {
6512  absvalsum = absvalsum/((SCIP_Real) nvars);
6513  if ( slackvartype == SCIP_VARTYPE_IMPLINT )
6514  absvalsum = SCIPceil(scip, absvalsum);
6515  if ( SCIPisZero(scip, absvalsum) )
6516  absvalsum = 1.0;
6517  SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, -absvalsum) );
6518  }
6519  else
6520  {
6521  SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, -1.0) );
6522  }
6523  SCIP_CALL( SCIPaddCons(scip, lincons) );
6524 
6525  /* check whether we should generate a bilinear constraint instead of an indicator constraint */
6526  if ( conshdlrdata->generatebilinear )
6527  {
6528  SCIP_Real val = 1.0;
6529 
6530  /* create a quadratic constraint with a single bilinear term - note that cons is used */
6531  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL, 1, &binvar, &slackvar, &val, 0.0, 0.0,
6532  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6533  }
6534  else
6535  {
6536  /* create constraint data */
6537  consdata = NULL;
6538  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrbound, conshdlrdata->eventhdlrrestart,
6539  binvar, slackvar, lincons, linconsactive) );
6540  assert( consdata != NULL );
6541 
6542  /* create constraint */
6543  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
6544  local, modifiable, dynamic, removable, stickingatnode) );
6545  }
6546 
6547  /* release slack variable and linear constraint */
6548  SCIP_CALL( SCIPreleaseVar(scip, &slackvar) );
6549  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
6550 
6551  return SCIP_OKAY;
6552 }
6553 
6554 /** creates and captures an indicator constraint
6555  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
6556  * method SCIPcreateConsIndicator(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
6557  *
6558  * @see SCIPcreateConsIndicator() for information about the basic constraint flag configuration
6559  *
6560  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
6561  */
6563  SCIP* scip, /**< SCIP data structure */
6564  SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
6565  const char* name, /**< name of constraint */
6566  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
6567  int nvars, /**< number of variables in the inequality */
6568  SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
6569  SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
6570  SCIP_Real rhs /**< rhs of the inequality */
6571  )
6572 {
6573  assert(scip != NULL);
6574 
6575  SCIP_CALL( SCIPcreateConsIndicator(scip, cons, name, binvar, nvars, vars, vals, rhs,
6576  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6577 
6578  return SCIP_OKAY;
6579 }
6580 
6581 /** creates and captures an indicator constraint with given linear constraint and slack variable
6582  *
6583  * @note @a binvar is checked to be binary only later. This enables a change of the type in
6584  * procedures reading an instance.
6585  *
6586  * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
6587  * the role of a slack variable!
6588  *
6589  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
6590  */
6592  SCIP* scip, /**< SCIP data structure */
6593  SCIP_CONS** cons, /**< pointer to hold the created constraint */
6594  const char* name, /**< name of constraint */
6595  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
6596  SCIP_CONS* lincons, /**< linear constraint */
6597  SCIP_VAR* slackvar, /**< slack variable */
6598  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
6599  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
6600  * Usually set to TRUE. */
6601  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
6602  * TRUE for model constraints, FALSE for additional, redundant constraints. */
6603  SCIP_Bool check, /**< should the constraint be checked for feasibility?
6604  * TRUE for model constraints, FALSE for additional, redundant constraints. */
6605  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
6606  * Usually set to TRUE. */
6607  SCIP_Bool local, /**< is constraint only valid locally?
6608  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
6609  SCIP_Bool dynamic, /**< is constraint subject to aging?
6610  * Usually set to FALSE. Set to TRUE for own cuts which
6611  * are separated as constraints. */
6612  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
6613  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
6614  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
6615  * if it may be moved to a more global node?
6616  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
6617  )
6618 {
6619  SCIP_CONSHDLR* conshdlr;
6620  SCIP_CONSHDLRDATA* conshdlrdata;
6621  SCIP_CONSDATA* consdata;
6622  SCIP_Bool modifiable;
6623  SCIP_Bool linconsactive;
6624 
6625  assert( scip != NULL );
6626  assert( lincons != NULL );
6627  assert( slackvar != NULL );
6628 
6629  modifiable = FALSE;
6630 
6631  /* check whether lincons is really a linear constraint */
6632  conshdlr = SCIPconsGetHdlr(lincons);
6633  if ( strcmp(SCIPconshdlrGetName(conshdlr), "linear") != 0 )
6634  {
6635  SCIPerrorMessage("Lincons constraint is not linear.\n");
6636  return SCIP_INVALIDDATA;
6637  }
6638 
6639  /* find the indicator constraint handler */
6640  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
6641  if ( conshdlr == NULL )
6642  {
6643  SCIPerrorMessage("<%s> constraint handler not found.\n", CONSHDLR_NAME);
6644  return SCIP_PLUGINNOTFOUND;
6645  }
6646 
6647  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6648  assert( conshdlrdata != NULL );
6649 
6650  if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
6651  {
6652  SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
6653  return SCIP_INVALIDDATA;
6654  }
6655 
6656  /* mark slack variable not to be multi-aggregated */
6657  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );
6658 
6659  /* if the problem should be decomposed (only if all variables are continuous) */
6660  linconsactive = TRUE;
6661  if ( conshdlrdata->nolinconscont )
6662  {
6663  SCIP_Bool onlyCont;
6664  int v;
6665  int nvars;
6666  SCIP_VAR** vars;
6667 
6668  nvars = SCIPgetNVarsLinear(scip, lincons);
6669  vars = SCIPgetVarsLinear(scip, lincons);
6670  onlyCont = TRUE;
6671 
6672  /* check whether call variables are non-integer */
6673  for (v = 0; v < nvars; ++v)
6674  {
6675  SCIP_VARTYPE vartype;
6676 
6677  vartype = SCIPvarGetType(vars[v]);
6678  if ( vartype != SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_IMPLINT )
6679  {
6680  onlyCont = FALSE;
6681  break;
6682  }
6683  }
6684 
6685  if ( onlyCont )
6686  linconsactive = FALSE;
6687  }
6688 
6689  /* mark linear constraint not to be upgraded - otherwise we loose control over it */
6690  SCIPconsAddUpgradeLocks(lincons, 1);
6691  assert(SCIPconsGetNUpgradeLocks(lincons) > 0);
6692 
6693  /* check whether we should generate a bilinear constraint instead of an indicator constraint */
6694  if ( conshdlrdata->generatebilinear )
6695  {
6696  SCIP_Real val;
6697 
6698  /* create a quadratic constraint with a single bilinear term - note that cons is used */
6699  val = 1.0;
6700  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL, 1, &binvar, &slackvar, &val, 0.0, 0.0,
6701  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6702  }
6703  else
6704  {
6705  /* create constraint data */
6706  consdata = NULL;
6707  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrbound, conshdlrdata->eventhdlrrestart,
6708  binvar, slackvar, lincons, linconsactive) );
6709  assert( consdata != NULL );
6710 
6711  /* create constraint */
6712  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
6713  local, modifiable, dynamic, removable, stickingatnode) );
6714  }
6715 
6716  return SCIP_OKAY;
6717 }
6718 
6719 /** creates and captures an indicator constraint with given linear constraint and slack variable
6720  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
6721  * method SCIPcreateConsIndicator(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
6722  *
6723  * @note @a binvar is checked to be binary only later. This enables a change of the type in
6724  * procedures reading an instance.
6725  *
6726  * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
6727  * the role of a slack variable!
6728  *
6729  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
6730  *
6731  * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
6732  *
6733  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
6734  */
6736  SCIP* scip, /**< SCIP data structure */
6737  SCIP_CONS** cons, /**< pointer to hold the created constraint */
6738  const char* name, /**< name of constraint */
6739  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
6740  SCIP_CONS* lincons, /**< linear constraint */
6741  SCIP_VAR* slackvar /**< slack variable */
6742  )
6743 {
6744  assert(scip != NULL);
6745 
6746  SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
6747  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6748 
6749  return SCIP_OKAY;
6750 }
6751 
6752 
6753 /** adds variable to the inequality of the indicator constraint */
6755  SCIP* scip, /**< SCIP data structure */
6756  SCIP_CONS* cons, /**< indicator constraint */
6757  SCIP_VAR* var, /**< variable to add to the inequality */
6758  SCIP_Real val /**< value of variable */
6759  )
6760 {
6761  SCIP_CONSDATA* consdata;
6762 
6763  assert( cons != NULL );
6764  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
6765 
6766  consdata = SCIPconsGetData(cons);
6767  assert( consdata != NULL );
6768 
6769  SCIP_CALL( SCIPaddCoefLinear(scip, consdata->lincons, var, val) );
6770 
6771  /* possibly adapt variable type */
6772  if ( SCIPvarGetType(consdata->slackvar) != SCIP_VARTYPE_CONTINUOUS && (! SCIPvarIsIntegral(var) || ! SCIPisIntegral(scip, val) ) )
6773  {
6774  SCIP_Bool infeasible;
6775 
6776  SCIP_CALL( SCIPchgVarType(scip, consdata->slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
6777  assert(!infeasible);
6778  }
6779 
6780  return SCIP_OKAY;
6781 }
6782 
6783 
6784 /** gets the linear constraint corresponding to the indicator constraint (may be NULL) */
6786  SCIP_CONS* cons /**< indicator constraint */
6787  )
6788 {
6789  SCIP_CONSDATA* consdata;
6790 
6791  assert( cons != NULL );
6792  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
6793 
6794  consdata = SCIPconsGetData(cons);
6795  assert( consdata != NULL );
6796 
6797  return consdata->lincons;
6798 }
6799 
6800 
6801 /** sets the linear constraint corresponding to the indicator constraint (may be NULL) */
6803  SCIP* scip, /**< SCIP data structure */
6804  SCIP_CONS* cons, /**< indicator constraint */
6805  SCIP_CONS* lincons /**< linear constraint */
6806  )
6807 {
6808  SCIP_CONSHDLR* conshdlr;
6809  SCIP_CONSHDLRDATA* conshdlrdata;
6810  SCIP_CONSDATA* consdata;
6811 
6812  if ( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
6813  {
6814  SCIPerrorMessage("Cannot set linear constraint in SCIP stage <%d>\n", SCIPgetStage(scip) );
6815  return SCIP_INVALIDCALL;
6816  }
6817 
6818  assert( cons != NULL );
6819  conshdlr = SCIPconsGetHdlr(cons);
6820 
6821  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6822  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6823  assert( conshdlrdata != NULL );
6824 
6825  consdata = SCIPconsGetData(cons);
6826  assert( consdata != NULL );
6827 
6828  /* free old linear constraint */
6829  assert( consdata->lincons != NULL );
6830  SCIP_CALL( SCIPdelCons(scip, consdata->lincons) );
6831  SCIP_CALL( SCIPreleaseCons(scip, &(consdata->lincons) ) );
6832 
6833  assert( lincons != NULL );
6834  consdata->lincons = lincons;
6835  consdata->linconsactive = TRUE;
6836  SCIP_CALL( SCIPcaptureCons(scip, lincons) );
6837 
6838  /* if the problem should be decomposed if only non-integer variables are present */
6839  if ( conshdlrdata->nolinconscont )
6840  {
6841  SCIP_Bool onlyCont;
6842  int v;
6843  int nvars;
6844  SCIP_VAR** vars;
6845 
6846  onlyCont = TRUE;
6847  nvars = SCIPgetNVarsLinear(scip, lincons);
6848  vars = SCIPgetVarsLinear(scip, lincons);
6849  assert( vars != NULL );
6850 
6851  /* check whether call variables are non-integer */
6852  for (v = 0; v < nvars; ++v)
6853  {
6854  SCIP_VARTYPE vartype;
6855 
6856  vartype = SCIPvarGetType(vars[v]);
6857  if ( vartype != SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_IMPLINT )
6858  {
6859  onlyCont = FALSE;
6860  break;
6861  }
6862  }
6863 
6864  if ( onlyCont )
6865  consdata->linconsactive = FALSE;
6866  }
6867 
6868  return SCIP_OKAY;
6869 }
6870 
6871 
6872 /** gets binary variable corresponding to indicator constraint */
6874  SCIP_CONS* cons /**< indicator constraint */
6875  )
6876 {
6877  SCIP_CONSDATA* consdata;
6878 
6879  assert( cons != NULL );
6880  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
6881 
6882  consdata = SCIPconsGetData(cons);
6883  assert( consdata != NULL );
6884 
6885  return consdata->binvar;
6886 }
6887 
6888 
6889 /** sets binary indicator variable for indicator constraint */
6891  SCIP* scip, /**< SCIP data structure */
6892  SCIP_CONS* cons, /**< indicator constraint */
6893  SCIP_VAR* binvar /**< binary variable to add to the inequality */
6894  )
6895 {
6896  SCIP_CONSDATA* consdata;
6897 
6898  assert( cons != NULL );
6899  assert( binvar != NULL );
6900  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
6901 
6902  consdata = SCIPconsGetData(cons);
6903  assert( consdata != NULL );
6904 
6905  /* check type */
6906  if ( SCIPvarGetType(binvar) != SCIP_VARTYPE_BINARY )
6907  {
6908  SCIPerrorMessage("Indicator variable <%s> is not binary %d.\n", SCIPvarGetName(binvar), SCIPvarGetType(binvar));
6909  return SCIP_ERROR;
6910  }
6911 
6912  /* check previous binary variable */
6913  if ( consdata->binvar != NULL )
6914  {
6915  /* to allow replacement of binary variables, we would need to drop events etc. */
6916  SCIPerrorMessage("Cannot replace binary variable <%s> for indicator constraint <%s>.\n", SCIPvarGetName(binvar), SCIPconsGetName(cons));
6917  return SCIP_INVALIDCALL;
6918  }
6919 
6920  /* if we are transformed, obtain transformed variables and catch events */
6921  if ( SCIPconsIsTransformed(cons) )
6922  {
6923  SCIP_VAR* var;
6924  SCIP_CONSHDLR* conshdlr;
6925  SCIP_CONSHDLRDATA* conshdlrdata;
6926 
6927  /* make sure we have a transformed binary variable */
6928  SCIP_CALL( SCIPgetTransformedVar(scip, binvar, &var) );
6929  assert( var != NULL );
6930  consdata->binvar = var;
6931 
6932  conshdlr = SCIPconsGetHdlr(cons);
6933  assert( conshdlr != NULL );
6934  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6935  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6936  assert( conshdlrdata != NULL );
6937  assert( conshdlrdata->eventhdlrbound != NULL );
6938  assert( conshdlrdata->eventhdlrrestart != NULL );
6939 
6940  /* catch local bound change events on binary variable */
6941  if ( consdata->linconsactive )
6942  {
6943  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, NULL) );
6944  }
6945 
6946  /* catch global bound change events on binary variable */
6947  if ( conshdlrdata->forcerestart )
6948  {
6949  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
6950  }
6951 
6952  /* if binary variable is fixed to be nonzero */
6953  if ( SCIPvarGetLbLocal(var) > 0.5 )
6954  ++(consdata->nfixednonzero);
6955  }
6956  else
6957  consdata->binvar = binvar;
6958 
6959  return SCIP_OKAY;
6960 }
6961 
6962 
6963 /** gets slack variable corresponding to indicator constraint */
6965  SCIP_CONS* cons /**< indicator constraint */
6966  )
6967 {
6968  SCIP_CONSDATA* consdata;
6969 
6970  assert( cons != NULL );
6971  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
6972 
6973  consdata = SCIPconsGetData(cons);
6974  assert( consdata != NULL );
6975 
6976  return consdata->slackvar;
6977 }
6978 
6979 
6980 /** checks whether indicator constraint is violated w.r.t. sol */
6982  SCIP* scip, /**< SCIP data structure */
6983  SCIP_CONS* cons, /**< indicator constraint */
6984  SCIP_SOL* sol /**< solution, or NULL to use current node's solution */
6985  )
6986 {
6987  SCIP_CONSDATA* consdata;
6988 
6989  assert( cons != NULL );
6990 
6991  /* deleted constraints should always be satisfied */
6992  if ( SCIPconsIsDeleted(cons) )
6993  return FALSE;
6994 
6995  consdata = SCIPconsGetData(cons);
6996  assert( consdata != NULL );
6997 
6998  if ( consdata->linconsactive )
6999  {
7000  assert( consdata->slackvar != NULL );
7001  assert( consdata->binvar != NULL );
7002  return(
7003  SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) &&
7004  SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
7005  }
7006 
7007  /* @todo: check how this can be decided for linconsactive == FALSE */
7008  return TRUE;
7009 }
7010 
7011 
7012 /** Based on values of other variables, computes slack and binary variable to turn constraint feasible
7013  *
7014  * It will also clean up the solution, i.e., shift slack variable, as follows:
7015  *
7016  * If the inequality is \f$a^T x + \gamma\, s \leq \beta\f$, the value of the slack variable
7017  * \f$s\f$ to achieve equality is
7018  * \f[
7019  * s^* = \frac{\beta - a^T x^*}{\gamma},
7020  * \f]
7021  * where \f$x^*\f$ is the given solution. In case of \f$a^T x + \gamma\, s \geq \alpha\f$, we
7022  * arrive at
7023  * \f[
7024  * s^* = \frac{\alpha - a^T x^*}{\gamma}.
7025  * \f]
7026  * The typical values of \f$\gamma\f$ in the first case is -1 and +1 in the second case.
7027  *
7028  * Now, let \f$\sigma\f$ be the sign of \f$\gamma\f$ in the first case and \f$-\gamma\f$ in the
7029  * second case. Thus, if \f$\sigma > 0\f$ and \f$s^* < 0\f$, the inequality cannot be satisfied by
7030  * a nonnegative value for the slack variable; in this case, we have to leave the values as they
7031  * are. If \f$\sigma < 0\f$ and \f$s^* > 0\f$, the solution violates the indicator constraint (we
7032  * can set the slack variable to value \f$s^*\f$). If \f$\sigma < 0\f$ and \f$s^* \leq 0\f$ or
7033  * \f$\sigma > 0\f$ and \f$s^* \geq 0\f$, the constraint is satisfied, and we can set the slack
7034  * variable to 0.
7035  */
7037  SCIP* scip, /**< SCIP data structure */
7038  SCIP_CONS* cons, /**< indicator constraint */
7039  SCIP_SOL* sol, /**< solution */
7040  SCIP_Bool* changed /**< pointer to store whether the solution has been changed */
7041  )
7042 {
7043  SCIP_CONSDATA* consdata;
7044  SCIP_CONS* lincons;
7045  SCIP_VAR** linvars;
7046  SCIP_Real* linvals;
7047  SCIP_VAR* slackvar;
7048  SCIP_VAR* binvar;
7049  SCIP_Real slackcoef;
7050  SCIP_Real sum;
7051  SCIP_Real val;
7052  int nlinvars;
7053  int sigma;
7054  int v;
7055 
7056  assert( cons != NULL );
7057  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
7058  assert( sol != NULL );
7059  assert( changed != NULL );
7060 
7061  *changed = FALSE;
7062 
7063  /* avoid deleted indicator constraints, e.g., due to preprocessing */
7064  if ( ! SCIPconsIsActive(cons) && SCIPgetStage(scip) >= SCIP_STAGE_INITPRESOLVE )
7065  return SCIP_OKAY;
7066 
7067  assert( cons != NULL );
7068  consdata = SCIPconsGetData(cons);
7069  assert( consdata != NULL );
7070 
7071  /* if the linear constraint is not present, we cannot do anything */
7072  if ( ! consdata->linconsactive )
7073  return SCIP_OKAY;
7074 
7075  lincons = consdata->lincons;
7076  assert( lincons != NULL );
7077 
7078  /* avoid non-active linear constraints, e.g., due to preprocessing */
7079  if ( SCIPconsIsActive(lincons) || SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE )
7080  {
7081  slackvar = consdata->slackvar;
7082  binvar = consdata->binvar;
7083  assert( slackvar != NULL );
7084  assert( binvar != NULL );
7085 
7086  nlinvars = SCIPgetNVarsLinear(scip, lincons);
7087  linvars = SCIPgetVarsLinear(scip, lincons);
7088  linvals = SCIPgetValsLinear(scip, lincons);
7089 
7090  /* compute value of regular variables */
7091  sum = 0.0;
7092  slackcoef = 0.0;
7093  for (v = 0; v < nlinvars; ++v)
7094  {
7095  SCIP_VAR* var;
7096  var = linvars[v];
7097  if ( var != slackvar )
7098  sum += linvals[v] * SCIPgetSolVal(scip, sol, var);
7099  else
7100  slackcoef = linvals[v];
7101  }
7102 
7103  /* do nothing if slack variable does not appear */
7104  if ( SCIPisFeasZero(scip, slackcoef) )
7105  return SCIP_OKAY;
7106 
7107  assert( ! SCIPisZero(scip, slackcoef) );
7108  assert( slackcoef != 0.0 ); /* to satisfy lint */
7109  assert( SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, lincons)) || SCIPisInfinity(scip, SCIPgetRhsLinear(scip, lincons)) );
7110  assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(slackvar), 0.0) );
7111 
7112  val = SCIPgetRhsLinear(scip, lincons);
7113  sigma = 1;
7114  if ( SCIPisInfinity(scip, val) )
7115  {
7116  val = SCIPgetLhsLinear(scip, lincons);
7117  assert( ! SCIPisInfinity(scip, REALABS(val)) );
7118  sigma = -1;
7119  }
7120  /* compute value of slack that would achieve equality */
7121  val = (val - sum)/slackcoef;
7122 
7123  /* compute direction into which slack variable would be infeasible */
7124  if ( slackcoef < 0 )
7125  sigma *= -1;
7126 
7127  /* filter out cases in which no sensible change is possible */
7128  if ( sigma > 0 && SCIPisFeasNegative(scip, val) )
7129  return SCIP_OKAY;
7130 
7131  /* check if linear constraint w/o slack variable is violated */
7132  if ( sigma < 0 && SCIPisFeasPositive(scip, val) )
7133  {
7134  /* the original constraint is violated */
7135  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, slackvar), val) )
7136  {
7137  SCIP_CALL( SCIPsetSolVal(scip, sol, slackvar, val) );
7138  *changed = TRUE;
7139  }
7140  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 0.0) )
7141  {
7142  SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 0.0) );
7143  *changed = TRUE;
7144  }
7145  }
7146  else
7147  {
7148  assert( SCIPisFeasGE(scip, val * ((SCIP_Real) sigma), 0.0) );
7149 
7150  /* the original constraint is satisfied - we can set the slack variable to 0 (slackvar
7151  * should only occur in this indicator constraint) */
7152  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, slackvar), 0.0) && SCIPisFeasPositive(scip, SCIPvarGetLbLocal(slackvar)) )
7153  {
7154  SCIP_CALL( SCIPsetSolVal(scip, sol, slackvar, 0.0) );
7155  *changed = TRUE;
7156  }
7157 
7158  /* check whether binary variable is fixed or its negated variable is fixed */
7159  if ( SCIPvarGetStatus(binvar) != SCIP_VARSTATUS_FIXED &&
7161  {
7162  SCIP_Real obj;
7163  obj = varGetObjDelta(binvar);
7164 
7165  /* check objective for possibly setting binary variable */
7166  if ( obj <= 0 )
7167  {
7168  /* setting variable to 1 does not increase objective - check whether we can set it to 1 */
7169  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 1.0) )
7170  {
7171  /* check whether variable only occurs in the current constraint */
7172  if ( SCIPvarGetNLocksUp(binvar) <= 1 )
7173  {
7174  SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 1.0) );
7175  *changed = TRUE;
7176  /* make sure that the other case does not occur if obj = 0: prefer variables set to 1 */
7177  obj = -1.0;
7178  }
7179  }
7180  else
7181  {
7182  /* make sure that the other case does not occur if obj = 0: prefer variables set to 1 */
7183  obj = -1.0;
7184  }
7185  }
7186  if ( obj >= 0 )
7187  {
7188  /* setting variable to 0 does not inrease objective -> check whether variable only occurs in the current constraint
7189  * note: binary variables are only locked up */
7190  if ( SCIPvarGetNLocksDown(binvar) <= 0 && ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 0.0) )
7191  {
7192  SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 0.0) );
7193  *changed = TRUE;
7194  }
7195  }
7196  }
7197  }
7198  }
7199 
7200  return SCIP_OKAY;
7201 }
7202 
7203 
7204 /** Based on values of other variables, computes slack and binary variable to turn all constraints feasible */
7206  SCIP* scip, /**< SCIP data structure */
7207  SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
7208  SCIP_SOL* sol, /**< solution */
7209  SCIP_Bool* changed /**< pointer to store whether the solution has been changed */
7210  )
7211 {
7212  SCIP_CONS** conss;
7213  int nconss;
7214  int c;
7215 
7216  assert( conshdlr != NULL );
7217  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7218  assert( sol != NULL );
7219  assert( changed != NULL );
7220 
7221  *changed = FALSE;
7222 
7223  /* only run after or in presolving */
7224  if ( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE )
7225  return SCIP_OKAY;
7226 
7227  conss = SCIPconshdlrGetConss(conshdlr);
7228  nconss = SCIPconshdlrGetNConss(conshdlr);
7229 
7230  for (c = 0; c < nconss; ++c)
7231  {
7232  SCIP_CONSDATA* consdata;
7233  SCIP_Bool chg = FALSE;
7234  assert( conss[c] != NULL );
7235 
7236  consdata = SCIPconsGetData(conss[c]);
7237  assert( consdata != NULL );
7238 
7239  /* if the linear constraint is not present, we stop */
7240  if ( ! consdata->linconsactive )
7241  break;
7242 
7243  SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], sol, &chg) );
7244  *changed = *changed || chg;
7245  }
7246 
7247  return SCIP_OKAY;
7248 }
7249 
7250 
7251 /** adds additional linear constraint that is not connected with an indicator constraint, but can be used for separation */
7253  SCIP* scip, /**< SCIP data structure */
7254  SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
7255  SCIP_CONS* lincons /**< linear constraint */
7256  )
7257 {
7258  assert( scip != NULL );
7259  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7260  assert( lincons != NULL );
7261 
7262  /* do not add locally valid constraints (this would require much more bookkeeping) */
7263  if ( ! SCIPconsIsLocal(lincons) )
7264  {
7265  SCIP_CONSHDLRDATA* conshdlrdata;
7266 
7267  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7268  assert( conshdlrdata != NULL );
7269 
7270  SCIP_CALL( consdataEnsureAddLinConsSize(scip, conshdlr, conshdlrdata->naddlincons+1) );
7271  assert( conshdlrdata->naddlincons+1 <= conshdlrdata->maxaddlincons );
7272 
7273  conshdlrdata->addlincons[conshdlrdata->naddlincons++] = lincons;
7274  }
7275 
7276  return SCIP_OKAY;
7277 }
7278 
7279 
7280 /** adds additional row that is not connected by an indicator constraint, but can be used for separation
7281  *
7282  * @note The row is directly added to the alternative polyhedron and is not stored.
7283  */
7285  SCIP* scip, /**< SCIP data structure */
7286  SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
7287  SCIP_ROW* row /**< row to add */
7288  )
7289 {
7290  assert( scip != NULL );
7291  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7292  assert( row != NULL );
7293 
7294  /* skip local cuts (local cuts would require to dynamically add and remove columns from the alternative polyhedron */
7295  if ( ! SCIProwIsLocal(row) )
7296  {
7297  int colindex;
7298  SCIP_CONSHDLRDATA* conshdlrdata;
7299 
7300  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7301  assert( conshdlrdata != NULL );
7302 
7303  /* do not add rows if we do not separate */
7304  if ( ! conshdlrdata->sepaalternativelp )
7305  return SCIP_OKAY;
7306 
7307  SCIPdebugMessage("Adding row <%s> to alternative LP.\n", SCIProwGetName(row));
7308 
7309  /* add row directly to alternative polyhedron */
7310  SCIP_CALL( addAltLPRow(scip, conshdlr, row, 0.0, &colindex) );
7311  }
7312 
7313  return SCIP_OKAY;
7314 }
7315