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