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