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