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