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  ++(*nGen);
3962  }
3963 
3964  /* Note that because of possible multi-aggregation we cannot simply remove the indicator
3965  * constraint if the linear constraint is not active or disabled - see the note in @ref
3966  * PREPROC and consPresolIndicator(). Moreover, it would drastically increase memory
3967  * consumption, because the linear constraints have to be stored in each node. */
3968  }
3969 
3970  return SCIP_OKAY;
3971 }
3972 
3973 
3974 /** enforcement method that produces cuts if possible
3975  *
3976  * This is a variant of the enforcement method that generates cuts/constraints via the alternative
3977  * LP, if possible.
3978  */
3979 static
3981  SCIP* scip, /**< SCIP pointer */
3982  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3983  int nconss, /**< number of constraints */
3984  SCIP_CONS** conss, /**< indicator constraints */
3985  SCIP_SOL* sol, /**< solution to be enforced */
3986  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
3987  SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
3988  SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
3989  int* nGen /**< number of cuts generated */
3990  )
3991 {
3992  SCIP_CONSHDLRDATA* conshdlrdata;
3993  SCIP_LPI* lp;
3994  SCIP_Bool* S;
3995  SCIP_Real value = 0.0;
3996  SCIP_Bool error;
3997  int size = 0;
3998  int nCuts;
3999  int j;
4000 
4001  assert( scip != NULL );
4002  assert( conshdlr != NULL );
4003  assert( conss != NULL );
4004  assert( cutoff != NULL );
4005  assert( nGen != NULL );
4006 
4007  SCIPdebugMsg(scip, "Enforcing via cuts ...\n");
4008  *cutoff = FALSE;
4009  *nGen = 0;
4010 
4011  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4012  assert( conshdlrdata != NULL );
4013  lp = conshdlrdata->altlp;
4014  assert( lp != NULL );
4015 
4016 #ifndef NDEBUG
4017  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4018 #endif
4019 
4020  /* change coefficients of bounds in alternative LP */
4021  if ( conshdlrdata->updatebounds )
4022  SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
4023 
4024  /* possibly update upper bound */
4025  SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4026 
4027  /* scale first row if necessary */
4028  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
4029 
4030  /* set objective function to current solution */
4031  SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
4032 
4033  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
4034 
4035  /* set up variables fixed to 1 */
4036  for (j = 0; j < nconss; ++j)
4037  {
4038  SCIP_CONSDATA* consdata;
4039 
4040  assert( conss[j] != NULL );
4041  consdata = SCIPconsGetData(conss[j]);
4042  assert( consdata != NULL );
4043 
4044  assert( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
4045  if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
4046  {
4047  ++size;
4048  value += varGetObjDelta(consdata->binvar);
4049  S[j] = TRUE;
4050  }
4051  else
4052  S[j] = FALSE;
4053  }
4054 
4055  /* fix the variables in S */
4056  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
4057 
4058  /* extend set S to a cover and generate cuts */
4059  error = FALSE;
4060  SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, genlogicor, nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
4061  *nGen = nCuts;
4062 
4063  /* return with an error if no cuts have been produced and and error occurred in extendToCover() */
4064  if ( nCuts == 0 && error )
4065  return SCIP_LPERROR;
4066 
4067  SCIPdebugMsg(scip, "Generated %d IIS-cuts.\n", nCuts);
4068 
4069  /* reset bounds */
4070  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
4071 
4072 #ifndef NDEBUG
4073  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4074 #endif
4075 
4076  SCIPfreeBufferArray(scip, &S);
4077 
4078  return SCIP_OKAY;
4079 }
4080 
4081 
4082 /** enforcement method
4083  *
4084  * We check whether the current solution is feasible, i.e., if binvar = 1
4085  * implies that slackvar = 0. If not, we branch as follows:
4086  *
4087  * In one branch we fix binvar = 1 and slackvar = 0. In the other branch
4088  * we fix binvar = 0 and leave slackvar unchanged.
4089  */
4090 static
4092  SCIP* scip, /**< SCIP pointer */
4093  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4094  int nconss, /**< number of constraints */
4095  SCIP_CONS** conss, /**< indicator constraints */
4096  SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
4097  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4098  SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
4099  SCIP_RESULT* result /**< result */
4100  )
4101 {
4102  SCIP_CONSDATA* consdata;
4103  SCIP_CONSHDLRDATA* conshdlrdata;
4104  SCIP_NODE* node1;
4105  SCIP_NODE* node2;
4106  SCIP_VAR* slackvar;
4107  SCIP_VAR* binvar;
4109  SCIP_Real maxSlack = -1.0;
4110  SCIP_Bool someLinconsNotActive = FALSE;
4111  int c;
4112 
4113  assert( scip != NULL );
4114  assert( conshdlr != NULL );
4115  assert( conss != NULL );
4116  assert( result != NULL );
4117 
4118  *result = SCIP_FEASIBLE;
4119 
4120  SCIPdebugMsg(scip, "Enforcing indicator constraints for <%s> ...\n", SCIPconshdlrGetName(conshdlr) );
4121 
4122  /* get constraint handler data */
4123  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4124  assert( conshdlrdata != NULL );
4125 
4126 #ifdef SCIP_OUTPUT
4127  SCIP_CALL( SCIPwriteTransProblem(scip, "ind.cip", "cip", FALSE) );
4128 #endif
4129 
4130  /* check each constraint */
4131  for (c = 0; c < nconss; ++c)
4132  {
4133  SCIP_Bool cutoff;
4134  SCIP_Real valSlack;
4135  int cnt;
4136 
4137  assert( conss[c] != NULL );
4138  consdata = SCIPconsGetData(conss[c]);
4139  assert( consdata != NULL );
4140  assert( consdata->lincons != NULL );
4141 
4142  /* if the linear constraint has not been generated, we do nothing */
4143  if ( ! consdata->linconsactive )
4144  {
4145  someLinconsNotActive = TRUE;
4146  continue;
4147  }
4148 
4149  /* first perform propagation (it might happen that standard propagation is turned off) */
4150  SCIP_CALL( propIndicator(scip, conss[c], consdata,
4151  conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip), conshdlrdata->addopposite,
4152  &cutoff, &cnt) );
4153  if ( cutoff )
4154  {
4155  SCIPdebugMsg(scip, "Propagation in enforcing <%s> detected cutoff.\n", SCIPconsGetName(conss[c]));
4156  *result = SCIP_CUTOFF;
4157  return SCIP_OKAY;
4158  }
4159  if ( cnt > 0 )
4160  {
4161  SCIPdebugMsg(scip, "Propagation in enforcing <%s> reduced domains: %d.\n", SCIPconsGetName(conss[c]), cnt);
4162  *result = SCIP_REDUCEDDOM;
4163  return SCIP_OKAY;
4164  }
4165 
4166  /* check whether constraint is infeasible */
4167  binvar = consdata->binvar;
4168  valSlack = SCIPgetSolVal(scip, sol, consdata->slackvar);
4169  assert( ! SCIPisFeasNegative(scip, valSlack) );
4170  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, binvar)) && ! SCIPisFeasZero(scip, valSlack) )
4171  {
4172  /* binary variable is not fixed - otherwise we would not be infeasible */
4173  assert( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 );
4174 
4175  if ( valSlack > maxSlack )
4176  {
4177  maxSlack = valSlack;
4178  branchCons = conss[c];
4179 #ifdef SCIP_OUTPUT
4180  SCIPinfoMessage(scip, NULL, "Violated indicator constraint:\n");
4181  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
4182  SCIPinfoMessage(scip, NULL, ";\n");
4183  SCIPinfoMessage(scip, NULL, "Corresponding linear constraint:\n");
4184  SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
4185  SCIPinfoMessage(scip, NULL, ";\n");
4186 #endif
4187  }
4188  }
4189  }
4190 
4191  /* if some constraint has a linear constraint that is not active, we need to check feasibility via the alternative polyhedron */
4192  if ( (someLinconsNotActive || conshdlrdata->enforcecuts) && conshdlrdata->sepaalternativelp )
4193  {
4194  SCIP_Bool cutoff;
4195  int ngen;
4196 
4197  SCIP_CALL( enforceCuts(scip, conshdlr, nconss, conss, sol, enfosepatype, genlogicor, &cutoff, &ngen) );
4198  if ( cutoff )
4199  {
4200  conshdlrdata->niiscutsgen += ngen;
4201  *result = SCIP_CUTOFF;
4202  return SCIP_OKAY;
4203  }
4204 
4205  if ( ngen > 0 )
4206  {
4207  conshdlrdata->niiscutsgen += ngen;
4208  if ( genlogicor )
4209  {
4210  SCIPdebugMsg(scip, "Generated %d constraints.\n", ngen);
4211  *result = SCIP_CONSADDED;
4212  }
4213  else
4214  {
4215  SCIPdebugMsg(scip, "Generated %d cuts.\n", ngen);
4216  *result = SCIP_SEPARATED;
4217  }
4218  return SCIP_OKAY;
4219  }
4220  SCIPdebugMsg(scip, "Enforcing produced no cuts.\n");
4221 
4222  assert( ! someLinconsNotActive || branchCons == NULL );
4223  }
4224 
4225  /* if all constraints are feasible */
4226  if ( branchCons == NULL )
4227  {
4228  SCIPdebugMsg(scip, "All indicator constraints are feasible.\n");
4229  return SCIP_OKAY;
4230  }
4231 
4232  /* skip branching if required */
4233  if ( ! conshdlrdata->branchindicators )
4234  {
4235  *result = SCIP_INFEASIBLE;
4236  return SCIP_OKAY;
4237  }
4238 
4239  /* otherwise create branches */
4240  SCIPdebugMsg(scip, "Branching on constraint <%s> (slack value: %f).\n", SCIPconsGetName(branchCons), maxSlack);
4241  consdata = SCIPconsGetData(branchCons);
4242  assert( consdata != NULL );
4243  binvar = consdata->binvar;
4244  slackvar = consdata->slackvar;
4245 
4246  /* node1: binvar = 1, slackvar = 0 */
4247  SCIP_CALL( SCIPcreateChild(scip, &node1, 0.0, SCIPcalcChildEstimate(scip, binvar, 1.0) ) );
4248 
4249  if ( SCIPvarGetLbLocal(binvar) < 0.5 )
4250  {
4251  SCIP_CALL( SCIPchgVarLbNode(scip, node1, binvar, 1.0) );
4252  }
4253 
4254  /* if slack-variable is multi-aggregated */
4255  assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
4256  if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(slackvar)) )
4257  {
4258  SCIP_CALL( SCIPchgVarUbNode(scip, node1, slackvar, 0.0) );
4259  }
4260 
4261  /* node2: binvar = 0, no restriction on slackvar */
4262  SCIP_CALL( SCIPcreateChild(scip, &node2, 0.0, SCIPcalcChildEstimate(scip, binvar, 0.0) ) );
4263 
4264  if ( SCIPvarGetUbLocal(binvar) > 0.5 )
4265  {
4266  SCIP_CALL( SCIPchgVarUbNode(scip, node2, binvar, 0.0) );
4267  }
4268 
4269  SCIP_CALL( SCIPresetConsAge(scip, branchCons) );
4270  *result = SCIP_BRANCHED;
4271 
4272  return SCIP_OKAY;
4273 }
4274 
4275 
4276 /** separate IIS-cuts via rounding
4277  *
4278  * @todo Check whether the cover produced at the end is a feasible solution.
4279  */
4280 static
4282  SCIP* scip, /**< SCIP pointer */
4283  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4284  SCIP_SOL* sol, /**< solution to be separated */
4285  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4286  int nconss, /**< number of constraints */
4287  SCIP_CONS** conss, /**< indicator constraints */
4288  int maxsepacuts, /**< maximal number of cuts to be generated */
4289  SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
4290  int* nGen /**< number of domain changes */
4291  )
4292 { /*lint --e{850}*/
4293  SCIP_CONSHDLRDATA* conshdlrdata;
4294  SCIP_LPI* lp;
4295  int rounds;
4296  SCIP_Real threshold;
4297  SCIP_Bool* S;
4298  SCIP_Bool error;
4299  int oldsize = -1;
4300  SCIPdebug( int nGenOld = *nGen; )
4301 
4302  assert( scip != NULL );
4303  assert( conshdlr != NULL );
4304  assert( conss != NULL );
4305  assert( cutoff != NULL );
4306  assert( nGen != NULL );
4307 
4308  if ( *nGen >= maxsepacuts )
4309  return SCIP_OKAY;
4310 
4311  *cutoff = FALSE;
4312  rounds = 0;
4313 
4314  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4315  assert( conshdlrdata != NULL );
4316  lp = conshdlrdata->altlp;
4317  assert( lp != NULL );
4318 
4319  SCIPdebugMsg(scip, "Separating IIS-cuts by rounding ...\n");
4320 
4321 #ifndef NDEBUG
4322  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4323 #endif
4324 
4325  /* change coefficients of bounds in alternative LP */
4326  if ( conshdlrdata->updatebounds )
4327  {
4328  /* update to local bounds */
4329  SCIP_CALL( updateFirstRow(scip, conshdlrdata) );
4330  }
4331 
4332  /* possibly update upper bound */
4333  SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4334 
4335  /* scale first row if necessary */
4336  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
4337 
4338  /* set objective function to current solution */
4339  SCIP_CALL( setAltLPObj(scip, lp, sol, nconss, conss) );
4340 
4341  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
4342 
4343  /* loop through the possible thresholds */
4344  for (threshold = conshdlrdata->roundingmaxthres;
4345  rounds < conshdlrdata->maxroundingrounds && threshold >= conshdlrdata->roundingminthres && *nGen < maxsepacuts && ! (*cutoff);
4346  threshold -= conshdlrdata->roundingoffset )
4347  {
4348  SCIP_Real value = 0.0;
4349  int size = 0;
4350  int nCuts = 0;
4351  int j;
4352 #ifdef SCIP_DEBUG
4353  int nvarsone = 0;
4354  int nvarszero = 0;
4355  int nvarsfrac = 0;
4356 #endif
4357 
4358  SCIPdebugMsg(scip, "Threshold: %g.\n", threshold);
4359 
4360  /* choose variables that have a value < current threshold value */
4361  for (j = 0; j < nconss; ++j)
4362  {
4363  SCIP_CONSDATA* consdata;
4364  SCIP_Real binvarval;
4365  SCIP_VAR* binvarneg;
4366 
4367  assert( conss[j] != NULL );
4368  consdata = SCIPconsGetData(conss[j]);
4369  assert( consdata != NULL );
4370 
4371  binvarval = SCIPgetVarSol(scip, consdata->binvar);
4372 
4373 #ifdef SCIP_DEBUG
4374  if ( SCIPisFeasEQ(scip, binvarval, 1.0) )
4375  ++nvarsone;
4376  else if ( SCIPisFeasZero(scip, binvarval) )
4377  ++nvarszero;
4378  else
4379  ++nvarsfrac;
4380 #endif
4381 
4382  /* check whether complementary (negated) variable is present as well */
4383  binvarneg = SCIPvarGetNegatedVar(consdata->binvar);
4384  assert( binvarneg != NULL );
4385 
4386  /* negated variable is present as well */
4387  assert( conshdlrdata->binvarhash != NULL );
4388  if ( SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarneg) )
4389  {
4390  SCIP_Real binvarnegval = SCIPgetVarSol(scip, binvarneg);
4391 
4392  /* take larger one */
4393  if ( binvarval > binvarnegval )
4394  S[j] = TRUE;
4395  else
4396  S[j] = FALSE;
4397  continue;
4398  }
4399 
4400  /* check for threshold */
4401  if ( SCIPisFeasLT(scip, SCIPgetVarSol(scip, consdata->binvar), threshold) )
4402  {
4403  S[j] = TRUE;
4404  value += varGetObjDelta(consdata->binvar);
4405  ++size;
4406  }
4407  else
4408  S[j] = FALSE;
4409  }
4410 
4411  if ( size == nconss )
4412  {
4413  SCIPdebugMsg(scip, "All variables in the set. Continue ...\n");
4414  continue;
4415  }
4416 
4417  /* skip computation if size has not changed (computation is likely the same) */
4418  if ( size == oldsize )
4419  {
4420  SCIPdebugMsg(scip, "Skipping computation: size support has not changed.\n");
4421  continue;
4422  }
4423  oldsize = size;
4424 
4425 #ifdef SCIP_DEBUG
4426  SCIPdebugMsg(scip, " Vars with value 1: %d 0: %d and fractional: %d.\n", nvarsone, nvarszero, nvarsfrac);
4427 #endif
4428 
4429  /* fix the variables in S */
4430  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
4431 
4432  /* extend set S to a cover and generate cuts */
4433  SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, conshdlrdata->genlogicor,
4434  nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
4435 
4436  /* we ignore errors in extendToCover */
4437  if ( nCuts > 0 )
4438  {
4439  *nGen += nCuts;
4440  ++rounds;
4441  }
4442  else
4443  {
4444  /* possibly update upper bound */
4445  SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4446  }
4447 
4448  /* reset bounds */
4449  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
4450  }
4451  SCIPdebug( SCIPdebugMsg(scip, "Generated %d IISs.\n", *nGen - nGenOld); )
4452 
4453 #ifndef NDEBUG
4454  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4455 #endif
4456 
4457  SCIPfreeBufferArray(scip, &S);
4458 
4459  return SCIP_OKAY;
4460 }
4461 
4462 
4463 
4464 /** separate cuts based on perspective formulation
4465  *
4466  * Hijazi, Bonami, and Ouorou (2014) introduced the following cuts: We consider an indicator constraint
4467  * \f[
4468  * y = 1 \rightarrow \alpha^T x \leq \beta
4469  * \f]
4470  * and assume finite bounds \f$\ell \leq x \leq u\f$. Then for \f$I \subseteq \{1, \dots, n\}\f$ define
4471  * \f[
4472  * \Sigma(I,x,y) = \sum_{i \notin I} \alpha_i x_i +
4473  * y \Big(\sum_{i \in I, \alpha_i < 0} \alpha_i u_i + \sum_{i \in I, \alpha_i > 0} \alpha_i \ell_i +
4474  * \sum_{i \notin I, \alpha_i < 0} \alpha_i \ell_i + \sum_{i \notin I, \alpha_i > 0} \alpha_i u_i - \beta\Big).
4475  * \f]
4476  * Then the cuts
4477  * \f[
4478  * \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
4479  * \f]
4480  * are valid for the disjunction
4481  * \f[
4482  * \{y = 0,\; \ell \leq x \leq u\} \cup \{y = 1,\; \ell \leq x \leq u,\; \alpha^T x \leq \beta\}.
4483  * \f]
4484  * 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
4485  * \f[
4486  * y^*(\alpha_i\, u_i\, [\alpha_i < 0] + \alpha_i\, \ell_i\, [\alpha_i > 0]) >
4487  * \alpha_i x_i^* + y^* )\alpha_i \ell_i [\alpha_i < 0] + \alpha_i u_i [\alpha_i > 0]),
4488  * \f]
4489  * where \f$[C] = 1\f$ if condition \f$C\f$ is satisfied, otherwise it is 0.
4490  * If the above inequality holds, \f$i\f$ is included in \f$I\f$, otherwise not.
4491  */
4492 static
4494  SCIP* scip, /**< SCIP pointer */
4495  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4496  SCIP_SOL* sol, /**< solution to be separated */
4497  int nconss, /**< number of constraints */
4498  SCIP_CONS** conss, /**< indicator constraints */
4499  int maxsepacuts, /**< maximal number of cuts to be generated */
4500  int* nGen /**< number of generated cuts */
4501  )
4502 { /*lint --e{850}*/
4503  SCIP_CONSHDLRDATA* conshdlrdata;
4504  SCIP_VAR** cutvars;
4505  SCIP_Real* cutvals;
4506  int nvars;
4507  int c;
4508 
4509  assert( scip != NULL );
4510  assert( conshdlr != NULL );
4511  assert( conss != NULL );
4512  assert( nGen != NULL );
4513 
4514  if ( *nGen >= maxsepacuts )
4515  return SCIP_OKAY;
4516 
4517  nvars = SCIPgetNVars(scip);
4518  SCIP_CALL( SCIPallocBufferArray(scip, &cutvars, nvars+1) );
4519  SCIP_CALL( SCIPallocBufferArray(scip, &cutvals, nvars+1) );
4520 
4521  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4522  assert( conshdlrdata != NULL );
4523 
4524  /* loop through constraints */
4525  for (c = 0; c < nconss; ++c)
4526  {
4527  SCIP_CONSDATA* consdata;
4528  SCIP_CONS* lincons;
4529  SCIP_VAR* slackvar;
4530  SCIP_VAR* binvar;
4531  SCIP_Real binval;
4532 
4533  assert( conss[c] != NULL );
4534  consdata = SCIPconsGetData(conss[c]);
4535  assert( consdata != NULL );
4536  slackvar = consdata->slackvar;
4537 
4538  lincons = consdata->lincons;
4539  assert( lincons != NULL );
4540 
4541  binvar = consdata->binvar;
4542  assert( binvar != NULL );
4543  binval = SCIPgetSolVal(scip, sol, binvar);
4544 
4545  if ( SCIPconsIsActive(lincons) )
4546  {
4547  SCIP_VAR** linvars;
4548  SCIP_Real* linvals;
4549  SCIP_Real linrhs;
4550  SCIP_Bool finitebound = TRUE;
4551  SCIP_Real cutrhs = 0.0;
4552  SCIP_Real cutval;
4553  SCIP_Real signfactor = 1.0;
4554  SCIP_Real ypart;
4555  SCIP_Bool islocal = FALSE;
4556  int nlinvars;
4557  int cnt = 0;
4558  int j;
4559 
4560  linvars = SCIPgetVarsLinear(scip, lincons);
4561  linvals = SCIPgetValsLinear(scip, lincons);
4562  nlinvars = SCIPgetNVarsLinear(scip, lincons);
4563 
4564  linrhs = SCIPgetRhsLinear(scip, lincons);
4565  if ( SCIPisInfinity(scip, linrhs) )
4566  {
4567  if ( ! SCIPisInfinity(scip, SCIPgetLhsLinear(scip, lincons)) )
4568  {
4569  linrhs = -SCIPgetLhsLinear(scip, lincons);
4570  signfactor = -1.0;
4571  }
4572  else
4573  continue;
4574  }
4575  ypart = -linrhs;
4576  cutval = binval * ypart;
4577 
4578  for (j = 0; j < nlinvars; ++j)
4579  {
4580  SCIP_Real linval;
4581  SCIP_Real lb;
4582  SCIP_Real ub;
4583  SCIP_Real din = 0.0;
4584  SCIP_Real dout = 0.0;
4585  SCIP_Real xpart;
4586  SCIP_Real xval;
4587 
4588  if ( linvars[j] == slackvar )
4589  continue;
4590 
4591  if ( conshdlrdata->sepapersplocal )
4592  {
4593  lb = SCIPvarGetLbLocal(linvars[j]);
4594  ub = SCIPvarGetUbLocal(linvars[j]);
4595 
4596  if ( lb > SCIPvarGetLbGlobal(linvars[j]) )
4597  islocal = TRUE;
4598  if ( ub < SCIPvarGetUbGlobal(linvars[j]) )
4599  islocal = TRUE;
4600  }
4601  else
4602  {
4603  lb = SCIPvarGetLbGlobal(linvars[j]);
4604  ub = SCIPvarGetUbGlobal(linvars[j]);
4605  }
4606 
4607  /* skip cases with unbounded variables */
4608  if ( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
4609  {
4610  finitebound = FALSE;
4611  break;
4612  }
4613 
4614  /* compute rest parts for i in the set (din) or not in the set (dout) */
4615  linval = signfactor * linvals[j];
4616  if ( SCIPisNegative(scip, linval) )
4617  {
4618  din += linval * ub;
4619  dout += linval * lb;
4620  }
4621  else if ( SCIPisPositive(scip, linval) )
4622  {
4623  din += linval * lb;
4624  dout += linval * ub;
4625  }
4626 
4627  xval = SCIPgetSolVal(scip, sol, linvars[j]);
4628  xpart = linval * xval;
4629 
4630  /* if din > dout, we want to include i in the set */
4631  if ( SCIPisGT(scip, binval * din, binval * dout + xpart) )
4632  {
4633  ypart += din;
4634  cutval += binval * din;
4635  }
4636  else
4637  {
4638  /* otherwise i is not in the set */
4639  ypart += dout;
4640 
4641  cutrhs += dout;
4642  cutval += binval * dout + xpart;
4643 
4644  cutvars[cnt] = linvars[j];
4645  cutvals[cnt++] = linval;
4646  }
4647  }
4648 
4649  if ( ! finitebound )
4650  continue;
4651 
4652  if ( SCIPisEfficacious(scip, cutval - cutrhs) )
4653  {
4654  SCIP_ROW* row;
4655  SCIP_Bool infeasible;
4656  char name[50];
4657 
4658  /* add y-variable */
4659  cutvars[cnt] = binvar;
4660  cutvals[cnt] = ypart;
4661  ++cnt;
4662 
4663  SCIPdebugMsg(scip, "Found cut of lhs value %f > %f.\n", cutval, cutrhs);
4664  (void) SCIPsnprintf(name, 50, "persp%d", conshdlrdata->nperspcutsgen + *nGen);
4665  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), cutrhs, islocal, FALSE, conshdlrdata->removable) );
4666  SCIP_CALL( SCIPaddVarsToRow(scip, row, cnt, cutvars, cutvals) );
4667 #ifdef SCIP_OUTPUT
4668  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
4669 #endif
4670  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
4671  assert( ! infeasible );
4672  SCIP_CALL( SCIPreleaseRow(scip, &row));
4673  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
4674  ++(*nGen);
4675  }
4676  }
4677  if ( *nGen >= maxsepacuts )
4678  break;
4679  }
4680 
4681  SCIPfreeBufferArray(scip, &cutvals);
4682  SCIPfreeBufferArray(scip, &cutvars);
4683 
4684  return SCIP_OKAY;
4685 }
4686 
4687 
4688 /** separation method
4689  *
4690  * We first check whether coupling inequalities can be separated (if required). If not enough of
4691  * these could be generated, we check whether IIS inequalities can be separated.
4692  */
4693 static
4695  SCIP* scip, /**< SCIP pointer */
4696  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4697  int nconss, /**< number of constraints */
4698  int nusefulconss, /**< number of useful constraints */
4699  SCIP_CONS** conss, /**< indicator constraints */
4700  SCIP_SOL* sol, /**< solution to be separated */
4701  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4702  SCIP_RESULT* result /**< result */
4703  )
4704 {
4705  SCIP_CONSHDLRDATA* conshdlrdata;
4706  int maxsepacuts;
4707  int ncuts;
4708 
4709  assert( scip != NULL );
4710  assert( conshdlr != NULL );
4711  assert( conss != NULL );
4712  assert( result != NULL );
4713 
4714  *result = SCIP_DIDNOTRUN;
4715 
4716  if ( nconss == 0 )
4717  return SCIP_OKAY;
4718 
4719  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4720  assert( conshdlrdata != NULL );
4721  ncuts = 0;
4722 
4723  /* get the maximal number of cuts allowed in a separation round */
4724  if ( SCIPgetDepth(scip) == 0 )
4725  maxsepacuts = conshdlrdata->maxsepacutsroot;
4726  else
4727  maxsepacuts = conshdlrdata->maxsepacuts;
4728 
4729  /* first separate coupling inequalities (if required) */
4730  if ( conshdlrdata->sepacouplingcuts )
4731  {
4732  int c;
4733 
4734  *result = SCIP_DIDNOTFIND;
4735 
4736  /* check each constraint */
4737  for (c = 0; c < nusefulconss && ncuts < maxsepacuts; ++c)
4738  {
4739  SCIP_CONSDATA* consdata;
4740  SCIP_Bool islocal;
4741  SCIP_Real ub;
4742 
4743  assert( conss != NULL );
4744  assert( conss[c] != NULL );
4745  consdata = SCIPconsGetData(conss[c]);
4746  assert( consdata != NULL );
4747  assert( consdata->slackvar != NULL );
4748  assert( consdata->binvar != NULL );
4749 
4750  /* get upper bound for slack variable in linear constraint */
4751  islocal = FALSE;
4752  if ( conshdlrdata->sepacouplinglocal )
4753  {
4754  ub = SCIPvarGetUbLocal(consdata->slackvar);
4755  if ( ub < SCIPvarGetUbGlobal(consdata->slackvar) )
4756  islocal = TRUE;
4757  }
4758  else
4759  ub = SCIPvarGetUbGlobal(consdata->slackvar);
4760  assert( ! SCIPisFeasNegative(scip, ub) );
4761 
4762  /* only use coefficients that are not too large */
4763  if ( ub <= conshdlrdata->sepacouplingvalue )
4764  {
4765  SCIP_Real activity;
4766 
4767  activity = SCIPgetSolVal(scip, sol, consdata->slackvar) + ub * SCIPgetSolVal(scip, sol, consdata->binvar) - ub;
4768  if ( SCIPisEfficacious(scip, activity) )
4769  {
4770  SCIP_ROW* row;
4771  SCIP_Bool infeasible;
4772 #ifndef NDEBUG
4773  char name[50];
4774 
4775  (void) SCIPsnprintf(name, 50, "couple%d", c);
4776  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
4777 #else
4778  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], "", -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
4779 #endif
4780  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4781 
4782  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
4783  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
4784  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4785 
4786  SCIPdebugMsg(scip, "Separated coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
4787 #ifdef SCIP_OUTPUT
4788  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
4789 #endif
4790  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
4791  assert( ! infeasible );
4792  SCIP_CALL( SCIPreleaseRow(scip, &row));
4793 
4794  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
4795  *result = SCIP_SEPARATED;
4796 
4797  ++ncuts;
4798  }
4799  }
4800  }
4801  SCIPdebugMsg(scip, "Number of separated coupling inequalities: %d.\n", ncuts);
4802  }
4803 
4804  /* separate cuts from the alternative lp (if required) */
4805  if ( conshdlrdata->sepaalternativelp && ncuts < SEPAALTTHRESHOLD )
4806  {
4807  SCIP_Bool cutoff;
4808  int noldcuts;
4809 
4810  SCIPdebugMsg(scip, "Separating inequalities for indicator constraints.\n");
4811 
4812  noldcuts = ncuts;
4813  if ( *result == SCIP_DIDNOTRUN )
4814  *result = SCIP_DIDNOTFIND;
4815 
4816  /* start separation */
4817  SCIP_CALL( separateIISRounding(scip, conshdlr, sol, enfosepatype, nconss, conss, maxsepacuts, &cutoff, &ncuts) );
4818  SCIPdebugMsg(scip, "Separated %d cuts from indicator constraints.\n", ncuts - noldcuts);
4819 
4820  if ( cutoff )
4821  *result = SCIP_CUTOFF;
4822  else if ( ncuts > noldcuts )
4823  {
4824  conshdlrdata->niiscutsgen += ncuts;
4825 
4826  /* possibly overwrite result from separation above */
4827  if ( conshdlrdata->genlogicor )
4828  *result = SCIP_CONSADDED;
4829  else
4830  *result = SCIP_SEPARATED;
4831  }
4832  }
4833 
4834  /* separate cuts based on perspective formulation */
4835  if ( conshdlrdata->sepaperspective && ncuts < SEPAALTTHRESHOLD )
4836  {
4837  int noldcuts;
4838 
4839  SCIPdebugMsg(scip, "Separating inequalities based on perspective formulation.\n");
4840 
4841  noldcuts = ncuts;
4842  if ( *result == SCIP_DIDNOTRUN )
4843  *result = SCIP_DIDNOTFIND;
4844 
4845  /* start separation */
4846  SCIP_CALL( separatePerspective(scip, conshdlr, sol, nconss, conss, maxsepacuts, &ncuts) );
4847  SCIPdebugMsg(scip, "Separated %d cuts from perspective formulation.\n", ncuts - noldcuts);
4848 
4849  if ( ncuts > noldcuts )
4850  {
4851  conshdlrdata->nperspcutsgen += ncuts;
4852 
4853  /* possibly overwrite result from separation above */
4854  *result = SCIP_SEPARATED;
4855  }
4856  }
4857 
4858  return SCIP_OKAY;
4859 }
4860 
4861 
4862 /** initializes the constraint handler data */
4863 static
4864 void initConshdlrData(
4865  SCIP* scip, /**< SCIP pointer */
4866  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
4867  )
4868 {
4869  assert( conshdlrdata != NULL );
4870 
4871  conshdlrdata->removable = TRUE;
4872  conshdlrdata->scaled = FALSE;
4873  conshdlrdata->altlp = NULL;
4874  conshdlrdata->nrows = 0;
4875  conshdlrdata->varhash = NULL;
4876  conshdlrdata->slackhash = NULL;
4877  conshdlrdata->lbhash = NULL;
4878  conshdlrdata->ubhash = NULL;
4879  conshdlrdata->nlbbounds = 0;
4880  conshdlrdata->nubbounds = 0;
4881  conshdlrdata->nslackvars = 0;
4882  conshdlrdata->objcutindex = -1;
4883  conshdlrdata->objupperbound = SCIPinfinity(scip);
4884  conshdlrdata->objaltlpbound = SCIPinfinity(scip);
4885  conshdlrdata->roundingminthres = 0.1;
4886  conshdlrdata->roundingmaxthres = 0.6;
4887  conshdlrdata->maxroundingrounds = MAXROUNDINGROUNDS;
4888  conshdlrdata->roundingoffset = 0.1;
4889  conshdlrdata->addedcouplingcons = FALSE;
4890  conshdlrdata->ninitconss = 0;
4891  conshdlrdata->nbinvarszero = 0;
4892  conshdlrdata->performedrestart = FALSE;
4893  conshdlrdata->objindicatoronly = FALSE;
4894  conshdlrdata->objothervarsonly = FALSE;
4895  conshdlrdata->minabsobj = 0.0;
4896  conshdlrdata->normtype = 'e';
4897  conshdlrdata->niiscutsgen = 0;
4898  conshdlrdata->nperspcutsgen = 0;
4899 }
4900 
4901 
4902 /* ---------------------------- upgrading methods -----------------------------------*/
4903 
4904 /** tries to upgrade a linear constraint into an indicator constraint
4905  *
4906  * 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
4907  * it to an indicator constraint if for the residual value \f$a^T x \geq \gamma\f$, we have \f$\alpha + \gamma \geq
4908  * \beta\f$: in this case, the constraint is always satisfied if \f$y = 1\f$.
4909  *
4910  * 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
4911  * upgrade it to an indicator constraint if for the residual value \f$a^T x \leq \gamma\f$, we have \f$\alpha + \gamma
4912  * \leq \beta\f$.
4913  */
4914 static
4915 SCIP_DECL_LINCONSUPGD(linconsUpgdIndicator)
4916 { /*lint --e{715}*/
4917  SCIP_CONSHDLRDATA* conshdlrdata;
4918  SCIP_CONSHDLR* conshdlr;
4919  SCIP_Real minactivity = 0.0;
4920  SCIP_Real maxactivity = 0.0;
4921  SCIP_Real maxabsval = -1.0;
4922  SCIP_Real secabsval = -1.0;
4923  int maxabsvalidx = -1;
4924  int j;
4925 
4926  assert( scip != NULL );
4927  assert( upgdcons != NULL );
4928  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0 );
4929  assert( ! SCIPconsIsModifiable(cons) );
4930 
4931  /* do not upgrade if there are at most 2 variables (2 variables should be upgraded to a varbound constraint) */
4932  if ( nvars <= 2 )
4933  return SCIP_OKAY;
4934 
4935  /* cannot currently ranged constraints, since we can only return one constraint (and we would need one for each side each) */
4936  if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
4937  return SCIP_OKAY;
4938 
4939  /* check whether upgrading is turned on */
4940  conshdlr = SCIPfindConshdlr(scip, "indicator");
4941  assert( conshdlr != NULL );
4942  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4943  assert( conshdlrdata != NULL );
4944 
4945  if ( ! conshdlrdata->upgradelinear )
4946  return SCIP_OKAY;
4947 
4948  /* calculate activities */
4949  for (j = 0; j < nvars; ++j)
4950  {
4951  SCIP_VAR* var;
4952  SCIP_Real val;
4953  SCIP_Real lb;
4954  SCIP_Real ub;
4955 
4956  val = vals[j];
4957  assert( ! SCIPisZero(scip, val) );
4958 
4959  var = vars[j];
4960  assert( var != NULL );
4961 
4962  /* store maximal (and second to largest) value of coefficients */
4963  if ( SCIPisGE(scip, REALABS(val), maxabsval) )
4964  {
4965  secabsval = maxabsval;
4966  maxabsval = REALABS(val);
4967  maxabsvalidx = j;
4968  }
4969 
4970  if ( ! SCIPvarIsBinary(var) )
4971  {
4972  if ( val > 0.0 )
4973  {
4974  lb = SCIPvarGetLbGlobal(var);
4975  ub = SCIPvarGetUbGlobal(var);
4976  }
4977  else
4978  {
4979  ub = SCIPvarGetLbGlobal(var);
4980  lb = SCIPvarGetUbGlobal(var);
4981  }
4982 
4983  /* compute minimal activity */
4984  if ( SCIPisInfinity(scip, -lb) )
4985  minactivity = -SCIPinfinity(scip);
4986  else
4987  {
4988  if ( ! SCIPisInfinity(scip, -minactivity) )
4989  minactivity += val * lb;
4990  }
4991 
4992  /* compute maximal activity */
4993  if ( SCIPisInfinity(scip, ub) )
4994  maxactivity = SCIPinfinity(scip);
4995  else
4996  {
4997  if ( ! SCIPisInfinity(scip, maxactivity) )
4998  maxactivity += val * ub;
4999  }
5000  }
5001  }
5002  assert( maxabsval >= 0.0 );
5003  assert( 0 <= maxabsvalidx && maxabsvalidx < nvars );
5004 
5005  /* exit if largest coefficient does not belong to binary variable */
5006  if ( ! SCIPvarIsBinary(vars[maxabsvalidx]) )
5007  return SCIP_OKAY;
5008 
5009  /* exit if the second largest coefficient is as large as largest */
5010  if ( SCIPisEQ(scip, secabsval, maxabsval) )
5011  return SCIP_OKAY;
5012 
5013  /* cannot upgrade if all activities are infinity */
5014  if ( SCIPisInfinity(scip, -minactivity) && SCIPisInfinity(scip, maxactivity) )
5015  return SCIP_OKAY;
5016 
5017  /* check each variable as indicator variable */
5018  for (j = 0; j < nvars; ++j)
5019  {
5020  SCIP_VAR** indconsvars;
5021  SCIP_Real* indconsvals;
5022  SCIP_Bool upgdlhs = FALSE;
5023  SCIP_Bool upgdrhs = FALSE;
5024  SCIP_Bool indneglhs = FALSE;
5025  SCIP_Bool indnegrhs = FALSE;
5026  SCIP_VAR* indvar;
5027  SCIP_Real indval;
5028  int l;
5029 
5030  indvar = vars[j];
5031  indval = vals[j];
5032  assert( ! SCIPisZero(scip, indval) );
5033 
5034  if ( ! SCIPvarIsBinary(indvar) )
5035  continue;
5036 
5037  /* check for upgrading of lhs */
5038  if ( ! SCIPisInfinity(scip, -minactivity) && ! SCIPisInfinity(scip, -lhs) )
5039  {
5040  /* upgrading is possible with binary variable */
5041  if ( SCIPisGE(scip, minactivity, lhs) )
5042  upgdlhs = TRUE;
5043 
5044  /* upgrading is possible with negated binary variable */
5045  if ( SCIPisGE(scip, minactivity + indval, lhs) )
5046  {
5047  upgdlhs = TRUE;
5048  indneglhs = TRUE;
5049  }
5050  }
5051 
5052  /* check for upgrading of rhs */
5053  if ( ! SCIPisInfinity(scip, maxactivity) && ! SCIPisInfinity(scip, rhs) )
5054  {
5055  /* upgrading is possible with binary variable */
5056  if ( SCIPisLE(scip, maxactivity, rhs) )
5057  upgdrhs = TRUE;
5058 
5059  /* upgrading is possible with negated binary variable */
5060  if ( SCIPisLE(scip, maxactivity + indval, rhs) )
5061  {
5062  upgdrhs = TRUE;
5063  indnegrhs = TRUE;
5064  }
5065  }
5066 
5067  /* upgrade constraint */
5068  if ( upgdlhs || upgdrhs )
5069  {
5070  SCIP_VAR* indvar2;
5071  SCIP_Real bnd;
5072  int cnt = 0;
5073 
5074  assert( ! upgdlhs || ! upgdrhs ); /* cannot treat ranged rows */
5075  SCIPdebugMsg(scip, "upgrading constraint <%s> to an indicator constraint.\n", SCIPconsGetName(cons));
5076 
5077  SCIP_CALL( SCIPallocBufferArray(scip, &indconsvars, nvars - 1) );
5078  SCIP_CALL( SCIPallocBufferArray(scip, &indconsvals, nvars - 1) );
5079 
5080  /* create constraint */
5081  for (l = 0; l < nvars; ++l)
5082  {
5083  if ( vars[l] == indvar )
5084  continue;
5085  indconsvars[cnt] = vars[l];
5086  if ( upgdlhs )
5087  indconsvals[cnt] = -vals[l];
5088  else
5089  indconsvals[cnt] = vals[l];
5090  ++cnt;
5091  }
5092 
5093  if ( indneglhs || indnegrhs )
5094  {
5095  SCIP_CALL( SCIPgetNegatedVar(scip, indvar, &indvar2) );
5096  }
5097  else
5098  indvar2 = indvar;
5099 
5100  if ( upgdlhs )
5101  {
5102  bnd = -lhs;
5103  if ( ! indneglhs )
5104  bnd -= indval;
5105  SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
5108  }
5109  else
5110  {
5111  bnd = rhs;
5112  if ( ! indnegrhs )
5113  bnd -= indval;
5114  SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
5117  }
5118 
5119 #ifdef SCIP_DEBUG
5120  SCIPinfoMessage(scip, NULL, "upgrade: \n");
5121  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
5122  SCIPinfoMessage(scip, NULL, "\n");
5123  SCIP_CALL( SCIPprintCons(scip, *upgdcons, NULL) );
5124  SCIPinfoMessage(scip, NULL, "\n");
5126  SCIPinfoMessage(scip, NULL, " (minact: %f, maxact: %f)\n", minactivity, maxactivity);
5127 #endif
5128 
5129  SCIPfreeBufferArray(scip, &indconsvars);
5130  SCIPfreeBufferArray(scip, &indconsvals);
5131 
5132  return SCIP_OKAY;
5133  }
5134  }
5135 
5136  return SCIP_OKAY;
5137 }
5138 
5139 
5140 /* ---------------------------- constraint handler callback methods ----------------------*/
5141 
5142 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
5143 static
5144 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyIndicator)
5145 { /*lint --e{715}*/
5146  assert( scip != NULL );
5147  assert( conshdlr != NULL );
5148  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5149  assert( valid != NULL );
5150 
5151  /* call inclusion method of constraint handler */
5153 
5154  *valid = TRUE;
5155 
5156  return SCIP_OKAY;
5157 }
5158 
5159 
5160 /** initialization method of constraint handler (called after problem was transformed) */
5161 static
5162 SCIP_DECL_CONSINIT(consInitIndicator)
5163 { /*lint --e{715}*/
5164  SCIP_CONSHDLRDATA* conshdlrdata;
5165 
5166  assert( scip != NULL );
5167  assert( conshdlr != NULL );
5168  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5169 
5170  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5171  assert( conshdlrdata != NULL );
5172 
5173  initConshdlrData(scip, conshdlrdata);
5174 
5175  /* find trysol heuristic */
5176  if ( conshdlrdata->trysolutions && conshdlrdata->heurtrysol == NULL )
5177  {
5178  conshdlrdata->heurtrysol = SCIPfindHeur(scip, "trysol");
5179  }
5180 
5181  return SCIP_OKAY;
5182 }
5183 
5184 
5185 /** deinitialization method of constraint handler (called before transformed problem is freed) */
5186 static
5187 SCIP_DECL_CONSEXIT(consExitIndicator)
5188 { /*lint --e{715}*/
5189  SCIP_CONSHDLRDATA* conshdlrdata;
5190 
5191  assert( scip != NULL );
5192  assert( conshdlr != NULL );
5193  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5194 
5195  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5196 
5197  if ( conshdlrdata->binvarhash != NULL )
5198  SCIPhashmapFree(&conshdlrdata->binvarhash);
5199 
5200  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
5201  conshdlrdata->maxaddlincons = 0;
5202  conshdlrdata->naddlincons = 0;
5203  conshdlrdata->nrows = 0;
5204 
5205  return SCIP_OKAY;
5206 }
5207 
5208 
5209 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
5210 static
5211 SCIP_DECL_CONSFREE(consFreeIndicator)
5213  SCIP_CONSHDLRDATA* conshdlrdata;
5214 
5215  assert( scip != NULL );
5216  assert( conshdlr != NULL );
5217  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5218 
5219  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5220  assert( conshdlrdata != NULL );
5221  assert( conshdlrdata->altlp == NULL );
5222  assert( conshdlrdata->varhash == NULL );
5223  assert( conshdlrdata->lbhash == NULL );
5224  assert( conshdlrdata->ubhash == NULL );
5225  assert( conshdlrdata->slackhash == NULL );
5226 
5227  if ( conshdlrdata->maxaddlincons > 0 )
5228  {
5229  /* if problem was not yet transformed the array may need to be freed, because we did not call the EXIT callback */
5230  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
5231  }
5232  assert( conshdlrdata->addlincons == NULL );
5233  conshdlrdata->naddlincons = 0;
5234  conshdlrdata->maxaddlincons = 0;
5235 
5236  SCIPfreeBlockMemory(scip, &conshdlrdata);
5237 
5238  return SCIP_OKAY;
5239 }
5240 
5241 
5242 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
5243 static
5244 SCIP_DECL_CONSINITSOL(consInitsolIndicator)
5246  SCIP_CONSHDLRDATA* conshdlrdata;
5247  int c;
5248 
5249  assert( scip != NULL );
5250  assert( conshdlr != NULL );
5251  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5252 
5255  return SCIP_OKAY;
5256 
5257  SCIPdebugMsg(scip, "Initsol for indicator constraints.\n");
5258 
5259  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5260  assert( conshdlrdata != NULL );
5261  assert( conshdlrdata->slackhash == NULL );
5262 
5263  SCIP_CALL( SCIPgetCharParam(scip, "separating/efficacynorm", &conshdlrdata->normtype) );
5264 
5265  if ( conshdlrdata->sepaalternativelp )
5266  {
5267  /* generate hash for storing all slack variables (size is just a guess) */
5268  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->slackhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
5269  assert( conshdlrdata->slackhash != NULL );
5270 
5271  /* first initialize slack hash */
5272  for (c = 0; c < nconss; ++c)
5273  {
5274  SCIP_CONSDATA* consdata;
5275 
5276  assert( conss != NULL );
5277  assert( conss[c] != NULL );
5278  assert( SCIPconsIsTransformed(conss[c]) );
5279 
5280  consdata = SCIPconsGetData(conss[c]);
5281  assert( consdata != NULL );
5282 
5283  assert( consdata->slackvar != NULL );
5284 
5285  /* insert slack variable into hash */
5286  SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->slackhash, consdata->slackvar, INT_MAX) );
5287  assert( SCIPhashmapExists(conshdlrdata->slackhash, consdata->slackvar) );
5288  ++conshdlrdata->nslackvars;
5289  }
5290 
5291  if ( conshdlrdata->genlogicor )
5292  {
5293  SCIP_CONSHDLR* logicorconshdlr;
5294  int logicorsepafreq;
5295  int sepafreq;
5296 
5297  /* If we generate logicor constraints, but the separation frequency is not 1, output warning */
5298  logicorconshdlr = SCIPfindConshdlr(scip, "logicor");
5299  if ( logicorconshdlr == NULL )
5300  {
5301  SCIPerrorMessage("Logicor constraint handler not included, cannot generate constraints.\n");
5302  return SCIP_ERROR;
5303  }
5304  logicorsepafreq = SCIPconshdlrGetSepaFreq(logicorconshdlr);
5305  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
5306  if ( (sepafreq != -1 || conshdlrdata->enforcecuts) && logicorsepafreq != 1 )
5307  {
5308  SCIPwarningMessage(scip, "For better performance set parameter 'constraints/logicor/sepafreq' to 1 if 'constraints/included/genlogicor' is true.\n");
5309  }
5310  }
5311  }
5312 
5313  /* check each constraint */
5314  conshdlrdata->objothervarsonly = TRUE;
5315  for (c = 0; c < nconss; ++c)
5316  {
5317  SCIP_CONSDATA* consdata;
5318 
5319  assert( conss != NULL );
5320  assert( conss[c] != NULL );
5321  assert( SCIPconsIsTransformed(conss[c]) );
5322 
5323  consdata = SCIPconsGetData(conss[c]);
5324  assert( consdata != NULL );
5325  assert( consdata->binvar != NULL );
5326  assert( consdata->slackvar != NULL );
5327 
5328  /* Presolving might replace a slack variable by an active variable. Thus, the objective of a slack variables might
5329  * be nonzero. However, we do not need to check slack variables here. */
5330  if ( ! SCIPisZero(scip, varGetObjDelta(consdata->binvar)) )
5331  conshdlrdata->objothervarsonly = FALSE;
5332 
5333  /* deactivate */
5334  if ( ! consdata->linconsactive )
5335  {
5336  SCIP_CALL( SCIPdisableCons(scip, consdata->lincons) );
5337  }
5338  else
5339  {
5340  /* add constraint to alternative LP if not already done */
5341  if ( conshdlrdata->sepaalternativelp && consdata->colindex < 0 )
5342  {
5343  SCIP_CALL( addAltLPConstraint(scip, conshdlr, consdata->lincons, consdata->slackvar, 1.0, &consdata->colindex) );
5344  SCIPdebugMsg(scip, "Added column for <%s> to alternative LP with column index %d.\n", SCIPconsGetName(conss[c]),consdata->colindex);
5345 #ifdef SCIP_OUTPUT
5346  SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
5347  SCIPinfoMessage(scip, NULL, ";\n");
5348 #endif
5349  }
5350  }
5351 
5352  /* add nlrow representation to NLP, if NLP had been constructed
5353  *
5354  * Note, that we did not tell SCIP in exitpre that we have something to add to the NLP, thus
5355  * indicators are only available in the NLP for MINLPs, but not for MIPs with indicators.
5356  */
5357  if ( SCIPisNLPConstructed(scip) && SCIPconsIsChecked(conss[c]) )
5358  {
5359  /* create nonlinear row binary variable * slack variable = 0 */
5360  SCIP_NLROW* nlrow;
5361  SCIP_EXPR* quadexpr;
5362  SCIP_EXPR* varexprs[2];
5363 
5364  SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[0], consdata->binvar, NULL, NULL) );
5365  SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[1], consdata->slackvar, NULL, NULL) );
5366  SCIP_CALL( SCIPcreateExprProduct(scip, &quadexpr, 2, varexprs, 1.0, NULL, NULL) );
5367 
5368  SCIP_CALL( SCIPcreateNlRow(scip, &nlrow, SCIPconsGetName(conss[c]), 0.0, 0, NULL, NULL, quadexpr, 0.0, 0.0, SCIP_EXPRCURV_UNKNOWN) );
5369 
5370  SCIP_CALL( SCIPreleaseExpr(scip, &quadexpr) );
5371  SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[1]) );
5372  SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[0]) );
5373 
5374  /* add row to NLP and forget about it */
5375  SCIP_CALL( SCIPaddNlRow(scip, nlrow) );
5376  SCIP_CALL( SCIPreleaseNlRow(scip, &nlrow) );
5377  }
5378  }
5379 
5380  SCIPdebugMsg(scip, "Initialized %d indicator constraints.\n", nconss);
5381 
5382  /* check additional constraints */
5383  if ( conshdlrdata->sepaalternativelp )
5384  {
5385  SCIP_CONS* cons;
5386  int colindex;
5387  int cnt = 0;
5388 
5389  /* add stored linear constraints if they exist */
5390  if ( conshdlrdata->naddlincons > 0 )
5391  {
5392  for (c = 0; c < conshdlrdata->naddlincons; ++c)
5393  {
5394  cons = conshdlrdata->addlincons[c];
5395 
5396  /* get transformed constraint - since it is needed only here, we do not store the information */
5397  if ( ! SCIPconsIsTransformed(cons) )
5398  {
5399  SCIP_CALL( SCIPgetTransformedCons(scip, conshdlrdata->addlincons[c], &cons) );
5400 
5401  /* @todo check when exactly the transformed constraint does not exist - SCIPisActive() does not suffice */
5402  if ( cons == NULL )
5403  continue;
5404  }
5405  SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
5406  ++cnt;
5407 
5408 #ifdef SCIP_OUTPUT
5409  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
5410  SCIPinfoMessage(scip, NULL, ";\n");
5411 #endif
5412  }
5413  SCIPdebugMsg(scip, "Added %d additional columns to alternative LP.\n", cnt);
5414  }
5415  else
5416  {
5417  /* if no stored linear constraints are available, possibly collect other linear constraints; we only use linear
5418  * constraints, since most other constraints involve integral variables, and in this context we will likely
5419  * benefit much more from continuous variables. */
5420  if ( conshdlrdata->useotherconss )
5421  {
5422  const char* conshdlrname;
5423  SCIP_CONS** allconss;
5424  int nallconss;
5425 
5426  nallconss = SCIPgetNConss(scip);
5427  allconss = SCIPgetConss(scip);
5428 
5429  /* loop through all constraints */
5430  for (c = 0; c < nallconss; ++c)
5431  {
5432  /* get constraint */
5433  cons = allconss[c];
5434  assert( cons != NULL );
5435  assert( SCIPconsIsTransformed(cons) );
5436 
5437  /* get constraint handler name */
5438  conshdlrname = SCIPconshdlrGetName(SCIPconsGetHdlr(cons));
5439 
5440  /* check type of constraint (only take modifiable linear constraints) */
5441  if ( strcmp(conshdlrname, "linear") == 0 && ! SCIPconsIsModifiable(cons) )
5442  {
5443  /* avoid adding linear constraints that correspond to indicator constraints */
5444  if ( strncmp(SCIPconsGetName(cons), "indlin", 6) != 0 )
5445  {
5446  SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
5447  SCIPdebugMsg(scip, "Added column for linear constraint <%s> to alternative LP with column index %d.\n", SCIPconsGetName(cons), colindex);
5448  ++cnt;
5449  }
5450  }
5451  }
5452  SCIPdebugMsg(scip, "Added %d additional columns from linear constraints to alternative LP.\n", cnt);
5453  }
5454  }
5455  }
5456 
5457  /* initialize event handler if restart should be forced */
5458  if ( conshdlrdata->forcerestart )
5459  {
5460  SCIP_Bool* covered;
5461  SCIP_VAR** vars;
5462  int nvars;
5463  int j;
5464 
5465  assert( conshdlrdata->eventhdlrrestart != NULL );
5466 
5467  /* store number of initial constraints */
5468  conshdlrdata->ninitconss = SCIPconshdlrGetNActiveConss(conshdlr);
5469 
5470  /* reset number of fixed binary variables */
5471  conshdlrdata->nbinvarszero = 0;
5472 
5473  /* loop through variables */
5474  nvars = SCIPgetNVars(scip);
5475  vars = SCIPgetVars(scip);
5476 
5477  conshdlrdata->objindicatoronly = FALSE;
5478  conshdlrdata->minabsobj = SCIP_REAL_MAX;
5479 
5480  /* unmark all variables */
5481  SCIP_CALL( SCIPallocBufferArray(scip, &covered, nvars) );
5482  for (j = 0; j < nvars; ++j)
5483  covered[j] = FALSE;
5484 
5485  /* mark indicator variables */
5486  for (c = 0; c < nconss; ++c)
5487  {
5488  SCIP_CONSDATA* consdata;
5489  int probindex;
5490 
5491  assert( conss != NULL );
5492  assert( conss[c] != NULL );
5493 
5494  /* avoid non-active indicator constraints */
5495  if ( ! SCIPconsIsActive(conss[c]) )
5496  continue;
5497 
5498  consdata = SCIPconsGetData(conss[c]);
5499  assert( consdata != NULL );
5500  assert( consdata->binvar != NULL );
5501 
5502  if ( SCIPvarIsNegated(consdata->binvar) )
5503  {
5504  assert( SCIPvarGetNegatedVar(consdata->binvar) != NULL );
5505  probindex = SCIPvarGetProbindex(SCIPvarGetNegatedVar(consdata->binvar));
5506  }
5507  else
5508  probindex = SCIPvarGetProbindex(consdata->binvar);
5509 
5510  /* if presolving detected infeasibility it might be that the binary variables are not active */
5511  if ( probindex < 0 )
5512  continue;
5513 
5514  assert( 0 <= probindex && probindex < nvars );
5515  covered[probindex] = TRUE;
5516  }
5517 
5518  /* check all variables */
5519  for (j = 0; j < nvars; ++j)
5520  {
5521  SCIP_Real obj;
5522 
5523  obj = SCIPvarGetObj(vars[j]);
5524  if ( ! SCIPisZero(scip, obj) )
5525  {
5526  if ( ! covered[j] )
5527  break;
5528  if ( ! SCIPisIntegral(scip, obj) )
5529  break;
5530  if ( REALABS(obj) < conshdlrdata->minabsobj )
5531  conshdlrdata->minabsobj = REALABS(obj);
5532  }
5533  }
5534 
5535  /* if all variables have integral objective and only indicator variables have nonzero objective */
5536  if ( j >= nvars )
5537  {
5538  /* if there are variables with nonzero objective */
5539  if ( conshdlrdata->minabsobj < SCIP_REAL_MAX )
5540  {
5541  assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
5542  assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0) );
5543 
5544  conshdlrdata->objindicatoronly = TRUE;
5545 
5546  assert( conshdlrdata->eventhdlrrestart != NULL );
5547  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
5548  }
5549  }
5550 
5551  SCIPfreeBufferArray(scip, &covered);
5552  }
5553 
5554  return SCIP_OKAY;
5555 }
5556 
5557 
5558 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
5559 static
5560 SCIP_DECL_CONSEXITSOL(consExitsolIndicator)
5561 { /*lint --e{715}*/
5562  SCIP_CONSHDLRDATA* conshdlrdata;
5563  int c;
5564 
5565  assert( scip != NULL );
5566  assert( conshdlr != NULL );
5567  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5568 
5569  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5570  assert( conshdlrdata != NULL );
5571 
5572  if ( conshdlrdata->sepaalternativelp )
5573  {
5574  if ( conshdlrdata->slackhash != NULL )
5575  {
5576 #ifdef SCIP_DEBUG
5577  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator slack hash:\n");
5578  SCIPhashmapPrintStatistics(conshdlrdata->slackhash, SCIPgetMessagehdlr(scip));
5579 #endif
5580  SCIPhashmapFree(&conshdlrdata->slackhash);
5581  }
5582 
5583  if ( conshdlrdata->altlp != NULL )
5584  {
5585  assert( conshdlrdata->varhash != NULL );
5586  assert( conshdlrdata->lbhash != NULL );
5587  assert( conshdlrdata->ubhash != NULL );
5588 
5589 #ifdef SCIP_DEBUG
5590  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator var hash:\n");
5591  SCIPhashmapPrintStatistics(conshdlrdata->varhash, SCIPgetMessagehdlr(scip));
5592  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator lower bound hash:\n");
5593  SCIPhashmapPrintStatistics(conshdlrdata->lbhash, SCIPgetMessagehdlr(scip));
5594  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator upper bound hash:\n");
5595  SCIPhashmapPrintStatistics(conshdlrdata->ubhash, SCIPgetMessagehdlr(scip));
5596 #endif
5597 
5598  SCIPhashmapFree(&conshdlrdata->varhash);
5599  SCIPhashmapFree(&conshdlrdata->lbhash);
5600  SCIPhashmapFree(&conshdlrdata->ubhash);
5601 
5602  SCIP_CALL( SCIPlpiFree(&conshdlrdata->altlp) );
5603 
5604  /* save the information that the columns have been deleted */
5605  for (c = 0; c < nconss; ++c)
5606  {
5607  SCIP_CONSDATA* consdata;
5608 
5609  assert( conss != NULL );
5610  assert( conss[c] != NULL );
5611 
5612  consdata = SCIPconsGetData(conss[c]);
5613  assert( consdata != NULL );
5614  consdata->colindex = -1;
5615  }
5616  }
5617  }
5618  else
5619  {
5620  assert( conshdlrdata->slackhash == NULL );
5621  assert( conshdlrdata->varhash == NULL );
5622  assert( conshdlrdata->lbhash == NULL );
5623  assert( conshdlrdata->ubhash == NULL );
5624  }
5625 
5626  return SCIP_OKAY;
5627 }
5628 
5629 
5630 /** frees specific constraint data */
5631 static
5632 SCIP_DECL_CONSDELETE(consDeleteIndicator)
5634  assert( scip != NULL );
5635  assert( conshdlr != NULL );
5636  assert( cons != NULL );
5637  assert( consdata != NULL );
5638  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5639 
5640 #ifdef SCIP_MORE_DEBUG
5641  SCIPdebugMsg(scip, "Deleting indicator constraint <%s>.\n", SCIPconsGetName(cons) );
5642 #endif
5643 
5644  /* drop events on transformed variables */
5645  if ( SCIPconsIsTransformed(cons) )
5646  {
5647  SCIP_CONSHDLRDATA* conshdlrdata;
5648 
5649  /* get constraint handler data */
5650  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5651  assert( conshdlrdata != NULL );
5652 
5653  if ( conshdlrdata->sepaalternativelp )
5654  {
5655  SCIP_CALL( deleteAltLPConstraint(scip, conshdlr, cons) );
5656  }
5657 
5658  assert( (*consdata)->slackvar != NULL );
5659  assert( (*consdata)->binvar != NULL );
5660 
5661  /* free events only in correct stages */
5663  {
5664  if ( (*consdata)->linconsactive )
5665  {
5666  assert( conshdlrdata->eventhdlrbound != NULL );
5667  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
5668  (SCIP_EVENTDATA*)*consdata, -1) );
5669  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
5670  (SCIP_EVENTDATA*)*consdata, -1) );
5671  }
5672  if ( conshdlrdata->forcerestart )
5673  {
5674  assert( conshdlrdata->eventhdlrrestart != NULL );
5675  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
5676  (SCIP_EVENTDATA*) conshdlrdata, -1) );
5677  }
5678  }
5679  }
5680 
5681  /* Can there be cases where lincons is NULL, e.g., if presolve found the problem infeasible? */
5682  assert( (*consdata)->lincons != NULL );
5683 
5684  /* release linear constraint and slack variable */
5685  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->slackvar) );
5686  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->lincons) );
5687 
5688  SCIPfreeBlockMemory(scip, consdata);
5689 
5690  return SCIP_OKAY;
5691 }
5692 
5693 
5694 /** transforms constraint data into data belonging to the transformed problem */
5695 static
5696 SCIP_DECL_CONSTRANS(consTransIndicator)
5698  SCIP_CONSDATA* consdata;
5699  SCIP_CONSHDLRDATA* conshdlrdata;
5700  SCIP_CONSDATA* sourcedata;
5701  char s[SCIP_MAXSTRLEN];
5702 
5703  assert( scip != NULL );
5704  assert( conshdlr != NULL );
5705  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5706  assert( sourcecons != NULL );
5707  assert( targetcons != NULL );
5708 
5709  /* get constraint handler data */
5710  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5711  assert( conshdlrdata != NULL );
5712  assert( conshdlrdata->eventhdlrbound != NULL );
5713 
5714 #ifdef SCIP_MORE_DEBUG
5715  SCIPdebugMsg(scip, "Transforming indicator constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
5716 #endif
5717 
5718  /* get data of original constraint */
5719  sourcedata = SCIPconsGetData(sourcecons);
5720  assert( sourcedata != NULL );
5721  assert( sourcedata->binvar != NULL );
5722 
5723  /* check for slackvar */
5724  if ( sourcedata->slackvar == NULL )
5725  {
5726  SCIPerrorMessage("The indicator constraint <%s> needs a slack variable.\n", SCIPconsGetName(sourcecons));
5727  return SCIP_INVALIDDATA;
5728  }
5729 
5730  /* check for linear constraint */
5731  if ( sourcedata->lincons == NULL )
5732  {
5733  SCIPerrorMessage("The indicator constraint <%s> needs a linear constraint variable.\n", SCIPconsGetName(sourcecons));
5734  return SCIP_INVALIDDATA;
5735  }
5736  assert( sourcedata->lincons != NULL );
5737  assert( sourcedata->slackvar != NULL );
5738 
5739  /* create constraint data */
5740  consdata = NULL;
5741  /* Note that the constraint has activeone = TRUE, since the binary variable has been negated already if needed. */
5742  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, SCIPconsGetName(sourcecons), &consdata, conshdlrdata->eventhdlrbound,
5743  conshdlrdata->eventhdlrrestart, sourcedata->binvar, TRUE, sourcedata->lessthanineq, sourcedata->slackvar, sourcedata->lincons, sourcedata->linconsactive) );
5744  consdata->activeone = sourcedata->activeone;
5745  assert( consdata != NULL );
5746 
5747  /* capture slack variable and linear constraint */
5748  SCIP_CALL( SCIPcaptureVar(scip, consdata->slackvar) );
5749  SCIP_CALL( SCIPcaptureCons(scip, consdata->lincons) );
5750 
5751  /* create transformed constraint with the same flags */
5752  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
5753  SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
5754  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
5755  SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
5756  SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
5757  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
5758  SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
5759 
5760  /* make sure that binary variable hash exists */
5761  if ( conshdlrdata->sepaalternativelp )
5762  {
5763  if ( conshdlrdata->binvarhash == NULL )
5764  {
5765  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
5766  }
5767 
5768  /* check whether binary variable is present: note that a binary variable might appear several times, but this seldomly happens. */
5769  assert( conshdlrdata->binvarhash != NULL );
5770  if ( ! SCIPhashmapExists(conshdlrdata->binvarhash, (void*) consdata->binvar) )
5771  {
5772  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binvarhash, (void*) consdata->binvar, (void*) (*targetcons)) );
5773  }
5774  }
5775 
5776  return SCIP_OKAY;
5777 }
5778 
5779 
5780 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
5781 static
5782 SCIP_DECL_CONSINITPRE(consInitpreIndicator)
5783 { /*lint --e{715}*/
5784  SCIP_CONSHDLRDATA* conshdlrdata;
5785  int c;
5786 
5787  assert( scip != NULL );
5788  assert( conshdlr != NULL );
5789  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5790 
5791  if ( SCIPgetStatus(scip) != SCIP_STATUS_UNKNOWN )
5792  return SCIP_OKAY;
5793 
5794  SCIPdebugMsg(scip, "Initpre method for indicator constraints.\n");
5795 
5796  /* check each constraint and get transformed linear constraint */
5797  for (c = 0; c < nconss; ++c)
5798  {
5799  SCIP_CONSDATA* consdata;
5800 
5801  assert( conss != NULL );
5802  assert( conss[c] != NULL );
5803  assert( SCIPconsIsTransformed(conss[c]) );
5804 
5805  consdata = SCIPconsGetData(conss[c]);
5806  assert( consdata != NULL );
5807 
5808  /* if not happened already, get transformed linear constraint */
5809  assert( consdata->lincons != NULL );
5810  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear") == 0 );
5811 
5812  /* in a restart the linear constraint might already be transformed */
5813  if ( ! SCIPconsIsTransformed(consdata->lincons) )
5814  {
5815  SCIP_CONS* translincons;
5816 
5817  SCIP_CALL( SCIPgetTransformedCons(scip, consdata->lincons, &translincons) );
5818  assert( translincons != NULL );
5819 
5820  SCIP_CALL( SCIPreleaseCons(scip, &consdata->lincons) );
5821  SCIP_CALL( SCIPcaptureCons(scip, translincons) );
5822  consdata->lincons = translincons;
5823  }
5824  }
5825 
5826  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5827  assert( conshdlrdata != NULL );
5828 
5829  /* reset flag, in case presolve was called for some problem before */
5830  conshdlrdata->addedcouplingcons = FALSE;
5831 
5832  return SCIP_OKAY;
5833 }
5834 
5835 
5836 /** presolving method of constraint handler
5837  *
5838  * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
5839  * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
5840  * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not
5841  * inserted. Depending on the parameter @a addcouplingcons we add a variable upper bound or a row
5842  * (in consInitlpIndicator()).
5843  *
5844  * @warning We can never delete linear constraints, because we need them to get the right values
5845  * for the slack variables!
5846  */
5847 static
5848 SCIP_DECL_CONSPRESOL(consPresolIndicator)
5849 { /*lint --e{715}*/
5850  SCIP_CONSHDLRDATA* conshdlrdata;
5851  SCIP_Bool noReductions;
5852  SCIPdebug( int oldnfixedvars = *nfixedvars; )
5853  SCIPdebug( int oldndelconss = *ndelconss; )
5854  int c;
5855 
5856  assert( scip != NULL );
5857  assert( conshdlr != NULL );
5858  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5859  assert( result != NULL );
5860 
5861  *result = SCIP_DIDNOTRUN;
5862  /* get constraint handler data */
5863  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5864  assert( conshdlrdata != NULL );
5865 
5866  SCIPdebugMsg(scip, "Presolving indicator constraints.\n");
5867 
5868  /* only run if success is possible */
5869  if ( nrounds == 0 || nnewfixedvars > 0 || nnewchgbds > 0 || nnewaggrvars > 0 )
5870  {
5871  *result = SCIP_DIDNOTFIND;
5872 
5873  /* check each constraint */
5874  for (c = 0; c < nconss; ++c)
5875  {
5876  SCIP_CONSDATA* consdata;
5877  SCIP_CONS* cons;
5878  SCIP_Bool success;
5879  SCIP_Bool cutoff;
5880 
5881  assert( conss != NULL );
5882  assert( conss[c] != NULL );
5883  cons = conss[c];
5884  consdata = SCIPconsGetData(cons);
5885  assert( consdata != NULL );
5886  assert( consdata->binvar != NULL );
5887  assert( ! SCIPconsIsModifiable(cons) );
5888 
5889 #ifdef SCIP_MORE_DEBUG
5890  SCIPdebugMsg(scip, "Presolving indicator constraint <%s>.\n", SCIPconsGetName(cons) );
5891 #endif
5892 
5893  /* do nothing if the linear constraint is not active */
5894  if ( ! consdata->linconsactive )
5895  continue;
5896 
5897  assert( consdata->lincons != NULL );
5898  assert( consdata->slackvar != NULL );
5899  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear") == 0 );
5900  assert( SCIPconsIsTransformed(consdata->lincons) );
5901 
5902  /* add implications if not yet done */
5903  if ( ! consdata->implicationadded )
5904  {
5905  int nbnds = 0;
5906  SCIP_CALL( SCIPaddVarImplication(scip, consdata->binvar, TRUE, consdata->slackvar, SCIP_BOUNDTYPE_UPPER, 0.0,
5907  &cutoff, &nbnds) );
5908  *nchgbds += nbnds;
5909 
5910  /* cutoff/infeasible might be true if preprocessing was truncated */
5911  /* note: nbdchgs == 0 is not necessarily true, because preprocessing might be truncated. */
5912  consdata->implicationadded = TRUE;
5913  if ( cutoff )
5914  {
5915  *result = SCIP_CUTOFF;
5916  return SCIP_OKAY;
5917  }
5918  }
5919 
5920  /* check type of slack variable if not yet done */
5921  if ( ! consdata->slacktypechecked )
5922  {
5923  consdata->slacktypechecked = TRUE;
5924  /* check if slack variable can be made implicit integer. */
5925  if ( SCIPvarGetType(consdata->slackvar) == SCIP_VARTYPE_CONTINUOUS )
5926  {
5927  SCIP_Real* vals;
5928  SCIP_VAR** vars;
5929  SCIP_VAR* slackvar;
5930  SCIP_Bool foundslackvar = FALSE;
5931  int nvars;
5932  int j;
5933 
5934  assert( consdata->lincons != NULL );
5935  vars = SCIPgetVarsLinear(scip, consdata->lincons);
5936  vals = SCIPgetValsLinear(scip, consdata->lincons);
5937  nvars = SCIPgetNVarsLinear(scip, consdata->lincons);
5938  slackvar = consdata->slackvar;
5939  assert( slackvar != NULL );
5940 
5941  for (j = 0; j < nvars; ++j)
5942  {
5943  if ( vars[j] == slackvar )
5944  foundslackvar = TRUE;
5945  else
5946  {
5947  if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, vals[j]))
5948  break;
5949  }
5950  }
5951  /* something is strange if the slack variable does not appear in the linear constraint (possibly because it is an artificial constraint) */
5952  if ( j == nvars && foundslackvar )
5953  {
5954  SCIP_Bool infeasible;
5955  SCIP_Real lb;
5956  SCIP_Real ub;
5957 
5958  lb = SCIPvarGetLbGlobal(consdata->slackvar);
5959  ub = SCIPvarGetUbGlobal(consdata->slackvar);
5960  if ( (SCIPisInfinity(scip, -lb) || SCIPisIntegral(scip, lb)) && (SCIPisInfinity(scip, ub) || SCIPisIntegral(scip, ub)) )
5961  {
5962  SCIP_CALL( SCIPchgVarType(scip, consdata->slackvar, SCIP_VARTYPE_IMPLINT, &infeasible) );
5963  /* don't assert feasibility here because the presolver should detect infeasibility */
5964  }
5965  else
5966  {
5967  /* It can happen that the bounds of the slack variable have been changed to be non-integral in
5968  * previous presolving steps. We then might get a problem with tightening the bounds. In this case,
5969  * we just leave the slack variable to be continuous. */
5970  SCIPdebugMsg(scip, "Cannot change type of slack variable (<%s>) to IMPLINT, since global bound is non-integral: (%g, %g).\n",
5971  SCIPvarGetName(consdata->slackvar), SCIPvarGetLbGlobal(consdata->slackvar), SCIPvarGetUbGlobal(consdata->slackvar));
5972  }
5973  }
5974  }
5975  }
5976 
5977  /* perform one presolving round */
5978  SCIP_CALL( presolRoundIndicator(scip, conshdlrdata, cons, consdata,
5979  conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip), &cutoff, &success, ndelconss, nfixedvars) );
5980 
5981  if ( cutoff )
5982  {
5983  *result = SCIP_CUTOFF;
5984  return SCIP_OKAY;
5985  }
5986  if ( success )
5987  *result = SCIP_SUCCESS;
5988  }
5989  }
5990 
5991  /* determine whether other methods have found reductions */
5992  noReductions = nnewfixedvars == 0 && nnewaggrvars == 0 && nnewchgvartypes == 0 && nnewchgbds == 0
5993  && nnewdelconss == 0 && nnewchgcoefs == 0 && nnewchgsides == 0;
5994 
5995  /* add variable upper bounds after bounds are likely to be strengthened */
5996  if ( noReductions && *result != SCIP_SUCCESS && conshdlrdata->addcouplingcons && ! conshdlrdata->addedcouplingcons )
5997  {
5998  int ngen;
5999 
6000  /* create variable upper bounds, possibly removing indicator constraints */
6001  SCIP_CALL( createVarUbs(scip, conshdlrdata, conss, nconss, &ngen) );
6002 
6003  if ( ngen > 0 )
6004  {
6005  *result = SCIP_SUCCESS;
6006  *nupgdconss += ngen;
6007  if ( conshdlrdata->removeindicators )
6008  *ndelconss += ngen;
6009  }
6010  conshdlrdata->addedcouplingcons = TRUE;
6011  }
6012 
6013  SCIPdebug( SCIPdebugMsg(scip, "Presolved %d constraints (fixed %d variables, removed 0 variables, and deleted %d constraints).\n",
6014  nconss, *nfixedvars - oldnfixedvars, *ndelconss - oldndelconss); )
6015 
6016  return SCIP_OKAY; /*lint !e438*/
6017 }
6018 
6019 
6020 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved)
6021  *
6022  * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
6023  * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
6024  * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not inserted.
6025  */
6026 static
6027 SCIP_DECL_CONSINITLP(consInitlpIndicator)
6029  int c;
6030  SCIP_CONSHDLRDATA* conshdlrdata;
6031 
6032  assert( scip != NULL );
6033  assert( conshdlr != NULL );
6034  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6035 
6036  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6037  assert( conshdlrdata != NULL );
6038 
6039  *infeasible = FALSE;
6040 
6041  /* check whether coupling constraints should be added */
6042  if ( ! conshdlrdata->addcoupling )
6043  return SCIP_OKAY;
6044 
6045  /* check whether coupling constraints have been added already */
6046  if ( conshdlrdata->addcouplingcons && conshdlrdata->addedcouplingcons )
6047  return SCIP_OKAY;
6048 
6049  SCIPdebugMsg(scip, "Handle initial rows for %d indicator constraints.\n", nconss);
6050 
6051  /* check each constraint */
6052  for (c = 0; c < nconss && !(*infeasible); ++c)
6053  {
6054  SCIP_CONSDATA* consdata;
6055  SCIP_Real ub;
6056 
6057  assert( conss != NULL );
6058  assert( conss[c] != NULL );
6059  consdata = SCIPconsGetData(conss[c]);
6060  assert( consdata != NULL );
6061 
6062  /* do not add inequalities if there are no linear constraints (no slack variable available) */
6063  if ( ! consdata->linconsactive )
6064  continue;
6065 
6066  /* get upper bound for slack variable in linear constraint */
6067  ub = SCIPvarGetUbGlobal(consdata->slackvar);
6068  assert( ! SCIPisNegative(scip, ub) );
6069 
6070  /* insert corresponding row if helpful and coefficient is not too large */
6071  if ( ub <= conshdlrdata->maxcouplingvalue )
6072  {
6073  char name[50];
6074 
6075 #ifndef NDEBUG
6076  (void) SCIPsnprintf(name, 50, "couple%d", c);
6077 #else
6078  name[0] = '\0';
6079 #endif
6080 
6081  /* add variable upper bound if required */
6082  if ( conshdlrdata->addcouplingcons )
6083  {
6084  SCIP_CONS* cons;
6085 
6086  assert( ! conshdlrdata->addedcouplingcons );
6087 
6088  SCIPdebugMsg(scip, "Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
6089 
6090  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
6091  TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
6092 
6093  SCIP_CALL( SCIPaddCons(scip, cons) );
6094  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
6095  }
6096  else
6097  {
6098  SCIP_ROW* row;
6099 
6100  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, FALSE, FALSE, FALSE) );
6101  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
6102 
6103  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
6104  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
6105  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
6106 
6107  SCIPdebugMsg(scip, "Insert coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
6108 #ifdef SCIP_OUTPUT
6109  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
6110 #endif
6111  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
6112  SCIP_CALL( SCIPreleaseRow(scip, &row));
6113  }
6114  }
6115  }
6116 
6117  return SCIP_OKAY;
6118 }
6119 
6120 
6121 /** separation method of constraint handler for LP solutions */
6122 static
6123 SCIP_DECL_CONSSEPALP(consSepalpIndicator)
6124 { /*lint --e{715}*/
6125  assert( scip != NULL );
6126  assert( conshdlr != NULL );
6127  assert( conss != NULL );
6128  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6129  assert( result != NULL );
6130 
6131  /* perform separation */
6132  SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, NULL, SCIP_TYPE_SEPALP, result) );
6133 
6134  return SCIP_OKAY;
6135 }
6136 
6137 
6138 /** separation method of constraint handler for arbitrary primal solutions */
6139 static
6140 SCIP_DECL_CONSSEPASOL(consSepasolIndicator)
6141 { /*lint --e{715}*/
6142  assert( scip != NULL );
6143  assert( conshdlr != NULL );
6144  assert( conss != NULL );
6145  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6146  assert( result != NULL );
6147 
6148  /* perform separation */
6149  SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, sol, SCIP_TYPE_SEPASOL, result) );
6150 
6151  return SCIP_OKAY;
6152 }
6153 
6154 
6155 /** constraint enforcing method of constraint handler for LP solutions */
6156 static
6157 SCIP_DECL_CONSENFOLP(consEnfolpIndicator)
6158 { /*lint --e{715}*/
6159  SCIP_CONSHDLRDATA* conshdlrdata;
6160 
6161  assert( scip != NULL );
6162  assert( conshdlr != NULL );
6163  assert( conss != NULL );
6164  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6165  assert( result != NULL );
6166 
6167  if ( solinfeasible )
6168  {
6169  *result = SCIP_FEASIBLE;
6170  return SCIP_OKAY;
6171  }
6172 
6173  /* get constraint handler data */
6174  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6175  assert( conshdlrdata != NULL );
6176 
6177  SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, NULL, SCIP_TYPE_ENFOLP, conshdlrdata->genlogicor, result) );
6178 
6179  return SCIP_OKAY;
6180 }
6181 
6182 
6183 /** constraint enforcing method of constraint handler for relaxation solutions */
6184 static
6185 SCIP_DECL_CONSENFORELAX(consEnforelaxIndicator)
6186 { /*lint --e{715}*/
6187  SCIP_CONSHDLRDATA* conshdlrdata;
6188 
6189  assert( scip != NULL );
6190  assert( conshdlr != NULL );
6191  assert( conss != NULL );
6192  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6193  assert( result != NULL );
6194 
6195  if ( solinfeasible )
6196  {
6197  *result = SCIP_FEASIBLE;
6198  return SCIP_OKAY;
6199  }
6200 
6201  /* get constraint handler data */
6202  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6203  assert( conshdlrdata != NULL );
6204 
6205  SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, sol, SCIP_TYPE_ENFORELAX, conshdlrdata->genlogicor, result) );
6206 
6207  return SCIP_OKAY;
6208 }
6209 
6210 
6211 /** constraint enforcing method of constraint handler for pseudo solutions */
6212 static
6213 SCIP_DECL_CONSENFOPS(consEnfopsIndicator)
6214 { /*lint --e{715}*/
6215  assert( scip != NULL );
6216  assert( conshdlr != NULL );
6217  assert( conss != NULL );
6218  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6219  assert( result != NULL );
6220 
6221  if ( solinfeasible )
6222  {
6223  *result = SCIP_FEASIBLE;
6224  return SCIP_OKAY;
6225  }
6226 
6227  if ( objinfeasible )
6228  {
6229  *result = SCIP_DIDNOTRUN;
6230  return SCIP_OKAY;
6231  }
6232 
6233  SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, NULL, SCIP_TYPE_ENFOPS, TRUE, result) );
6234 
6235  return SCIP_OKAY;
6236 }
6237 
6238 
6239 /** feasibility check method of constraint handler for integral solutions */
6240 static
6241 SCIP_DECL_CONSCHECK(consCheckIndicator)
6242 { /*lint --e{715}*/
6243  SCIP_SOL* trysol = NULL;
6244  SCIP_CONSHDLRDATA* conshdlrdata;
6245  SCIP_Bool someLinconsNotActive;
6246  SCIP_Bool changedSol;
6247  int c;
6248 
6249  assert( scip != NULL );
6250  assert( conshdlr != NULL );
6251  assert( conss != NULL );
6252  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6253  assert( result != NULL );
6254 
6255  SCIPdebugMsg(scip, "Checking %d indicator constraints <%s>.\n", nconss, SCIPconshdlrGetName(conshdlr) );
6256 
6257  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6258  assert( conshdlrdata != NULL );
6259 
6260  /* try to repair solution below, if it makes sense (will send solution to trysol heuristic in any case (see below) */
6261  if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM && SCIPgetStage(scip) < SCIP_STAGE_SOLVED && conshdlrdata->trysolutions && conshdlrdata->heurtrysol != NULL )
6262  {
6263  SCIP_CALL( SCIPcreateSolCopy(scip, &trysol, sol) );
6264  assert( trysol != NULL );
6265  }
6266 
6267  /* check each constraint */
6268  *result = SCIP_FEASIBLE;
6269  changedSol = FALSE;
6270  someLinconsNotActive = FALSE;
6271  for (c = 0; c < nconss; ++c)
6272  {
6273  SCIP_CONSDATA* consdata;
6274 
6275  assert( conss[c] != NULL );
6276  consdata = SCIPconsGetData(conss[c]);
6277  assert( consdata != NULL );
6278  assert( consdata->binvar != NULL );
6279 
6280  /* if the linear constraint has not been generated, we do nothing */
6281  if ( ! consdata->linconsactive )
6282  {
6283  someLinconsNotActive = TRUE;
6284  continue;
6285  }
6286 
6287  assert( consdata->slackvar != NULL );
6288  /* if printreason is true it can happen that non-integral solutions are checked */
6289  assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
6290 
6291  /* if constraint is infeasible */
6292  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) &&
6293  ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) )
6294  {
6295  SCIP_Real absviol = REALABS(SCIPgetSolVal(scip, sol, consdata->slackvar));
6296  SCIP_Real relviol = SCIPrelDiff(absviol, 0.0);
6297  if( sol != NULL )
6298  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
6299 
6300  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
6301  *result = SCIP_INFEASIBLE;
6302 
6303  if ( printreason )
6304  {
6305  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
6306  SCIPinfoMessage(scip, NULL, ";\nviolation: <%s> = %g and <%s> = %.15g\n",
6307  SCIPvarGetName(consdata->binvar), SCIPgetSolVal(scip, sol, consdata->binvar),
6308  SCIPvarGetName(consdata->slackvar), SCIPgetSolVal(scip, sol, consdata->slackvar));
6309  }
6310 
6311  /* try to make solution feasible if it makes sense - otherwise exit */
6312  if ( trysol != NULL )
6313  {
6314  SCIP_Bool changed;
6315  SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
6316  changedSol = changedSol || changed;
6317  }
6318  else
6319  {
6320  SCIPdebugMsg(scip, "Indicator constraint %s is not feasible.\n", SCIPconsGetName(conss[c]));
6321 
6322  if( !completely )
6323  return SCIP_OKAY;
6324  }
6325  }
6326  else
6327  {
6328  if ( trysol != NULL )
6329  {
6330  SCIP_Bool changed;
6331  SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
6332  changedSol = changedSol || changed;
6333  }
6334  }
6335  }
6336 
6337  /* if some linear constraints are not active, we need to check feasibility via the alternative polyhedron */
6338  if ( someLinconsNotActive )
6339  {
6340  SCIP_LPI* lp;
6341  SCIP_Bool infeasible;
6342  SCIP_Bool error;
6343  SCIP_Bool* S;
6344 
6345  lp = conshdlrdata->altlp;
6346  assert( conshdlrdata->sepaalternativelp );
6347 
6348  /* the check maybe called before we have build the alternative polyhedron -> return SCIP_INFEASIBLE */
6349  if ( lp != NULL )
6350  {
6351 #ifndef NDEBUG
6352  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
6353 #endif
6354 
6355  /* change coefficients of bounds in alternative LP */
6356  if ( conshdlrdata->updatebounds )
6357  {
6358  SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
6359  }
6360 
6361  /* scale first row if necessary */
6362  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
6363 
6364  /* set objective function to current solution */
6365  SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
6366 
6367  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
6368 
6369  /* set up variables fixed to 1 */
6370  for (c = 0; c < nconss; ++c)
6371  {
6372  SCIP_CONSDATA* consdata;
6373 
6374  assert( conss[c] != NULL );
6375  consdata = SCIPconsGetData(conss[c]);
6376  assert( consdata != NULL );
6377 
6378  /* if printreason is true it can happen that non-integral solutions are checked */
6379  assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
6380  if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
6381  S[c] = TRUE;
6382  else
6383  S[c] = FALSE;
6384  }
6385 
6386  /* fix the variables in S */
6387  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
6388 
6389  /* check feasibility */
6391  SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, TRUE, &infeasible, &error) );
6393 
6394  if ( error )
6395  return SCIP_LPERROR;
6396 
6397  if ( ! infeasible )
6398  *result = SCIP_INFEASIBLE;
6399 
6400  /* reset bounds */
6401  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
6402 
6403 #ifndef NDEBUG
6404  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
6405 #endif
6406 
6407  SCIPfreeBufferArray(scip, &S);
6408  }
6409  else
6410  *result = SCIP_INFEASIBLE;
6411  }
6412  else
6413  {
6414  /* tell heur_trysol about solution - it will pass it to SCIP */
6415  if ( trysol != NULL && changedSol )
6416  {
6417  assert( conshdlrdata->heurtrysol != NULL );
6418  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->heurtrysol, trysol) );
6419  }
6420  }
6421 
6422  if ( trysol != NULL )
6423  SCIP_CALL( SCIPfreeSol(scip, &trysol) );
6424 
6425  if ( *result == SCIP_INFEASIBLE )
6426  {
6427  SCIPdebugMsg(scip, "Indicator constraints are not feasible.\n");
6428  return SCIP_OKAY;
6429  }
6430 
6431  /* at this point we are feasible */
6432  SCIPdebugMsg(scip, "Indicator constraints are feasible.\n");
6433 
6434  return SCIP_OKAY;
6435 }
6436 
6437 
6438 /** domain propagation method of constraint handler */
6439 static
6440 SCIP_DECL_CONSPROP(consPropIndicator)
6441 { /*lint --e{715}*/
6442  SCIP_CONSHDLRDATA* conshdlrdata;
6443  int ngen;
6444  int c;
6445 
6446  assert( scip != NULL );
6447  assert( conshdlr != NULL );
6448  assert( conss != NULL );
6449  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6450  assert( result != NULL );
6451  *result = SCIP_DIDNOTRUN;
6452 
6453  assert( SCIPisTransformed(scip) );
6454 
6455  SCIPdebugMsg(scip, "Start propagation of constraint handler <%s>.\n", SCIPconshdlrGetName(conshdlr));
6456  ngen = 0;
6457 
6458  /* get constraint handler data */
6459  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6460  assert( conshdlrdata != NULL );
6461 
6462  /* check each constraint */
6463  for (c = 0; c < nconss; ++c)
6464  {
6465  SCIP_CONS* cons;
6466  SCIP_CONSDATA* consdata;
6467  SCIP_Bool cutoff;
6468  int cnt;
6469 
6470  *result = SCIP_DIDNOTFIND;
6471  assert( conss[c] != NULL );
6472  cons = conss[c];
6473  consdata = SCIPconsGetData(cons);
6474  assert( consdata != NULL );
6475 
6476 #ifdef SCIP_MORE_DEBUG
6477  SCIPdebugMsg(scip, "Propagating indicator constraint <%s>.\n", SCIPconsGetName(cons) );
6478 #endif
6479 
6480  *result = SCIP_DIDNOTFIND;
6481 
6482  SCIP_CALL( propIndicator(scip, cons, consdata, conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip),
6483  conshdlrdata->addopposite, &cutoff, &cnt) );
6484 
6485  if ( cutoff )
6486  {
6487  *result = SCIP_CUTOFF;
6488  return SCIP_OKAY;
6489  }
6490  ngen += cnt;
6491  }
6492  SCIPdebugMsg(scip, "Propagated %d domains in constraint handler <%s>.\n", ngen, SCIPconshdlrGetName(conshdlr));
6493  if ( ngen > 0 )
6494  *result = SCIP_REDUCEDDOM;
6495 
6496  return SCIP_OKAY;
6497 }
6498 
6499 
6500 /** propagation conflict resolving method of constraint handler
6501  *
6502  * We check which bound changes were the reason for infeasibility. We use that @a inferinfo is 0 if
6503  * the binary variable has bounds that fix it to be nonzero (these bounds are the reason). Likewise
6504  * @a inferinfo is 1 if the slack variable has bounds that fix it to be nonzero.
6505  */
6506 static
6507 SCIP_DECL_CONSRESPROP(consRespropIndicator)
6508 { /*lint --e{715}*/
6509  SCIP_CONSDATA* consdata;
6510 
6511  assert( scip != NULL );
6512  assert( cons != NULL );
6513  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6514  assert( infervar != NULL );
6515  assert( bdchgidx != NULL );
6516  assert( result != NULL );
6517 
6518  *result = SCIP_DIDNOTFIND;
6519  SCIPdebugMsg(scip, "Propagation resolution method of indicator constraint <%s>.\n", SCIPconsGetName(cons));
6520 
6521  consdata = SCIPconsGetData(cons);
6522  assert( consdata != NULL );
6523  assert( inferinfo == 0 || inferinfo == 1 || inferinfo == 2 );
6524  assert( consdata->linconsactive );
6525 
6526  /* if the binary variable was the reason */
6527  if ( inferinfo == 0 )
6528  {
6529  assert( SCIPgetVarLbAtIndex(scip, consdata->binvar, bdchgidx, FALSE) > 0.5 );
6530  assert( infervar != consdata->binvar );
6531 
6532  SCIP_CALL( SCIPaddConflictLb(scip, consdata->binvar, bdchgidx) );
6533  }
6534  else if ( inferinfo == 1 )
6535  {
6536  /* if the slack variable fixed to a positive value was the reason */
6537  assert( infervar != consdata->slackvar );
6538  /* Use a weaker comparison to SCIPvarGetLbAtIndex here (i.e., SCIPisPositive instead of SCIPisFeasPositive),
6539  * because SCIPvarGetLbAtIndex might differ from the local bound at time bdchgidx by epsilon. */
6540  assert( SCIPisPositive(scip, SCIPgetVarLbAtIndex(scip, consdata->slackvar, bdchgidx, FALSE)) );
6541  SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, bdchgidx) );
6542  }
6543  else
6544  {
6545  assert( inferinfo == 2 );
6546  assert( SCIPisFeasZero(scip, SCIPgetVarUbAtIndex(scip, consdata->slackvar, bdchgidx, FALSE)) );
6547  assert( SCIPconshdlrGetData(conshdlr)->dualreductions && SCIPallowStrongDualReds(scip) && SCIPallowWeakDualReds(scip) );
6548  SCIP_CALL( SCIPaddConflictUb(scip, consdata->slackvar, bdchgidx) );
6549  }
6550  *result = SCIP_SUCCESS;
6551 
6552  return SCIP_OKAY;
6553 }
6554 
6555 
6556 /** variable rounding lock method of constraint handler
6557  *
6558  * The up-rounding of the binary and slack variable may violate the constraint. If the linear
6559  * constraint is not active, we lock all variables in the depending constraint - otherwise they
6560  * will be fixed by dual presolving methods.
6561  */
6562 static
6563 SCIP_DECL_CONSLOCK(consLockIndicator)
6565  SCIP_CONSDATA* consdata;
6566 
6567  assert( scip != NULL );
6568  assert( conshdlr != NULL );
6569  assert( cons != NULL );
6570  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6571  consdata = SCIPconsGetData(cons);
6572  assert( consdata != NULL );
6573  assert( consdata->binvar != NULL );
6574 
6575 #ifdef SCIP_MORE_DEBUG
6576  SCIPdebugMsg(scip, "%socking constraint <%s>.\n", (nlocksneg < 0) || (nlockspos < 0) ? "Unl" : "L", SCIPconsGetName(cons));
6577 #endif
6578 
6579  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->binvar, locktype, nlocksneg, nlockspos) );
6580 
6581  if ( consdata->linconsactive )
6582  {
6583  assert( consdata->slackvar != NULL );
6584 
6585  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->slackvar, locktype, nlocksneg, nlockspos) );
6586  }
6587  else
6588  {
6589  SCIP_VAR** linvars;
6590  SCIP_Real* linvals;
6591  SCIP_Bool haslhs;
6592  SCIP_Bool hasrhs;
6593  int nlinvars;
6594  int j;
6595 
6596  assert( consdata->lincons != NULL );
6597  assert( consdata->slackvar == NULL );
6598 
6599  nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
6600  linvars = SCIPgetVarsLinear(scip, consdata->lincons);
6601  linvals = SCIPgetValsLinear(scip, consdata->lincons);
6602  haslhs = ! SCIPisInfinity(scip, REALABS(SCIPgetLhsLinear(scip, consdata->lincons)));
6603  hasrhs = ! SCIPisInfinity(scip, REALABS(SCIPgetRhsLinear(scip, consdata->lincons)));
6604 
6605  for (j = 0; j < nlinvars; ++j)
6606  {
6607  assert( ! SCIPisZero(scip, linvals[j]) );
6608  if ( SCIPisPositive(scip, linvals[j]) )
6609  {
6610  if ( haslhs )
6611  {
6612  SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlockspos, nlocksneg) );
6613  }
6614  if ( hasrhs )
6615  {
6616  SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlocksneg, nlockspos) );
6617  }
6618  }
6619  else
6620  {
6621  if ( haslhs )
6622  {
6623  SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlocksneg, nlockspos) );
6624  }
6625  if ( hasrhs )
6626  {
6627  SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlockspos, nlocksneg) );
6628  }
6629  }
6630  }
6631  }
6632 
6633  return SCIP_OKAY;
6634 }
6635 
6636 
6637 /** constraint display method of constraint handler */
6638 static
6639 SCIP_DECL_CONSPRINT(consPrintIndicator)
6641  SCIP_CONSDATA* consdata;
6642  SCIP_VAR* binvar;
6643  int rhs;
6644 
6645  assert( scip != NULL );
6646  assert( conshdlr != NULL );
6647  assert( cons != NULL );
6648  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6649 
6650  consdata = SCIPconsGetData(cons);
6651  assert( consdata != NULL );
6652  assert( consdata->binvar != NULL );
6653 
6654  binvar = consdata->binvar;
6655  rhs = 1;
6656  if ( SCIPvarGetStatus(binvar) == SCIP_VARSTATUS_NEGATED )
6657  {
6658  rhs = 0;
6659  binvar = SCIPvarGetNegatedVar(binvar);
6660  }
6661  SCIPinfoMessage(scip, file, "<%s> = %d", SCIPvarGetName(binvar), rhs);
6662 
6663  assert( consdata->slackvar != NULL );
6664  assert( consdata->lincons != NULL );
6665  SCIPinfoMessage(scip, file, " -> <%s> = 0", SCIPvarGetName(consdata->slackvar));
6666  SCIPinfoMessage(scip, file, " (<%s>)", SCIPconsGetName(consdata->lincons));
6667 
6668  return SCIP_OKAY;
6669 }
6670 
6671 
6672 /** constraint copying method of constraint handler */
6673 static
6674 SCIP_DECL_CONSCOPY(consCopyIndicator)
6675 { /*lint --e{715}*/
6676  SCIP_CONSDATA* sourceconsdata;
6677  SCIP_CONS* targetlincons = NULL;
6678  SCIP_VAR* targetbinvar = NULL;
6679  SCIP_VAR* targetslackvar = NULL;
6680  SCIP_CONS* sourcelincons;
6681  SCIP_CONSHDLR* conshdlrlinear;
6682  const char* consname;
6683 
6684  assert( scip != NULL );
6685  assert( sourcescip != NULL );
6686  assert( sourcecons != NULL );
6687  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 );
6688 
6689  *valid = TRUE;
6690 
6691  if ( name != NULL )
6692  consname = name;
6693  else
6694  consname = SCIPconsGetName(sourcecons);
6695 
6696 #ifdef SCIP_MORE_DEBUG
6697  SCIPdebugMsg(scip, "Copying indicator constraint <%s> ...\n", consname);
6698 #endif
6699 
6700  if ( modifiable )
6701  {
6702  SCIPwarningMessage(scip, "cannot create modifiable indicator constraint when trying to copy constraint <%s>,\n", SCIPconsGetName(sourcecons));
6703  *valid = FALSE;
6704  return SCIP_OKAY;
6705  }
6706 
6707  sourceconsdata = SCIPconsGetData(sourcecons);
6708  assert( sourceconsdata != NULL );
6709 
6710  /* get linear constraint */
6711  sourcelincons = sourceconsdata->lincons;
6712 
6713  /* if the constraint has been deleted -> create empty constraint (multi-aggregation might still contain slack variable, so indicator is valid) */
6714  if ( SCIPconsIsDeleted(sourcelincons) )
6715  {
6716  SCIPdebugMsg(scip, "Linear constraint <%s> deleted! Create empty linear constraint.\n", SCIPconsGetName(sourceconsdata->lincons));
6717 
6718  SCIP_CALL( SCIPcreateConsLinear(scip, &targetlincons, "dummy", 0, NULL, NULL, 0.0, SCIPinfinity(scip),
6720  SCIP_CALL( SCIPaddCons(scip, targetlincons) );
6721  }
6722  else
6723  {
6724  /* get copied version of linear constraint */
6725  assert( sourcelincons != NULL );
6726  conshdlrlinear = SCIPfindConshdlr(sourcescip, "linear");
6727  assert( conshdlrlinear != NULL );
6728 
6729  /* if copying scip after transforming the original instance before presolving, we need to correct the linear
6730  * constraint pointer */
6731  if ( SCIPisTransformed(sourcescip) && ! SCIPconsIsTransformed(sourcelincons) )
6732  {
6733  SCIP_CONS* translincons;
6734 
6735  /* adjust the linear constraint in the original constraint (no need to release translincons) */
6736  SCIP_CALL( SCIPgetTransformedCons(sourcescip, sourcelincons, &translincons) );
6737  assert( translincons != NULL );
6738  SCIP_CALL( SCIPreleaseCons(sourcescip, &sourceconsdata->lincons) );
6739  SCIP_CALL( SCIPcaptureCons(sourcescip, translincons) );
6740  sourceconsdata->lincons = translincons;
6741  sourcelincons = translincons;
6742  }
6743 
6744  SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, sourcelincons, &targetlincons, conshdlrlinear, varmap, consmap, SCIPconsGetName(sourcelincons),
6745  SCIPconsIsInitial(sourcelincons), SCIPconsIsSeparated(sourcelincons), SCIPconsIsEnforced(sourcelincons), SCIPconsIsChecked(sourcelincons),
6746  SCIPconsIsPropagated(sourcelincons), SCIPconsIsLocal(sourcelincons), SCIPconsIsModifiable(sourcelincons), SCIPconsIsDynamic(sourcelincons),
6747  SCIPconsIsRemovable(sourcelincons), SCIPconsIsStickingAtNode(sourcelincons), global, valid) );
6748  }
6749 
6750  /* find copied variable corresponding to binvar */
6751  if ( *valid )
6752  {
6753  SCIP_VAR* sourcebinvar;
6754 
6755  sourcebinvar = sourceconsdata->binvar;
6756  assert( sourcebinvar != NULL );
6757 
6758  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcebinvar, &targetbinvar, varmap, consmap, global, valid) );
6759  }
6760 
6761  /* find copied variable corresponding to slackvar */
6762  if ( *valid )
6763  {
6764  SCIP_VAR* sourceslackvar;
6765 
6766  sourceslackvar = sourceconsdata->slackvar;
6767  assert( sourceslackvar != NULL );
6768 
6769  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourceslackvar, &targetslackvar, varmap, consmap, global, valid) );
6770  }
6771 
6772  /* create indicator constraint */
6773  if ( *valid )
6774  {
6775  assert( targetlincons != NULL );
6776  assert( targetbinvar != NULL );
6777  assert( targetslackvar != NULL );
6778 
6779  /* creates indicator constraint (and captures the linear constraint) */
6780  /* Note that the copied constraint has activeone = TRUE, since the target binary variable already was negated if needed. */
6781  SCIP_CALL( SCIPcreateConsIndicatorGenericLinCons(scip, cons, consname, targetbinvar, targetlincons, targetslackvar, TRUE,
6782  initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
6783  }
6784  else
6785  {
6786  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "could not copy linear constraint <%s>\n", SCIPconsGetName(sourcelincons));
6787  }
6788 
6789  /* release copied linear constraint */
6790  if ( targetlincons != NULL )
6791  {
6792  SCIP_CALL( SCIPreleaseCons(scip, &targetlincons) );
6793  }
6794 
6795  return SCIP_OKAY;
6796 }
6797 
6798 
6799 /** constraint parsing method of constraint handler */
6800 static
6801 SCIP_DECL_CONSPARSE(consParseIndicator)
6802 { /*lint --e{715}*/
6803  char binvarname[1024];
6804  char slackvarname[1024];
6805  char linconsname[1024];
6806  SCIP_VAR* binvar;
6807  SCIP_VAR* slackvar;
6808  SCIP_CONS* lincons;
6809  int zeroone;
6810  int nargs;
6811 
6812  *success = TRUE;
6813 
6814  /* read indicator constraint */
6815  /* coverity[secure_coding] */
6816  nargs = sscanf(str, " <%1023[^>]> = %d -> <%1023[^>]> = 0 (<%1023[^>]>)", binvarname, &zeroone, slackvarname, linconsname);
6817 
6818  /* downward compatible: accept missing linear constraint at end */
6819  if ( nargs != 3 && nargs != 4 )
6820  {
6821  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0 (<lincons>).\n%s\n", str);
6822  *success = FALSE;
6823  return SCIP_OKAY;
6824  }
6825 
6826  if ( zeroone != 0 && zeroone != 1 )
6827  {
6828  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0.\n%s\n", str);
6829  *success = FALSE;
6830  return SCIP_OKAY;
6831  }
6832 
6833  /* get binary variable */
6834  binvar = SCIPfindVar(scip, binvarname);
6835  if ( binvar == NULL )
6836  {
6837  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", binvarname);
6838  *success = FALSE;
6839  return SCIP_OKAY;
6840  }
6841  /* check whether we need the complemented variable */
6842  if ( zeroone == 0 )
6843  SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
6844 
6845  /* get slack variable */
6846  slackvar = SCIPfindVar(scip, slackvarname);
6847  if ( slackvar == NULL )
6848  {
6849  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", slackvarname);
6850  *success = FALSE;
6851  return SCIP_OKAY;
6852  }
6853 
6854  /* determine linear constraint */
6855  if ( nargs == 4 )
6856  {
6857  lincons = SCIPfindCons(scip, linconsname);
6858  if ( lincons == NULL )
6859  {
6860  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown constraint <%s>\n", linconsname);
6861  *success = FALSE;
6862  return SCIP_OKAY;
6863  }
6864  if ( strncmp(SCIPconshdlrGetName(SCIPconsGetHdlr(lincons)), "linear", 6) != 0 )
6865  {
6866  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "constraint <%s> is not linear\n", linconsname);
6867  *success = FALSE;
6868  return SCIP_OKAY;
6869  }
6870  }
6871  else
6872  {
6873  const char* posstr;
6874 
6875  /* for backward compability try to determine name of linear constraint from variables names */
6876  assert( nargs == 3 );
6877 
6878  /* find matching linear constraint */
6879  posstr = strstr(slackvarname, "indslack");
6880  if ( posstr == NULL )
6881  {
6882  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "strange slack variable name: <%s>\n", slackvarname);
6883  *success = FALSE;
6884  return SCIP_OKAY;
6885  }
6886 
6887  /* overwrite binvarname: set up name for linear constraint */
6888  (void) SCIPsnprintf(binvarname, 1023, "indlin%s", posstr+8);
6889 
6890  lincons = SCIPfindCons(scip, binvarname);
6891  if ( lincons == NULL )
6892  {
6893  /* if not found - check without indlin */
6894  (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+9);
6895  lincons = SCIPfindCons(scip, binvarname);
6896 
6897  if ( lincons == NULL )
6898  {
6899  /* if not found - check without indrhs or indlhs */
6900  (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+16);
6901  lincons = SCIPfindCons(scip, binvarname);
6902 
6903  if( lincons == NULL )
6904  {
6905  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: unknown linear constraint <indlin%s>, <%s> or <%s>.\n",
6906  name, posstr+8, posstr+9, posstr+16);
6907  *success = FALSE;
6908  return SCIP_OKAY;
6909  }
6910  }
6911  }
6912  }
6913  assert( lincons != NULL );
6914 
6915  /* check correct linear constraint */
6916  if ( ! SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, lincons)) && ! SCIPisInfinity(scip, SCIPgetRhsLinear(scip, lincons)) )
6917  {
6918  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: linear constraint is ranged or equation.\n", name);
6919  *success = FALSE;
6920  return SCIP_OKAY;
6921  }
6922 
6923  /* create indicator constraint */
6924  SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
6925  initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
6926 
6927  return SCIP_OKAY;
6928 }
6929 
6930 
6931 /** constraint enabling notification method of constraint handler */
6932 static
6933 SCIP_DECL_CONSENABLE(consEnableIndicator)
6935  SCIP_CONSHDLRDATA* conshdlrdata;
6936  SCIP_CONSDATA* consdata;
6937 
6938  assert( scip != NULL );
6939  assert( conshdlr != NULL );
6940  assert( cons != NULL );
6941  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6942 
6943 #ifdef SCIP_MORE_DEBUG
6944  SCIPdebugMsg(scip, "Enabling constraint <%s>.\n", SCIPconsGetName(cons));
6945 #endif
6946 
6947  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6948  assert( conshdlrdata != NULL );
6949 
6950  consdata = SCIPconsGetData(cons);
6951  assert( consdata != NULL );
6952 
6953  if ( conshdlrdata->altlp != NULL )
6954  {
6955  assert( conshdlrdata->sepaalternativelp );
6956 
6957  if ( consdata->colindex >= 0 )
6958  {
6959  SCIP_CALL( unfixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
6960  }
6961  }
6962 
6963  return SCIP_OKAY;
6964 }
6965 
6966 
6967 /** constraint disabling notification method of constraint handler */
6968 static
6969 SCIP_DECL_CONSDISABLE(consDisableIndicator)
6971  SCIP_CONSHDLRDATA* conshdlrdata;
6972 
6973  assert( scip != NULL );
6974  assert( conshdlr != NULL );
6975  assert( cons != NULL );
6976  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6977 
6978 #ifdef SCIP_MORE_DEBUG
6979  SCIPdebugMsg(scip, "Disabling constraint <%s>.\n", SCIPconsGetName(cons));
6980 #endif
6981 
6982  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6983  assert( conshdlrdata != NULL );
6984 
6985  if ( conshdlrdata->altlp != NULL )
6986  {
6987  SCIP_CONSDATA* consdata;
6988 
6989  consdata = SCIPconsGetData(cons);
6990  assert( consdata != NULL );
6991  assert( conshdlrdata->sepaalternativelp );
6992 
6993  if ( consdata->colindex >= 0 )
6994  {
6995  SCIP_CALL( fixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
6996  }
6997  }
6998 
6999  return SCIP_OKAY;
7000 }
7001 
7002 
7003 /** constraint method of constraint handler which returns the variables (if possible) */
7004 static
7005 SCIP_DECL_CONSGETVARS(consGetVarsIndicator)
7006 { /*lint --e{715}*/
7007  SCIP_CONSDATA* consdata;
7008  int nvars = 0;
7009 
7010  assert( scip != NULL );
7011  assert( cons != NULL );
7012  assert( vars != NULL );
7013  assert( success != NULL );
7014 
7015  if ( varssize < 0 )
7016  return SCIP_INVALIDDATA;
7017  assert( varssize >= 0 );
7018 
7019  (*success) = TRUE;
7020 
7021  /* if indicator constraint is already deleted */
7022  if ( SCIPconsIsDeleted(cons) )
7023  return SCIP_OKAY;
7024 
7025  consdata = SCIPconsGetData(cons);
7026  assert( consdata != NULL );
7027  assert( consdata->lincons != NULL );
7028 
7029  if ( consdata->binvar != NULL )
7030  {
7031  assert( varssize > 0 );
7032  vars[nvars++] = consdata->binvar;
7033  }
7034  if ( consdata->slackvar != NULL )
7035  {
7036  assert( varssize > nvars );
7037  vars[nvars++] = consdata->slackvar;
7038  }
7039 
7040  /* if linear constraint of indicator is already deleted */
7041  if ( SCIPconsIsDeleted(consdata->lincons) )
7042  return SCIP_OKAY;
7043 
7044  SCIP_CALL( SCIPgetConsVars(scip, consdata->lincons, &(vars[nvars]), varssize - nvars, success) );
7045 
7046  return SCIP_OKAY;
7047 }
7048 
7049 
7050 /** constraint method of constraint handler which returns the number of variables (if possible) */
7051 static
7052 SCIP_DECL_CONSGETNVARS(consGetNVarsIndicator)
7053 { /*lint --e{715}*/
7054  SCIP_CONSDATA* consdata;
7055  int nlinvars;
7056 
7057  assert( scip != NULL );
7058  assert( cons != NULL );
7059  assert( nvars != NULL );
7060  assert( success != NULL );
7061 
7062  (*success) = TRUE;
7063  *nvars = 0;
7064 
7065  /* if indicator constraint is already deleted */
7066  if ( SCIPconsIsDeleted(cons) )
7067  return SCIP_OKAY;
7068 
7069  consdata = SCIPconsGetData(cons);
7070  assert( consdata != NULL );
7071  assert( consdata->lincons != NULL );
7072 
7073  if ( consdata->binvar != NULL )
7074  ++(*nvars);
7075  if ( consdata->slackvar != NULL )
7076  ++(*nvars);
7077 
7078  /* if linear constraint of indicator is already deleted */
7079  if ( SCIPconsIsDeleted(consdata->lincons) )
7080  return SCIP_OKAY;
7081 
7082  SCIP_CALL( SCIPgetConsNVars(scip, consdata->lincons, &nlinvars, success) );
7083 
7084  if ( *success )
7085  {
7086  assert( nlinvars >= 0 );
7087  *nvars += nlinvars;
7088  }
7089 
7090  return SCIP_OKAY;
7091 }
7092 
7093 
7094 /** constraint handler method to suggest dive bound changes during the generic diving algorithm */
7095 static
7096 SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsIndicator)
7098  SCIP_CONS** indconss;
7099  int nindconss;
7100  int c;
7101  SCIP_VAR* bestvar = NULL;
7102  SCIP_Bool bestvarroundup = FALSE;
7103  SCIP_Real bestscore = SCIP_REAL_MIN;
7104 
7105  assert(scip != NULL);
7106  assert(conshdlr != NULL);
7107  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7108  assert(diveset != NULL);
7109  assert(success != NULL);
7110  assert(infeasible != NULL);
7111 
7112  *success = FALSE;
7113  *infeasible = FALSE;
7114 
7115  indconss = SCIPconshdlrGetConss(conshdlr);
7116  nindconss = SCIPconshdlrGetNConss(conshdlr);
7117 
7118  /* loop over indicator constraints and score indicator variables with already integral solution value */
7119  for (c = 0; c < nindconss; ++c)
7120  {
7121  /* check whether constraint is violated */
7122  if( SCIPisViolatedIndicator(scip, indconss[c], sol) )
7123  {
7124  SCIP_VAR* binvar;
7125  SCIP_Real solval;
7126 
7127  binvar = SCIPgetBinaryVarIndicator(indconss[c]);
7128  solval = SCIPgetSolVal(scip, sol, binvar);
7129 
7130  /* we only treat indicator variables with integral solution values that are not yet fixed */
7131  if( SCIPisFeasIntegral(scip, solval) && SCIPvarGetLbLocal(binvar) < SCIPvarGetUbLocal(binvar) - 0.5 )
7132  {
7133  SCIP_Real score;
7134  SCIP_Bool roundup;
7135 
7136  SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_INTEGRALITY, binvar, solval, 0.0,
7137  &score, &roundup) );
7138 
7139  /* best candidate maximizes the score */
7140  if( score > bestscore )
7141  {
7142  bestscore = score;
7143  *success = TRUE;
7144  bestvar = binvar;
7145  bestvarroundup = roundup;
7146  }
7147  }
7148  }
7149  }
7150 
7151  assert(! *success || bestvar != NULL);
7152 
7153  if( *success )
7154  {
7155  /* if the diving score voted for fixing the best variable to 1.0, we add this as the preferred bound change */
7156  SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_UPWARDS, 1.0, bestvarroundup) );
7157  SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_DOWNWARDS, 0.0, ! bestvarroundup) );
7158  }
7159 
7160  return SCIP_OKAY;
7161 }
7162 
7163 /* ---------------- Constraint specific interface methods ---------------- */
7164 
7165 /** creates the handler for indicator constraints and includes it in SCIP */
7167  SCIP* scip /**< SCIP data structure */
7168  )
7169 {
7170  SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
7171  SCIP_CONFLICTHDLR* conflicthdlr;
7172  SCIP_CONSHDLRDATA* conshdlrdata;
7173  SCIP_CONSHDLR* conshdlr;
7174 
7175  /* create constraint handler data (used in conflicthdlrdata) */
7176  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
7177 
7178  /* create event handler for bound change events */
7179  conshdlrdata->eventhdlrbound = NULL;
7180  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlrbound), EVENTHDLR_BOUND_NAME, EVENTHDLR_BOUND_DESC,
7181  eventExecIndicatorBound, NULL) );
7182  assert(conshdlrdata->eventhdlrbound != NULL);
7183 
7184  /* create event handler for restart events */
7185  conshdlrdata->eventhdlrrestart = NULL;
7186  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlrrestart), EVENTHDLR_RESTART_NAME, EVENTHDLR_RESTART_DESC,
7187  eventExecIndicatorRestart, NULL) );
7188  assert( conshdlrdata->eventhdlrrestart != NULL );
7189 
7190  conshdlrdata->heurtrysol = NULL;
7191  conshdlrdata->sepaalternativelp = DEFAULT_SEPAALTERNATIVELP;
7192  conshdlrdata->nolinconscont = DEFAULT_NOLINCONSCONT;
7193  conshdlrdata->forcerestart = DEFAULT_FORCERESTART;
7194  conshdlrdata->binvarhash = NULL;
7195 
7196  /* initialize constraint handler data */
7197  initConshdlrData(scip, conshdlrdata);
7198 
7199  /* the following three variables cannot be initialized in the above method, because initConshdlrData() is also called
7200  * in the CONSINIT callback, but these variables might be used even before the is ccallback is called, so we would
7201  * lose the data added before calling this callback */
7202  conshdlrdata->addlincons = NULL;
7203  conshdlrdata->naddlincons = 0;
7204  conshdlrdata->maxaddlincons = 0;
7205 
7206  /* include constraint handler */
7209  consEnfolpIndicator, consEnfopsIndicator, consCheckIndicator, consLockIndicator,
7210  conshdlrdata) );
7211 
7212  assert( conshdlr != NULL );
7213 
7214  /* set non-fundamental callbacks via specific setter functions */
7215  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyIndicator, consCopyIndicator) );
7216  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteIndicator) );
7217  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableIndicator) );
7218  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableIndicator) );
7219  SCIP_CALL( SCIPsetConshdlrGetDiveBdChgs(scip, conshdlr, consGetDiveBdChgsIndicator) );
7220  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitIndicator) );
7221  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolIndicator) );
7222  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeIndicator) );
7223  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsIndicator) );
7224  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsIndicator) );
7225  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitIndicator) );
7226  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreIndicator) );
7227  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolIndicator) );
7228  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpIndicator) );
7229  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseIndicator) );
7230  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolIndicator, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
7231  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintIndicator) );
7232  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropIndicator, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
7234  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropIndicator) );
7235  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpIndicator, consSepasolIndicator, CONSHDLR_SEPAFREQ,
7237  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransIndicator) );
7238  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxIndicator) );
7239 
7240  /* add upgrading method */
7241  if ( SCIPfindConshdlr(scip, "linear") != NULL )
7242  {
7243  /* include the linear constraint upgrade in the linear constraint handler */
7244  SCIP_CALL( SCIPincludeLinconsUpgrade(scip, linconsUpgdIndicator, LINCONSUPGD_PRIORITY, CONSHDLR_NAME) );
7245  }
7246 
7247  /* create conflict handler data */
7248  SCIP_CALL( SCIPallocBlockMemory(scip, &conflicthdlrdata) );
7249  conflicthdlrdata->conshdlrdata = conshdlrdata;
7250  conflicthdlrdata->conshdlr = conshdlr;
7251  assert( conflicthdlrdata->conshdlr != NULL );
7252 
7253  /* create conflict handler for indicator constraints */
7255  conflictExecIndicator, conflicthdlrdata) );
7256 
7257  SCIP_CALL( SCIPsetConflicthdlrFree(scip, conflicthdlr, conflictFreeIndicator) );
7258 
7259  /* add indicator constraint handler parameters */
7261  "constraints/indicator/branchindicators",
7262  "Branch on indicator constraints in enforcing?",
7263  &conshdlrdata->branchindicators, TRUE, DEFAULT_BRANCHINDICATORS, NULL, NULL) );
7264 
7266  "constraints/indicator/genlogicor",
7267  "Generate logicor constraints instead of cuts?",
7268  &conshdlrdata->genlogicor, TRUE, DEFAULT_GENLOGICOR, NULL, NULL) );
7269 
7271  "constraints/indicator/addcoupling",
7272  "Add coupling constraints or rows if big-M is small enough?",
7273  &conshdlrdata->addcoupling, TRUE, DEFAULT_ADDCOUPLING, NULL, NULL) );
7274 
7276  "constraints/indicator/maxcouplingvalue",
7277  "maximum coefficient for binary variable in coupling constraint",
7278  &conshdlrdata->maxcouplingvalue, TRUE, DEFAULT_MAXCOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
7279 
7281  "constraints/indicator/addcouplingcons",
7282  "Add initial variable upper bound constraints, if 'addcoupling' is true?",
7283  &conshdlrdata->addcouplingcons, TRUE, DEFAULT_ADDCOUPLINGCONS, NULL, NULL) );
7284 
7286  "constraints/indicator/sepacouplingcuts",
7287  "Should the coupling inequalities be separated dynamically?",
7288  &conshdlrdata->sepacouplingcuts, TRUE, DEFAULT_SEPACOUPLINGCUTS, NULL, NULL) );
7289 
7291  "constraints/indicator/sepacouplinglocal",
7292  "Allow to use local bounds in order to separate coupling inequalities?",
7293  &conshdlrdata->sepacouplinglocal, TRUE, DEFAULT_SEPACOUPLINGLOCAL, NULL, NULL) );
7294 
7296  "constraints/indicator/sepacouplingvalue",
7297  "maximum coefficient for binary variable in separated coupling constraint",
7298  &conshdlrdata->sepacouplingvalue, TRUE, DEFAULT_SEPACOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
7299 
7301  "constraints/indicator/sepaperspective",
7302  "Separate cuts based on perspective formulation?",
7303  &conshdlrdata->sepaperspective, TRUE, DEFAULT_SEPAPERSPECTIVE, NULL, NULL) );
7304 
7306  "constraints/indicator/sepapersplocal",
7307  "Allow to use local bounds in order to separate perspective cuts?",
7308  &conshdlrdata->sepapersplocal, TRUE, DEFAULT_SEPAPERSPLOCAL, NULL, NULL) );
7309 
7310  SCIP_CALL( SCIPaddIntParam(scip,
7311  "constraints/indicator/maxsepanonviolated",
7312  "maximal number of separated non violated IISs, before separation is stopped",
7313  &conshdlrdata->maxsepanonviolated, FALSE, DEFAULT_MAXSEPANONVIOLATED, 0, INT_MAX, NULL, NULL) );
7314 
7316  "constraints/indicator/updatebounds",
7317  "Update bounds of original variables for separation?",
7318  &conshdlrdata->updatebounds, TRUE, DEFAULT_UPDATEBOUNDS, NULL, NULL) );
7319 
7321  "constraints/indicator/maxconditionaltlp",
7322  "maximum estimated condition of the solution basis matrix of the alternative LP to be trustworthy (0.0 to disable check)",
7323  &conshdlrdata->maxconditionaltlp, TRUE, DEFAULT_MAXCONDITIONALTLP, 0.0, SCIP_REAL_MAX, NULL, NULL) );
7324 
7325  SCIP_CALL( SCIPaddIntParam(scip,
7326  "constraints/indicator/maxsepacuts",
7327  "maximal number of cuts separated per separation round",
7328  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
7329 
7330  SCIP_CALL( SCIPaddIntParam(scip,
7331  "constraints/indicator/maxsepacutsroot",
7332  "maximal number of cuts separated per separation round in the root node",
7333  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
7334 
7336  "constraints/indicator/removeindicators",
7337  "Remove indicator constraint if corresponding variable bound constraint has been added?",
7338  &conshdlrdata->removeindicators, TRUE, DEFAULT_REMOVEINDICATORS, NULL, NULL) );
7339 
7341  "constraints/indicator/generatebilinear",
7342  "Do not generate indicator constraint, but a bilinear constraint instead?",
7343  &conshdlrdata->generatebilinear, TRUE, DEFAULT_GENERATEBILINEAR, NULL, NULL) );
7344 
7346  "constraints/indicator/scaleslackvar",
7347  "Scale slack variable coefficient at construction time?",
7348  &conshdlrdata->scaleslackvar, TRUE, DEFAULT_SCALESLACKVAR, NULL, NULL) );
7349 
7351  "constraints/indicator/trysolutions",
7352  "Try to make solutions feasible by setting indicator variables?",
7353  &conshdlrdata->trysolutions, TRUE, DEFAULT_TRYSOLUTIONS, NULL, NULL) );
7354 
7356  "constraints/indicator/enforcecuts",
7357  "In enforcing try to generate cuts (only if sepaalternativelp is true)?",
7358  &conshdlrdata->enforcecuts, TRUE, DEFAULT_ENFORCECUTS, NULL, NULL) );
7359 
7361  "constraints/indicator/dualreductions",
7362  "Should dual reduction steps be performed?",
7363  &conshdlrdata->dualreductions, TRUE, DEFAULT_DUALREDUCTIONS, NULL, NULL) );
7364 
7366  "constraints/indicator/addopposite",
7367  "Add opposite inequality in nodes in which the binary variable has been fixed to 0?",
7368  &conshdlrdata->addopposite, TRUE, DEFAULT_ADDOPPOSITE, NULL, NULL) );
7369 
7371  "constraints/indicator/conflictsupgrade",
7372  "Try to upgrade bounddisjunction conflicts by replacing slack variables?",
7373  &conshdlrdata->conflictsupgrade, TRUE, DEFAULT_CONFLICTSUPGRADE, NULL, NULL) );
7374 
7376  "constraints/indicator/restartfrac",
7377  "fraction of binary variables that need to be fixed before restart occurs (in forcerestart)",
7378  &conshdlrdata->restartfrac, TRUE, DEFAULT_RESTARTFRAC, 0.0, 1.0, NULL, NULL) );
7379 
7381  "constraints/indicator/useotherconss",
7382  "Collect other constraints to alternative LP?",
7383  &conshdlrdata->useotherconss, TRUE, DEFAULT_USEOTHERCONSS, NULL, NULL) );
7384 
7386  "constraints/indicator/useobjectivecut",
7387  "Use objective cut with current best solution to alternative LP?",
7388  &conshdlrdata->useobjectivecut, TRUE, DEFAULT_USEOBJECTIVECUT, NULL, NULL) );
7389 
7391  "constraints/indicator/trysolfromcover",
7392  "Try to construct a feasible solution from a cover?",
7393  &conshdlrdata->trysolfromcover, TRUE, DEFAULT_TRYSOLFROMCOVER, NULL, NULL) );
7394 
7396  "constraints/indicator/upgradelinear",
7397  "Try to upgrade linear constraints to indicator constraints?",
7398  &conshdlrdata->upgradelinear, TRUE, DEFAULT_UPGRADELINEAR, NULL, NULL) );
7399 
7400  /* parameters that should not be changed after problem stage: */
7402  "constraints/indicator/sepaalternativelp",
7403  "Separate using the alternative LP?",
7404  &conshdlrdata->sepaalternativelp_, TRUE, DEFAULT_SEPAALTERNATIVELP, paramChangedIndicator, NULL) );
7405 
7407  "constraints/indicator/forcerestart",
7408  "Force restart if absolute gap is 1 or enough binary variables have been fixed?",
7409  &conshdlrdata->forcerestart_, TRUE, DEFAULT_FORCERESTART, paramChangedIndicator, NULL) );
7410 
7412  "constraints/indicator/nolinconscont",
7413  "Decompose problem (do not generate linear constraint if all variables are continuous)?",
7414  &conshdlrdata->nolinconscont_, TRUE, DEFAULT_NOLINCONSCONT, paramChangedIndicator, NULL) );
7415 
7416  return SCIP_OKAY;
7417 }
7418 
7419 /** creates and captures an indicator constraint
7420  *
7421  * @note @a binvar is checked to be binary only later. This enables a change of the type in
7422  * procedures reading an instance.
7423  *
7424  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7425  */
7427  SCIP* scip, /**< SCIP data structure */
7428  SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
7429  const char* name, /**< name of constraint */
7430  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
7431  int nvars, /**< number of variables in the inequality */
7432  SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
7433  SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
7434  SCIP_Real rhs, /**< rhs of the inequality */
7435  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
7436  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
7437  * Usually set to TRUE. */
7438  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
7439  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7440  SCIP_Bool check, /**< should the constraint be checked for feasibility?
7441  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7442  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
7443  * Usually set to TRUE. */
7444  SCIP_Bool local, /**< is constraint only valid locally?
7445  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7446  SCIP_Bool dynamic, /**< is constraint subject to aging?
7447  * Usually set to FALSE. Set to TRUE for own cuts which
7448  * are separated as constraints. */
7449  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
7450  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
7451  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
7452  * if it may be moved to a more global node?
7453  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
7454  )
7455 {
7456  return SCIPcreateConsIndicatorGeneric(scip, cons, name, binvar, nvars, vars, vals, rhs, TRUE, TRUE, initial,
7457  separate, enforce, check, propagate, local, dynamic, removable, stickingatnode);
7458 }
7459 
7460 /** creates and captures a indicator constraint in a more generic version.
7461  *
7462  * The key difference from SCIPcreateConsIndicator() is the activeone and lessthanineq Booleans.
7463  * If \f$z = o\f$, with \f$o\f$ the activeone flag, then:
7464  * 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$.
7465  * The underlying linear constraint is always created as a less-than inequality.
7466  */
7468  SCIP* scip, /**< SCIP data structure */
7469  SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
7470  const char* name, /**< name of constraint */
7471  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
7472  int nvars, /**< number of variables in the inequality */
7473  SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
7474  SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
7475  SCIP_Real rhs, /**< rhs of the inequality */
7476  SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
7477  SCIP_Bool lessthanineq, /**< is the linear constraint a less than RHS (TRUE) or greater than RHS (FALSE)? */
7478  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
7479  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
7480  * Usually set to TRUE. */
7481  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
7482  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7483  SCIP_Bool check, /**< should the constraint be checked for feasibility?
7484  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7485  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
7486  * Usually set to TRUE. */
7487  SCIP_Bool local, /**< is constraint only valid locally?
7488  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7489  SCIP_Bool dynamic, /**< is constraint subject to aging?
7490  * Usually set to FALSE. Set to TRUE for own cuts which
7491  * are separated as constraints. */
7492  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
7493  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
7494  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
7495  * if it may be moved to a more global node?
7496  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
7497  )
7498 {
7499  SCIP_CONSHDLR* conshdlr;
7500  SCIP_CONSHDLRDATA* conshdlrdata;
7501  SCIP_CONSDATA* consdata;
7502  SCIP_CONS* lincons;
7503  SCIP_VAR* slackvar;
7504  SCIP_Bool modifiable = FALSE;
7505  SCIP_Bool linconsactive;
7506  SCIP_VARTYPE slackvartype;
7507  SCIP_Real absvalsum = 0.0;
7508  char s[SCIP_MAXSTRLEN];
7509  SCIP_Real* valscopy;
7510  int j;
7511 
7512  if ( nvars < 0 )
7513  {
7514  SCIPerrorMessage("Indicator constraint <%s> needs nonnegative number of variables in linear constraint.\n", name);
7515  return SCIP_INVALIDDATA;
7516  }
7517 
7518  /* find the indicator constraint handler */
7519  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
7520  if ( conshdlr == NULL )
7521  {
7522  SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
7523  return SCIP_PLUGINNOTFOUND;
7524  }
7525 
7526  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7527  assert( conshdlrdata != NULL );
7528 
7529  if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
7530  {
7531  SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
7532  return SCIP_INVALIDDATA;
7533  }
7534 
7535  if ( conshdlrdata->nolinconscont && conshdlrdata->generatebilinear )
7536  {
7537  SCIPerrorMessage("constraint handler <%s>: parameters <nolinconscont> and <generatebilinear> cannot both be true.\n", CONSHDLR_NAME);
7538  return SCIP_INVALIDDATA;
7539  }
7540 
7541  valscopy = NULL;
7542  if ( lessthanineq )
7543  valscopy = vals;
7544  else
7545  {
7546  /* flip coefficients and RHS of indicator */
7547  SCIP_CALL( SCIPallocBufferArray(scip, &valscopy, nvars) );
7548  for (j = 0; j < nvars; ++j)
7549  valscopy[j] = -vals[j];
7550  rhs = -rhs;
7551  }
7552  assert( nvars == 0 || valscopy != NULL );
7553 
7554  /* check if slack variable can be made implicit integer */
7555  slackvartype = SCIP_VARTYPE_IMPLINT;
7556  for (j = 0; j < nvars; ++j)
7557  {
7558  if ( conshdlrdata->scaleslackvar )
7559  absvalsum += REALABS(valscopy[j]);
7560  if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, valscopy[j]) )
7561  {
7562  slackvartype = SCIP_VARTYPE_CONTINUOUS;
7563  if ( ! conshdlrdata->scaleslackvar )
7564  break;
7565  }
7566  }
7567 
7568  /* create slack variable */
7569  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
7570  SCIP_CALL( SCIPcreateVar(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0, slackvartype, TRUE, FALSE,
7571  NULL, NULL, NULL, NULL, NULL) );
7572 
7573  SCIP_CALL( SCIPaddVar(scip, slackvar) );
7574 
7575  /* mark slack variable not to be multi-aggregated */
7576  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );
7577 
7578  /* if the problem should be decomposed if only non-integer variables are present */
7579  linconsactive = TRUE;
7580  if ( conshdlrdata->nolinconscont )
7581  {
7582  SCIP_Bool onlyCont = TRUE;
7583 
7584  assert( ! conshdlrdata->generatebilinear );
7585 
7586  /* check whether call variables are non-integer */
7587  for (j = 0; j < nvars; ++j)
7588  {
7589  SCIP_VARTYPE vartype;
7590 
7591  vartype = SCIPvarGetType(vars[j]);
7592  if ( vartype != SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_IMPLINT )
7593  {
7594  onlyCont = FALSE;
7595  break;
7596  }
7597  }
7598 
7599  if ( onlyCont )
7600  linconsactive = FALSE;
7601  }
7602 
7603  /* create linear constraint */
7604  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indlin_%s", name);
7605 
7606  /* if the linear constraint should be activated (lincons is captured) */
7607  if ( linconsactive )
7608  {
7609  /* the constraint is initial if initial is true, enforced, separated, and checked */
7610  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, s, nvars, vars, valscopy, -SCIPinfinity(scip), rhs,
7611  initial, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
7612  }
7613  else
7614  {
7615  /* create non-active linear constraint, which is neither initial, nor enforced, nor separated, nor checked */
7616  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, s, nvars, vars, valscopy, -SCIPinfinity(scip), rhs,
7618  }
7619 
7620  if ( ! lessthanineq )
7621  SCIPfreeBufferArray(scip, &valscopy);
7622 
7623  /* mark linear constraint not to be upgraded - otherwise we loose control over it */
7624  SCIPconsAddUpgradeLocks(lincons, 1);
7625  assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
7626 
7627  /* add slack variable */
7628  if ( conshdlrdata->scaleslackvar && nvars > 0 )
7629  {
7630  absvalsum = absvalsum/((SCIP_Real) nvars);
7631  if ( slackvartype == SCIP_VARTYPE_IMPLINT )
7632  absvalsum = SCIPceil(scip, absvalsum);
7633  if ( SCIPisZero(scip, absvalsum) )
7634  absvalsum = 1.0;
7635  SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, -absvalsum) );
7636  }
7637  else
7638  {
7639  SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, -1.0) );
7640  }
7641  SCIP_CALL( SCIPaddCons(scip, lincons) );
7642 
7643  /* check whether we should generate a bilinear constraint instead of an indicator constraint */
7644  if ( conshdlrdata->generatebilinear )
7645  {
7646  SCIP_Real val = 1.0;
7647  SCIP_VAR* binvarinternal;
7648 
7649  /* if active on 0, the binary variable is reversed */
7650  if ( activeone )
7651  binvarinternal = binvar;
7652  else
7653  {
7654  SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
7655  }
7656 
7657  /* create a quadratic constraint with a single bilinear term - note that cons is used */
7658  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
7659  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
7660  }
7661  else
7662  {
7663  /* create constraint data */
7664  consdata = NULL;
7665  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrbound, conshdlrdata->eventhdlrrestart,
7666  binvar, activeone, lessthanineq, slackvar, lincons, linconsactive) );
7667  assert( consdata != NULL );
7668  /* do not need to capture slack variable and linear constraint here */
7669 
7670  /* create constraint */
7671  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
7672  local, modifiable, dynamic, removable, stickingatnode) );
7673 
7674  if ( SCIPisTransformed(scip) )
7675  {
7676  /* make sure that binary variable hash exists */
7677  if ( conshdlrdata->sepaalternativelp )
7678  {
7679  SCIP_VAR* binvarinternal;
7680 
7681  if ( conshdlrdata->binvarhash == NULL )
7682  {
7683  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
7684  }
7685 
7686  /* if active on 0, the binary variable is reversed */
7687  if ( activeone )
7688  binvarinternal = binvar;
7689  else
7690  {
7691  SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
7692  }
7693 
7694  /* check whether binary variable is present: note that a binary variable might appear several times, but this seldomly happens. */
7695  assert( conshdlrdata->binvarhash != NULL );
7696  if ( ! SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarinternal) )
7697  {
7698  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binvarhash, (void*) binvarinternal, (void*) (*cons)) );
7699  }
7700  }
7701  }
7702  }
7703 
7704  return SCIP_OKAY;
7705 }
7706 
7707 /** creates and captures an indicator constraint in its most basic version, i. e., all constraint flags are set to their
7708  * basic value as explained for the method SCIPcreateConsIndicator(); all flags can be set via
7709  * SCIPsetConsFLAGNAME-methods in scip.h
7710  *
7711  * @see SCIPcreateConsIndicator() for information about the basic constraint flag configuration
7712  *
7713  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7714  */
7716  SCIP* scip, /**< SCIP data structure */
7717  SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
7718  const char* name, /**< name of constraint */
7719  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
7720  int nvars, /**< number of variables in the inequality */
7721  SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
7722  SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
7723  SCIP_Real rhs /**< rhs of the inequality */
7724  )
7725 {
7726  assert( scip != NULL );
7727 
7728  SCIP_CALL( SCIPcreateConsIndicator(scip, cons, name, binvar, nvars, vars, vals, rhs,
7729  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
7730 
7731  return SCIP_OKAY;
7732 }
7733 
7734 /** creates and captures an indicator constraint with given linear constraint and slack variable
7735  * in a generic version, i. e., with a flag activeone indicating whether the constraint is active on
7736  * value 1 or 0 of the binary variable.
7737 
7738  * @note @a binvar is checked to be binary only later. This enables a change of the type in
7739  * procedures reading an instance.
7740  *
7741  * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
7742  * the role of a slack variable!
7743  *
7744  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7745  *
7746  * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
7747  */
7749  SCIP* scip, /**< SCIP data structure */
7750  SCIP_CONS** cons, /**< pointer to hold the created constraint */
7751  const char* name, /**< name of constraint */
7752  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
7753  SCIP_CONS* lincons, /**< linear constraint */
7754  SCIP_VAR* slackvar, /**< slack variable */
7755  SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
7756  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
7757  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
7758  * Usually set to TRUE. */
7759  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
7760  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7761  SCIP_Bool check, /**< should the constraint be checked for feasibility?
7762  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7763  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
7764  * Usually set to TRUE. */
7765  SCIP_Bool local, /**< is constraint only valid locally?
7766  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7767  SCIP_Bool dynamic, /**< is constraint subject to aging?
7768  * Usually set to FALSE. Set to TRUE for own cuts which
7769  * are separated as constraints. */
7770  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
7771  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
7772  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
7773  * if it may be moved to a more global node?
7774  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
7775  )
7776 {
7777  SCIP_CONSHDLR* conshdlr;
7778  SCIP_CONSHDLRDATA* conshdlrdata;
7779  SCIP_CONSDATA* consdata = NULL;
7780  SCIP_Bool modifiable = FALSE;
7781  SCIP_Bool linconsactive = TRUE;
7782 
7783  assert( scip != NULL );
7784  assert( lincons != NULL );
7785  assert( slackvar != NULL );
7786 
7787  /* check whether lincons is really a linear constraint */
7788  conshdlr = SCIPconsGetHdlr(lincons);
7789  if ( strcmp(SCIPconshdlrGetName(conshdlr), "linear") != 0 )
7790  {
7791  SCIPerrorMessage("Lincons constraint is not linear.\n");
7792  return SCIP_INVALIDDATA;
7793  }
7794 
7795  /* find the indicator constraint handler */
7796  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
7797  if ( conshdlr == NULL )
7798  {
7799  SCIPerrorMessage("<%s> constraint handler not found.\n", CONSHDLR_NAME);
7800  return SCIP_PLUGINNOTFOUND;
7801  }
7802 
7803  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7804  assert( conshdlrdata != NULL );
7805 
7806  if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
7807  {
7808  SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
7809  return SCIP_INVALIDDATA;
7810  }
7811 
7812  /* mark slack variable not to be multi-aggregated */
7813  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );
7814 
7815  /* if the problem should be decomposed (only if all variables are continuous) */
7816  if ( conshdlrdata->nolinconscont )
7817  {
7818  SCIP_Bool onlyCont = TRUE;
7819  int v;
7820  int nvars;
7821  SCIP_VAR** vars;
7822 
7823  nvars = SCIPgetNVarsLinear(scip, lincons);
7824  vars = SCIPgetVarsLinear(scip, lincons);
7825 
7826  /* check whether call variables are non-integer */
7827  for (v = 0; v < nvars; ++v)
7828  {
7829  SCIP_VARTYPE vartype;
7830 
7831  vartype = SCIPvarGetType(vars[v]);
7832  if ( vartype != SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_IMPLINT )
7833  {
7834  onlyCont = FALSE;
7835  break;
7836  }
7837  }
7838 
7839  if ( onlyCont )
7840  linconsactive = FALSE;
7841  }
7842 
7843  /* mark linear constraint not to be upgraded - otherwise we loose control over it */
7844  SCIPconsAddUpgradeLocks(lincons, 1);
7845  assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
7846 
7847  /* check whether we should generate a bilinear constraint instead of an indicator constraint */
7848  if ( conshdlrdata->generatebilinear )
7849  {
7850  SCIP_Real val = 1.0;
7851 
7852  /* if active on 0, the binary variable is reversed */
7853  SCIP_VAR* binvarinternal;
7854  if ( activeone )
7855  {
7856  binvarinternal = binvar;
7857  }
7858  else
7859  {
7860  SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
7861  }
7862 
7863  /* create a quadratic constraint with a single bilinear term - note that cons is used */
7864  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
7865  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
7866  }
7867  else
7868  {
7869  /* create constraint data */
7870  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrbound, conshdlrdata->eventhdlrrestart,
7871  binvar, activeone, TRUE, slackvar, lincons, linconsactive) );
7872  assert( consdata != NULL );
7873 
7874  /* create constraint */
7875  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
7876  local, modifiable, dynamic, removable, stickingatnode) );
7877  }
7878 
7879  /* capture slack variable and linear constraint */
7880  SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
7881  SCIP_CALL( SCIPcaptureCons(scip, lincons) );
7882 
7883  return SCIP_OKAY;
7884 }
7885 
7886 /** creates and captures an indicator constraint with given linear constraint and slack variable
7887  *
7888  * @note @a binvar is checked to be binary only later. This enables a change of the type in
7889  * procedures reading an instance.
7890  *
7891  * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
7892  * the role of a slack variable!
7893  *
7894  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7895  */
7897  SCIP* scip, /**< SCIP data structure */
7898  SCIP_CONS** cons, /**< pointer to hold the created constraint */
7899  const char* name, /**< name of constraint */
7900  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
7901  SCIP_CONS* lincons, /**< linear constraint */
7902  SCIP_VAR* slackvar, /**< slack variable */
7903  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
7904  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
7905  * Usually set to TRUE. */
7906  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
7907  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7908  SCIP_Bool check, /**< should the constraint be checked for feasibility?
7909  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7910  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
7911  * Usually set to TRUE. */
7912  SCIP_Bool local, /**< is constraint only valid locally?
7913  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7914  SCIP_Bool dynamic, /**< is constraint subject to aging?
7915  * Usually set to FALSE. Set to TRUE for own cuts which
7916  * are separated as constraints. */
7917  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
7918  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
7919  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
7920  * if it may be moved to a more global node?
7921  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
7922  )
7923 {
7924  return SCIPcreateConsIndicatorGenericLinCons(scip, cons, name, binvar, lincons, slackvar, TRUE, initial, separate,
7925  enforce, check, propagate, local, dynamic, removable, stickingatnode);
7926 }
7927 
7928 
7929 /** creates and captures an indicator constraint with given linear constraint and slack variable
7930  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
7931  * method SCIPcreateConsIndicator(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
7932  *
7933  * @note @a binvar is checked to be binary only later. This enables a change of the type in
7934  * procedures reading an instance.
7935  *
7936  * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
7937  * the role of a slack variable!
7938  *
7939  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7940  *
7941  * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
7942  *
7943  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7944  */
7946  SCIP* scip, /**< SCIP data structure */
7947  SCIP_CONS** cons, /**< pointer to hold the created constraint */
7948  const char* name, /**< name of constraint */
7949  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
7950  SCIP_CONS* lincons, /**< linear constraint */
7951  SCIP_VAR* slackvar /**< slack variable */
7952  )
7953 {
7954  assert( scip != NULL );
7955 
7956  SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
7957  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
7958 
7959  return SCIP_OKAY;
7960 }
7961 
7962 
7963 /** adds variable to the inequality of the indicator constraint */
7965  SCIP* scip, /**< SCIP data structure */
7966  SCIP_CONS* cons, /**< indicator constraint */
7967  SCIP_VAR* var, /**< variable to add to the inequality */
7968  SCIP_Real val /**< value of variable */
7969  )
7970 {
7971  SCIP_CONSDATA* consdata;
7972 
7973  assert( cons != NULL );
7974  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
7975 
7976  consdata = SCIPconsGetData(cons);
7977  assert( consdata != NULL );
7978 
7979  /* if linear inequality is flipped, variable is added with negative coefficient */
7980  if ( !consdata->lessthanineq )
7981  val = -val;
7982 
7983  SCIP_CALL( SCIPaddCoefLinear(scip, consdata->lincons, var, val) );
7984 
7985  /* possibly adapt variable type */
7986  if ( SCIPvarGetType(consdata->slackvar) != SCIP_VARTYPE_CONTINUOUS && (! SCIPvarIsIntegral(var) || ! SCIPisIntegral(scip, val) ) )
7987  {
7988  SCIP_Bool infeasible;
7989 
7990  SCIP_CALL( SCIPchgVarType(scip, consdata->slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
7991  assert( ! infeasible );
7992  }
7993 
7994  return SCIP_OKAY;
7995 }
7996 
7997 
7998 /** gets the linear constraint corresponding to the indicator constraint (may be NULL) */
8000  SCIP_CONS* cons /**< indicator constraint */
8001  )
8002 {
8003  SCIP_CONSDATA* consdata;
8004 
8005  assert( cons != NULL );
8006  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8007 
8008  consdata = SCIPconsGetData(cons);
8009  assert( consdata != NULL );
8010 
8011  return consdata->lincons;
8012 }
8013 
8014 
8015 /** sets the linear constraint corresponding to the indicator constraint (may be NULL) */
8017  SCIP* scip, /**< SCIP data structure */
8018  SCIP_CONS* cons, /**< indicator constraint */
8019  SCIP_CONS* lincons /**< linear constraint */
8020  )
8021 {
8022  SCIP_CONSHDLR* conshdlr;
8023  SCIP_CONSHDLRDATA* conshdlrdata;
8024  SCIP_CONSDATA* consdata;
8025 
8026  if ( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
8027  {
8028  SCIPerrorMessage("Cannot set linear constraint in SCIP stage <%d>\n", SCIPgetStage(scip) );
8029  return SCIP_INVALIDCALL;
8030  }
8031 
8032  assert( cons != NULL );
8033  conshdlr = SCIPconsGetHdlr(cons);
8034 
8035  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8036  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8037  assert( conshdlrdata != NULL );
8038 
8039  consdata = SCIPconsGetData(cons);
8040  assert( consdata != NULL );
8041 
8042  /* free old linear constraint */
8043  assert( consdata->lincons != NULL );
8044  SCIP_CALL( SCIPdelCons(scip, consdata->lincons) );
8045  SCIP_CALL( SCIPreleaseCons(scip, &(consdata->lincons) ) );
8046 
8047  assert( lincons != NULL );
8048  consdata->lincons = lincons;
8049  consdata->linconsactive = TRUE;
8050  SCIP_CALL( SCIPcaptureCons(scip, lincons) );
8051 
8052  /* if the problem should be decomposed if only non-integer variables are present */
8053  if ( conshdlrdata->nolinconscont )
8054  {
8055  SCIP_Bool onlyCont;
8056  int v;
8057  int nvars;
8058  SCIP_VAR** vars;
8059 
8060  onlyCont = TRUE;
8061  nvars = SCIPgetNVarsLinear(scip, lincons);
8062  vars = SCIPgetVarsLinear(scip, lincons);
8063  assert( vars != NULL );
8064 
8065  /* check whether call variables are non-integer */
8066  for (v = 0; v < nvars; ++v)
8067  {
8068  SCIP_VARTYPE vartype;
8069 
8070  vartype = SCIPvarGetType(vars[v]);
8071  if ( vartype != SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_IMPLINT )
8072  {
8073  onlyCont = FALSE;
8074  break;
8075  }
8076  }
8077 
8078  if ( onlyCont )
8079  consdata->linconsactive = FALSE;
8080  }
8081 
8082  return SCIP_OKAY;
8083 }
8084 
8085 /** gets activation value of an indicator constraint, TRUE for active on 1, FALSE for active on 0 */
8087  SCIP_CONS* cons /**< indicator constraint */
8088  )
8089 {
8090  SCIP_CONSDATA* consdata;
8091 
8092  assert( cons != NULL );
8093  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8094 
8095  consdata = SCIPconsGetData(cons);
8096  assert( consdata != NULL );
8097 
8098  return consdata->activeone;
8099 }
8100 
8101 
8102 /** gets binary variable corresponding to indicator constraint */
8104  SCIP_CONS* cons /**< indicator constraint */
8105  )
8106 {
8107  SCIP_CONSDATA* consdata;
8108 
8109  assert( cons != NULL );
8110  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8111 
8112  consdata = SCIPconsGetData(cons);
8113  assert( consdata != NULL );
8114 
8115  return consdata->binvar;
8116 }
8117 
8118 /** similar to SCIPgetBinaryVarIndicator but returns the original binary variable passed by the user. */
8120  SCIP_CONS* cons /**< indicator constraint */
8121  )
8122 {
8123  SCIP_CONSDATA* consdata;
8124  SCIP_VAR* binvar;
8125 
8126  assert(cons != NULL);
8127  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
8128 
8129  consdata = SCIPconsGetData(cons);
8130  assert(consdata != NULL);
8131  binvar = consdata->binvar;
8132 
8133  if ( ! consdata->activeone )
8134  binvar = SCIPvarGetNegationVar(binvar);
8135  assert(binvar != NULL);
8136 
8137  return binvar;
8138 }
8139 
8140 /** sets binary indicator variable for indicator constraint */
8142  SCIP* scip, /**< SCIP data structure */
8143  SCIP_CONS* cons, /**< indicator constraint */
8144  SCIP_VAR* binvar /**< binary variable to add to the inequality */
8145  )
8146 {
8147  SCIP_CONSDATA* consdata;
8148 
8149  assert( cons != NULL );
8150  assert( binvar != NULL );
8151  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8152 
8153  consdata = SCIPconsGetData(cons);
8154  assert( consdata != NULL );
8155 
8156  /* check type */
8157  if ( SCIPvarGetType(binvar) != SCIP_VARTYPE_BINARY )
8158  {
8159  SCIPerrorMessage("Indicator variable <%s> is not binary %d.\n", SCIPvarGetName(binvar), SCIPvarGetType(binvar));
8160  return SCIP_ERROR;
8161  }
8162 
8163  /* check previous binary variable */
8164  if ( consdata->binvar != NULL )
8165  {
8166  /* to allow replacement of binary variables, we would need to drop events etc. */
8167  SCIPerrorMessage("Cannot replace binary variable <%s> for indicator constraint <%s>.\n", SCIPvarGetName(binvar), SCIPconsGetName(cons));
8168  return SCIP_INVALIDCALL;
8169  }
8170 
8171  /* if we are transformed, obtain transformed variables and catch events */
8172  if ( SCIPconsIsTransformed(cons) )
8173  {
8174  SCIP_VAR* var;
8175  SCIP_CONSHDLR* conshdlr;
8176  SCIP_CONSHDLRDATA* conshdlrdata;
8177 
8178  /* make sure we have a transformed binary variable */
8179  SCIP_CALL( SCIPgetTransformedVar(scip, binvar, &var) );
8180  assert( var != NULL );
8181  if ( ! consdata->activeone )
8182  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
8183 
8184  consdata->binvar = var;
8185 
8186  conshdlr = SCIPconsGetHdlr(cons);
8187  assert( conshdlr != NULL );
8188  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8189  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8190  assert( conshdlrdata != NULL );
8191  assert( conshdlrdata->eventhdlrbound != NULL );
8192  assert( conshdlrdata->eventhdlrrestart != NULL );
8193 
8194  /* catch local bound change events on binary variable */
8195  if ( consdata->linconsactive )
8196  {
8197  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, NULL) );
8198  }
8199 
8200  /* catch global bound change events on binary variable */
8201  if ( conshdlrdata->forcerestart )
8202  {
8203  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
8204  }
8205 
8206  /* if binary variable is fixed to be nonzero */
8207  if ( SCIPvarGetLbLocal(var) > 0.5 )
8208  ++(consdata->nfixednonzero);
8209  }
8210  else
8211  {
8212  if ( ! consdata->activeone )
8213  SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
8214  consdata->binvar = binvar;
8215  }
8216 
8217  return SCIP_OKAY;
8218 }
8219 
8220 /** gets slack variable corresponding to indicator constraint */
8222  SCIP_CONS* cons /**< indicator constraint */
8223  )
8224 {
8225  SCIP_CONSDATA* consdata;
8226 
8227  assert( cons != NULL );
8228  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8229 
8230  consdata = SCIPconsGetData(cons);
8231  assert( consdata != NULL );
8232 
8233  return consdata->slackvar;
8234 }
8235 
8236 
8237 /** sets upper bound for slack variable corresponding to indicator constraint
8238  *
8239  * Use with care if you know that the maximal violation of the corresponding constraint is at most @p ub. This bound
8240  * might be improved automatically during the solution process.
8241  *
8242  * @pre This method should only be called if SCIP is in one of the following stages:
8243  * - \ref SCIP_STAGE_INIT
8244  * - \ref SCIP_STAGE_PROBLEM
8245  */
8247  SCIP* scip, /**< SCIP data structure */
8248  SCIP_CONS* cons, /**< indicator constraint */
8249  SCIP_Real ub /**< upper bound for slack variable */
8250  )
8251 {
8252  SCIP_CONSDATA* consdata;
8253 
8254  assert( scip != NULL );
8255  assert( cons != NULL );
8256  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8257 
8258  consdata = SCIPconsGetData(cons);
8259  assert( consdata != NULL );
8260 
8261  if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM )
8262  return SCIP_OKAY;
8263 
8264  assert( consdata->slackvar != NULL );
8265  SCIP_CALL( SCIPchgVarUb(scip, consdata->slackvar, ub) );
8266 
8267  return SCIP_OKAY;
8268 }
8269 
8270 
8271 /** checks whether indicator constraint is violated w.r.t. sol */
8273  SCIP* scip, /**< SCIP data structure */
8274  SCIP_CONS* cons, /**< indicator constraint */
8275  SCIP_SOL* sol /**< solution, or NULL to use current node's solution */
8276  )
8277 {
8278  SCIP_CONSDATA* consdata;
8279 
8280  assert( cons != NULL );
8281 
8282  /* deleted constraints should always be satisfied */
8283  if ( SCIPconsIsDeleted(cons) )
8284  return FALSE;
8285 
8286  consdata = SCIPconsGetData(cons);
8287  assert( consdata != NULL );
8288 
8289  if ( consdata->linconsactive )
8290  {
8291  assert( consdata->slackvar != NULL );
8292  assert( consdata->binvar != NULL );
8293  return(
8294  SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) &&
8295  SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
8296  }
8297 
8298  /* @todo: check how this can be decided for linconsactive == FALSE */
8299  return TRUE;
8300 }
8301 
8302 
8303 /** based on values of other variables, computes slack and binary variable to turn constraint feasible
8304  *
8305  * It will also clean up the solution, i.e., shift slack variable, as follows:
8306  *
8307  * If the inequality is \f$a^T x + \gamma\, s \leq \beta\f$, the value of the slack variable
8308  * \f$s\f$ to achieve equality is
8309  * \f[
8310  * s^* = \frac{\beta - a^T x^*}{\gamma},
8311  * \f]
8312  * where \f$x^*\f$ is the given solution. In case of \f$a^T x + \gamma\, s \geq \alpha\f$, we
8313  * arrive at
8314  * \f[
8315  * s^* = \frac{\alpha - a^T x^*}{\gamma}.
8316  * \f]
8317  * The typical values of \f$\gamma\f$ in the first case is -1 and +1 in the second case.
8318  *
8319  * Now, let \f$\sigma\f$ be the sign of \f$\gamma\f$ in the first case and \f$-\gamma\f$ in the
8320  * second case. Thus, if \f$\sigma > 0\f$ and \f$s^* < 0\f$, the inequality cannot be satisfied by
8321  * a nonnegative value for the slack variable; in this case, we have to leave the values as they
8322  * are. If \f$\sigma < 0\f$ and \f$s^* > 0\f$, the solution violates the indicator constraint (we
8323  * can set the slack variable to value \f$s^*\f$). If \f$\sigma < 0\f$ and \f$s^* \leq 0\f$ or
8324  * \f$\sigma > 0\f$ and \f$s^* \geq 0\f$, the constraint is satisfied, and we can set the slack
8325  * variable to 0.
8326  */
8328  SCIP* scip, /**< SCIP data structure */
8329  SCIP_CONS* cons, /**< indicator constraint */
8330  SCIP_SOL* sol, /**< solution */
8331  SCIP_Bool* changed /**< pointer to store whether the solution has been changed */
8332  )
8333 {
8334  SCIP_CONSDATA* consdata;
8335  SCIP_CONS* lincons;
8336  SCIP_VAR** linvars;
8337  SCIP_Real* linvals;
8338  SCIP_VAR* slackvar;
8339  SCIP_VAR* binvar;
8340  SCIP_Real slackcoef;
8341  SCIP_Real sum;
8342  SCIP_Real val;
8343  int nlinvars;
8344  int sigma;
8345  int v;
8346 
8347  assert( cons != NULL );
8348  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8349  assert( sol != NULL );
8350  assert( changed != NULL );
8351 
8352  *changed = FALSE;
8353 
8354  /* avoid deleted indicator constraints, e.g., due to preprocessing */
8355  if ( ! SCIPconsIsActive(cons) && SCIPgetStage(scip) >= SCIP_STAGE_INITPRESOLVE )
8356  return SCIP_OKAY;
8357 
8358  assert( cons != NULL );
8359  consdata = SCIPconsGetData(cons);
8360  assert( consdata != NULL );
8361 
8362  /* if the linear constraint is not present, we cannot do anything */
8363  if ( ! consdata->linconsactive )
8364  return SCIP_OKAY;
8365 
8366  lincons = consdata->lincons;
8367  assert( lincons != NULL );
8368 
8369  /* avoid non-active linear constraints, e.g., due to preprocessing */
8370  if ( SCIPconsIsActive(lincons) || SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE )
8371  {
8372  slackvar = consdata->slackvar;
8373  binvar = consdata->binvar;
8374  assert( slackvar != NULL );
8375  assert( binvar != NULL );
8376 
8377  nlinvars = SCIPgetNVarsLinear(scip, lincons);
8378  linvars = SCIPgetVarsLinear(scip, lincons);
8379  linvals = SCIPgetValsLinear(scip, lincons);
8380 
8381  /* compute value of regular variables */
8382  sum = 0.0;
8383  slackcoef = 0.0;
8384  for (v = 0; v < nlinvars; ++v)
8385  {
8386  SCIP_VAR* var;
8387  var = linvars[v];
8388  if ( var != slackvar )
8389  sum += linvals[v] * SCIPgetSolVal(scip, sol, var);
8390  else
8391  slackcoef = linvals[v];
8392  }
8393 
8394  /* do nothing if slack variable does not appear */
8395  if ( SCIPisFeasZero(scip, slackcoef) )
8396  return SCIP_OKAY;
8397 
8398  assert( ! SCIPisZero(scip, slackcoef) );
8399  assert( slackcoef != 0.0 ); /* to satisfy lint */
8400  assert( SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, lincons)) || SCIPisInfinity(scip, SCIPgetRhsLinear(scip, lincons)) );
8401  assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(slackvar), 0.0) );
8402 
8403  val = SCIPgetRhsLinear(scip, lincons);
8404  sigma = 1;
8405  if ( SCIPisInfinity(scip, val) )
8406  {
8407  val = SCIPgetLhsLinear(scip, lincons);
8408  assert( ! SCIPisInfinity(scip, REALABS(val)) );
8409  sigma = -1;
8410  }
8411  /* compute value of slack that would achieve equality */
8412  val = (val - sum)/slackcoef;
8413 
8414  /* compute direction into which slack variable would be infeasible */
8415  if ( slackcoef < 0 )
8416  sigma *= -1;
8417 
8418  /* filter out cases in which no sensible change is possible */
8419  if ( sigma > 0 && SCIPisFeasNegative(scip, val) )
8420  return SCIP_OKAY;
8421 
8422  /* check if linear constraint w/o slack variable is violated */
8423  if ( sigma < 0 && SCIPisFeasPositive(scip, val) )
8424  {
8425  /* the original constraint is violated */
8426  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, slackvar), val) )
8427  {
8428  SCIP_CALL( SCIPsetSolVal(scip, sol, slackvar, val) );
8429  *changed = TRUE;
8430  }
8431  /* check whether binary variable is fixed or its negated variable is fixed */
8432  if ( SCIPvarGetStatus(binvar) != SCIP_VARSTATUS_FIXED &&
8434  {
8435  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 0.0) )
8436  {
8437  SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 0.0) );
8438  *changed = TRUE;
8439  }
8440  }
8441  }
8442  else
8443  {
8444  assert( SCIPisFeasGE(scip, val * ((SCIP_Real) sigma), 0.0) );
8445 
8446  /* the original constraint is satisfied - we can set the slack variable to 0 (slackvar
8447  * should only occur in this indicator constraint) */
8448  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, slackvar), 0.0) && SCIPisFeasPositive(scip, SCIPvarGetLbLocal(slackvar)) )
8449  {
8450  SCIP_CALL( SCIPsetSolVal(scip, sol, slackvar, 0.0) );
8451  *changed = TRUE;
8452  }
8453 
8454  /* check whether binary variable is fixed or its negated variable is fixed */
8455  if ( SCIPvarGetStatus(binvar) != SCIP_VARSTATUS_FIXED &&
8457  {
8458  SCIP_Real obj;
8459  obj = varGetObjDelta(binvar);
8460 
8461  /* check objective for possibly setting binary variable */
8462  if ( obj <= 0 )
8463  {
8464  /* setting variable to 1 does not increase objective - check whether we can set it to 1 */
8465  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 1.0) )
8466  {
8467  /* check whether variable only occurs in the current constraint */
8468  if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
8469  {
8470  SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 1.0) );
8471  *changed = TRUE;
8472  /* make sure that the other case does not occur if obj = 0: prefer variables set to 1 */
8473  obj = -1.0;
8474  }
8475  }
8476  else
8477  {
8478  /* make sure that the other case does not occur if obj = 0: prefer variables set to 1 */
8479  obj = -1.0;
8480  }
8481  }
8482  if ( obj >= 0 )
8483  {
8484  /* setting variable to 0 does not increase objective -> check whether variable only occurs in the current constraint
8485  * note: binary variables are only locked up */
8487  && ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 0.0) )
8488  {
8489  SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 0.0) );
8490  *changed = TRUE;
8491  }
8492  }
8493  }
8494  }
8495  }
8496 
8497  return SCIP_OKAY;
8498 }
8499 
8500 
8501 /** based on values of other variables, computes slack and binary variable to turn all constraints feasible */
8503  SCIP* scip, /**< SCIP data structure */
8504  SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
8505  SCIP_SOL* sol, /**< solution */
8506  SCIP_Bool* changed /**< pointer to store whether the solution has been changed */
8507  )
8508 {
8509  SCIP_CONS** conss;
8510  int nconss;
8511  int c;
8512 
8513  assert( conshdlr != NULL );
8514  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8515  assert( sol != NULL );
8516  assert( changed != NULL );
8517 
8518  *changed = FALSE;
8519 
8520  /* only run after or in presolving */
8521  if ( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE )
8522  return SCIP_OKAY;
8523 
8524  conss = SCIPconshdlrGetConss(conshdlr);
8525  nconss = SCIPconshdlrGetNConss(conshdlr);
8526 
8527  for (c = 0; c < nconss; ++c)
8528  {
8529  SCIP_CONSDATA* consdata;
8530  SCIP_Bool chg = FALSE;
8531  assert( conss[c] != NULL );
8532 
8533  consdata = SCIPconsGetData(conss[c]);
8534  assert( consdata != NULL );
8535 
8536  /* if the linear constraint is not present, we stop */
8537  if ( ! consdata->linconsactive )
8538  break;
8539 
8540  SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], sol, &chg) );
8541  *changed = *changed || chg;
8542  }
8543 
8544  return SCIP_OKAY;
8545 }
8546 
8547 
8548 /** adds additional linear constraint that is not connected with an indicator constraint, but can be used for separation */
8550  SCIP* scip, /**< SCIP data structure */
8551  SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
8552  SCIP_CONS* lincons /**< linear constraint */
8553  )
8554 {
8555  assert( scip != NULL );
8556  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8557  assert( lincons != NULL );
8558 
8559  /* do not add locally valid constraints (this would require much more bookkeeping) */
8560  if ( ! SCIPconsIsLocal(lincons) && ! SCIPconsIsModifiable(lincons) )
8561  {
8562  SCIP_CONSHDLRDATA* conshdlrdata;
8563 
8564  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8565  assert( conshdlrdata != NULL );
8566 
8567  SCIP_CALL( consdataEnsureAddLinConsSize(scip, conshdlr, conshdlrdata->naddlincons+1) );
8568  assert( conshdlrdata->naddlincons+1 <= conshdlrdata->maxaddlincons );
8569 
8570  conshdlrdata->addlincons[conshdlrdata->naddlincons++] = lincons;
8571  }
8572 
8573  return SCIP_OKAY;
8574 }
8575 
8576 
8577 /** adds additional row that is not connected with an indicator constraint, but can be used for separation
8578  *
8579  * @note The row is directly added to the alternative polyhedron and is not stored.
8580  */
8582  SCIP* scip, /**< SCIP data structure */
8583  SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
8584  SCIP_ROW* row /**< row to add */
8585  )
8586 {
8587  assert( scip != NULL );
8588  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8589  assert( row != NULL );
8590 
8591  /* skip local cuts (local cuts would require to dynamically add and remove columns from the alternative polyhedron */
8592  if ( ! SCIProwIsLocal(row) )
8593  {
8594  int colindex;
8595  SCIP_CONSHDLRDATA* conshdlrdata;
8596 
8597  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8598  assert( conshdlrdata != NULL );
8599 
8600  /* do not add rows if we do not separate */
8601  if ( ! conshdlrdata->sepaalternativelp )
8602  return SCIP_OKAY;
8603 
8604  SCIPdebugMsg(scip, "Adding row <%s> to alternative LP.\n", SCIProwGetName(row));
8605 
8606  /* add row directly to alternative polyhedron */
8607  SCIP_CALL( addAltLPRow(scip, conshdlr, row, 0.0, &colindex) );
8608  }
8609 
8610  return SCIP_OKAY;
8611 }
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:17146
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:17284
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:17225
#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:17136
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:17334
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:17235
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:17171
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:17181
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:5021
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:17191
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:16975
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:3571
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