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