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