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