Scippy

SCIP

Solving Constraint Integer Programs

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