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-2023 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file cons_indicator.c
26  * @ingroup DEFPLUGINS_CONS
27  * @brief constraint handler for indicator constraints
28  * @author Marc Pfetsch
29  *
30  * An indicator constraint is given by a binary variable \f$y\f$ and an inequality \f$ax \leq
31  * b\f$. It states that if \f$y = 1\f$ then \f$ax \leq b\f$ holds.
32  *
33  * This constraint is handled by adding a slack variable \f$s:\; ax - s \leq b\f$ with \f$s \geq
34  * 0\f$. The constraint is enforced by fixing \f$s\f$ to 0 if \f$y = 1\f$.
35  *
36  * @note The constraint only implements an implication not an equivalence, i.e., it does not ensure
37  * that \f$y = 1\f$ if \f$ax \leq b\f$ or equivalently if \f$s = 0\f$ holds.
38  *
39  * This constraint is equivalent to a linear constraint \f$ax - s \leq b\f$ and an SOS1 constraint on
40  * \f$y\f$ and \f$s\f$ (at most one should be nonzero). In the indicator context we can, however,
41  * separate more inequalities.
42  *
43  * The name indicator apparently comes from CPLEX.
44  *
45  *
46  * @section SEPARATION Separation Methods
47  *
48  * We now explain the handling of indicator constraints in more detail. The indicator constraint
49  * handler adds an inequality for each indicator constraint. We assume that this system (with added
50  * slack variables) is \f$ Ax - s \leq b \f$, where \f$ x \f$ are the original variables and \f$ s
51  * \f$ are the slack variables added by the indicator constraint. Variables \f$ y \f$ are the binary
52  * variables corresponding to the indicator constraints.
53  *
54  * @note In the implementation, we assume that bounds on the original variables \f$x\f$ cannot be
55  * influenced by the indicator constraint. If it should be possible to relax these constraints as
56  * well, then these constraints have to be added as indicator constraints.
57  *
58  * We separate inequalities by using the so-called alternative polyhedron.
59  *
60  *
61  * @section ALTERNATIVEPOLYHEDRON Separation via the Alternative Polyhedron
62  *
63  * We now describe the separation method of the first method in more detail.
64  *
65  * Consider the LP-relaxation of the current subproblem:
66  * \f[
67  * \begin{array}{ll}
68  * min & c^T x + d^T z\\
69  * & A x - s \leq b, \\
70  * & D x + C z \leq f, \\
71  * & l \leq x \leq u, \\
72  * & u \leq z \leq v, \\
73  * & 0 \leq s.
74  * \end{array}
75  * \f]
76  * As above \f$Ax - s \leq b\f$ contains all inequalities corresponding to indicator constraints,
77  * while the system \f$Dx + Cy \leq f\f$ contains all other inequalities (which are ignored in the
78  * following). Similarly, variables \f$z\f$ not appearing in indicator constraints are
79  * ignored. Bounds for the variables \f$x_j\f$ can be given, in particular, variables can be
80  * fixed. Note that \f$s \leq 0\f$ renders the system infeasible.
81  *
82  * To generate cuts, we construct the so-called @a alternative @a polyhedron:
83  * \f[
84  * \begin{array}{ll}
85  * P = \{ (w,r,t) : & A^T w - r + t = 0,\\
86  * & b^T w - l^T r + u^T t = -1,\\
87  * & w, r, t \geq 0 \}.
88  * \end{array}
89  * \f]
90  * Here, \f$r\f$ and \f$t\f$ correspond to the lower and upper bounds on \f$x\f$, respectively.
91  *
92  * It turns out that the vertices of \f$P\f$ correspond to minimal infeasible subsystems of \f$A x
93  * \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
94  * \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:
95  * \f[
96  * \sum_{i \in I} y_i \leq |I| - 1.
97  * \f]
98  *
99  *
100  * @subsection DETAIL Separation heuristic
101  *
102  * We separate the above inequalities by a heuristic described in
103  *
104  * Branch-And-Cut for the Maximum Feasible Subsystem Problem,@n
105  * Marc Pfetsch, SIAM Journal on Optimization 19, No.1, 21-38 (2008)
106  *
107  * The first step in the separation heuristic is to apply the transformation \f$\bar{y} = 1 - y\f$, which
108  * transforms the above inequality into the constraint
109  * \f[
110  * \sum_{i \in I} \bar{y}_i \geq 1,
111  * \f]
112  * that is, it is a set covering constraint on the negated variables.
113  *
114  * The basic idea is to use the current solution to the LP relaxation and use it as the objective,
115  * when optimizing of the alternative polyhedron. Since any vertex corresponds to such an
116  * inequality, we can check whether it is violated. To enlarge the chance that we find a @em
117  * violated inequality, we perform a fixing procedure, in which the variable corresponding to an
118  * arbitrary element of the last IIS \f$I\f$ is fixed to zero, i.e., cannot be used in the next
119  * IISs. This is repeated until the corresponding alternative polyhedron is infeasible, i.e., we
120  * have obtained an IIS-cover. For more details see the paper above.
121  *
122  *
123  * @subsection PREPROC Preprocessing
124  *
125  * Since each indicator constraint adds a linear constraint to the formulation, preprocessing of the
126  * linear constraints change the above approach as follows.
127  *
128  * The system as present in the formulation is the following (ignoring variables that are not
129  * contained in indicator constraints and the objective function):
130  * \f[
131  * \begin{array}{ll}
132  * & A x - s \leq b, \\
133  * & l \leq x \leq u, \\
134  * & s \leq 0.
135  * \end{array}
136  * \f]
137  * Note again that the requirement \f$s \leq 0\f$ leads to an infeasible system. Consider now the
138  * preprocessing of the linear constraint (aggregation, bound strengthening, etc.) and assume that
139  * this changes the above system to the following:
140  * \f[
141  * \begin{array}{ll}
142  * & \tilde{A} x - \tilde{B} s \leq \tilde{b}, \\
143  * & \tilde{l} \leq x \leq \tilde{u}, \\
144  * & s \leq 0. \\
145  * \end{array}
146  * \f]
147  * Note that we forbid multi-aggregation of the \f$s\f$ variables in order to be able to change their
148  * bounds in propagation/branching. The corresponding alternative system is the following:
149  * \f[
150  * \begin{array}{ll}
151  * & \tilde{A}^T w - r + t = 0,\\
152  * & - \tilde{B}^T w + v = 0,\\
153  * & b^T w - l^T r + u^T t = -1,\\
154  * & w, v, r, t \geq 0
155  * \end{array}
156  * \qquad \Leftrightarrow \qquad
157  * \begin{array}{ll}
158  * & \tilde{A}^T w - r + t = 0,\\
159  * & \tilde{B}^T w \geq 0,\\
160  * & b^T w - l^T r + u^T t = -1,\\
161  * & w, r, t \geq 0,
162  * \end{array}
163  * \f]
164  * where the second form arises by substituting \f$v \geq 0\f$. A closer look at this system reveals
165  * that it is not larger than the original one:
166  *
167  * - (Multi-)Aggregation of variables \f$x\f$ will remove these variables from the formulation, such that
168  * the corresponding column of \f$\tilde{A}\f$ (row of \f$\tilde{A}^T\f$) will be zero.
169  *
170  * - The rows of \f$\tilde{B}^T\f$ are not unit vectors, i.e., do not correspond to redundant
171  * nonnegativity constraints, only if the corresponding slack variables appear in an aggregation.
172  *
173  * Taken together, these two observations yield the conclusion that the new system is roughly as
174  * large as the original one.
175  *
176  * @note Because of possible (multi-)aggregation it might happen that the linear constraint
177  * corresponding to an indicator constraint becomes redundant and is deleted. From this we cannot
178  * conclude that the indicator constraint is redundant as well (i.e. always fulfilled), because the
179  * corresponding slack variable is still present and its setting to 0 might influence other
180  * (linear) constraints. Thus, we have to rely on the dual presolving of the linear constraints to
181  * detect this case: If the linear constraint is really redundant, i.e., is always fulfilled, it is
182  * deleted and the slack variable can be fixed to 0. In this case, the indicator constraint can be
183  * deleted as well.
184  *
185  * @todo Accept arbitrary ranged linear constraints as input (in particular: equations). Internally
186  * create two indicator constraints or correct alternative polyhedron accordingly (need to split the
187  * variables there, but not in original problem).
188  *
189  * @todo Treat variable upper bounds in a special way: Do not create the artificial slack variable,
190  * but directly enforce the propagations etc.
191  *
192  * @todo Turn off separation if the alternative polyhedron is infeasible and updateBounds is false.
193  *
194  * @todo Improve parsing of indicator constraint in CIP-format. Currently, we have to rely on a particular name, i.e.,
195  * the slack variable has to start with "indslack" and end with the name of the corresponding linear constraint.
196  *
197  * @todo Check whether one can further use the fact that the slack variable is aggregated.
198  */
199 
200 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
201 
202 #include "blockmemshell/memory.h"
203 #include "lpi/lpi.h"
204 #include "lpi/type_lpi.h"
205 #include "scip/expr_var.h"
206 #include "scip/expr_product.h"
207 #include "scip/cons_nonlinear.h"
208 #include "scip/cons_indicator.h"
209 #include "scip/cons_linear.h"
210 #include "scip/cons_logicor.h"
211 #include "scip/cons_varbound.h"
212 #include "scip/heur_indicator.h"
213 #include "scip/heur_trysol.h"
214 #include "scip/pub_conflict.h"
215 #include "scip/pub_cons.h"
216 #include "scip/pub_event.h"
217 #include "scip/pub_lp.h"
218 #include "scip/pub_message.h"
219 #include "scip/pub_misc.h"
220 #include "scip/pub_paramset.h"
221 #include "scip/pub_var.h"
222 #include "scip/scip_branch.h"
223 #include "scip/scip_conflict.h"
224 #include "scip/scip_cons.h"
225 #include "scip/scip_copy.h"
226 #include "scip/scip_cut.h"
227 #include "scip/scip_event.h"
228 #include "scip/scip_general.h"
229 #include "scip/scip_heur.h"
230 #include "scip/scip_lp.h"
231 #include "scip/scip_mem.h"
232 #include "scip/scip_message.h"
233 #include "scip/scip_nlp.h"
234 #include "scip/scip_numerics.h"
235 #include "scip/scip_param.h"
236 #include "scip/scip_prob.h"
237 #include "scip/scip_probing.h"
238 #include "scip/scip_sol.h"
239 #include "scip/scip_solve.h"
240 #include "scip/scip_solvingstats.h"
241 #include "scip/scip_tree.h"
242 #include "scip/scip_var.h"
243 #include <string.h>
244 
245 /* #define SCIP_OUTPUT */
246 /* #define SCIP_ENABLE_IISCHECK */
247 
248 /* constraint handler properties */
249 #define CONSHDLR_NAME "indicator"
250 #define CONSHDLR_DESC "indicator constraint handler"
251 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
252 #define CONSHDLR_ENFOPRIORITY -100 /**< priority of the constraint handler for constraint enforcing */
253 #define CONSHDLR_CHECKPRIORITY -6000000 /**< priority of the constraint handler for checking feasibility */
254 #define CONSHDLR_SEPAFREQ 10 /**< frequency for separating cuts; zero means to separate only in the root node */
255 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
256 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
257  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
258 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
259 #define CONSHDLR_DELAYSEPA FALSE /**< Should separation method be delayed, if other separators found cuts? */
260 #define CONSHDLR_DELAYPROP FALSE /**< Should propagation method be delayed, if other propagators found reductions? */
261 #define CONSHDLR_NEEDSCONS TRUE /**< Should the constraint handler be skipped, if no constraints are available? */
263 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_FAST
264 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
266 
267 /* event handler properties */
268 #define EVENTHDLR_BOUND_NAME "indicatorbound"
269 #define EVENTHDLR_BOUND_DESC "bound change event handler for indicator constraints"
271 #define EVENTHDLR_RESTART_NAME "indicatorrestart"
272 #define EVENTHDLR_RESTART_DESC "force restart if absolute gap is 1 or enough binary variables have been fixed"
274 
275 /* conflict handler properties */
276 #define CONFLICTHDLR_NAME "indicatorconflict"
277 #define CONFLICTHDLR_DESC "replace slack variables and generate logicor constraints"
278 #define CONFLICTHDLR_PRIORITY 200000
280 /* upgrade properties */
281 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
283 /* default values for parameters */
284 #define DEFAULT_BRANCHINDICATORS FALSE /**< Branch on indicator constraints in enforcing? */
285 #define DEFAULT_GENLOGICOR FALSE /**< Generate logicor constraints instead of cuts? */
286 #define DEFAULT_ADDCOUPLING TRUE /**< Add coupling constraints or rows if big-M is small enough? */
287 #define DEFAULT_MAXCOUPLINGVALUE 1e4 /**< maximum coefficient for binary variable in coupling constraint */
288 #define DEFAULT_ADDCOUPLINGCONS FALSE /**< Add initial variable upper bound constraints, if 'addcoupling' is true? */
289 #define DEFAULT_SEPACOUPLINGCUTS TRUE /**< Should the coupling inequalities be separated dynamically? */
290 #define DEFAULT_SEPACOUPLINGLOCAL FALSE /**< Allow to use local bounds in order to separate coupling inequalities? */
291 #define DEFAULT_SEPACOUPLINGVALUE 1e4 /**< maximum coefficient for binary variable in separated coupling constraint */
292 #define DEFAULT_SEPAALTERNATIVELP FALSE /**< Separate using the alternative LP? */
293 #define DEFAULT_SEPAPERSPECTIVE FALSE /**< Separate cuts based on perspective formulation? */
294 #define DEFAULT_SEPAPERSPLOCAL TRUE /**< Allow to use local bounds in order to separate perspectice cuts? */
295 #define DEFAULT_MAXSEPANONVIOLATED 3 /**< maximal number of separated non violated IISs, before separation is stopped */
296 #define DEFAULT_TRYSOLFROMCOVER FALSE /**< Try to construct a feasible solution from a cover? */
297 #define DEFAULT_UPGRADELINEAR FALSE /**< Try to upgrade linear constraints to indicator constraints? */
298 #define DEFAULT_USEOTHERCONSS FALSE /**< Collect other constraints to alternative LP? */
299 #define DEFAULT_USEOBJECTIVECUT FALSE /**< Use objective cut with current best solution to alternative LP? */
300 #define DEFAULT_UPDATEBOUNDS FALSE /**< Update bounds of original variables for separation? */
301 #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) */
302 #define DEFAULT_MAXSEPACUTS 100 /**< maximal number of cuts separated per separation round */
303 #define DEFAULT_MAXSEPACUTSROOT 2000 /**< maximal number of cuts separated per separation round in the root node */
304 #define DEFAULT_REMOVEINDICATORS FALSE /**< Remove indicator constraint if corresponding variable bound constraint has been added? */
305 #define DEFAULT_GENERATEBILINEAR FALSE /**< Do not generate indicator constraint, but a bilinear constraint instead? */
306 #define DEFAULT_SCALESLACKVAR FALSE /**< Scale slack variable coefficient at construction time? */
307 #define DEFAULT_NOLINCONSCONT FALSE /**< Decompose problem (do not generate linear constraint if all variables are continuous)? */
308 #define DEFAULT_TRYSOLUTIONS TRUE /**< Try to make solutions feasible by setting indicator variables? */
309 #define DEFAULT_ENFORCECUTS FALSE /**< In enforcing try to generate cuts (only if sepaalternativelp is true)? */
310 #define DEFAULT_DUALREDUCTIONS TRUE /**< Should dual reduction steps be performed? */
311 #define DEFAULT_ADDOPPOSITE FALSE /**< Add opposite inequality in nodes in which the binary variable has been fixed to 0? */
312 #define DEFAULT_CONFLICTSUPGRADE FALSE /**< Try to upgrade bounddisjunction conflicts by replacing slack variables? */
313 #define DEFAULT_FORCERESTART FALSE /**< Force restart if absolute gap is 1 or enough binary variables have been fixed? */
314 #define DEFAULT_RESTARTFRAC 0.9 /**< fraction of binary variables that need to be fixed before restart occurs (in forcerestart) */
316 
317 /* other values */
318 #define OBJEPSILON 0.001 /**< value to add to objective in alt. LP if the binary variable is 1 to get small IISs */
319 #define SEPAALTTHRESHOLD 10 /**< only separate IIS cuts if the number of separated coupling cuts is less than this value */
320 #define MAXROUNDINGROUNDS 1 /**< maximal number of rounds that produced cuts in separation */
322 
323 /** constraint data for indicator constraints */
324 struct SCIP_ConsData
325 {
326  SCIP_VAR* binvar; /**< binary variable for indicator constraint */
327  SCIP_VAR* slackvar; /**< slack variable of inequality of indicator constraint */
328  SCIP_CONS* lincons; /**< linear constraint corresponding to indicator constraint */
329  SCIP_Bool activeone; /**< whether the constraint is active on 1 or 0 */
330  SCIP_Bool lessthanineq; /**< whether the original linear constraint is less-than-rhs or greater-than-rhs */
331  int nfixednonzero; /**< number of variables among binvar and slackvar fixed to be nonzero */
332  int colindex; /**< column index in alternative LP */
333  unsigned int linconsactive:1; /**< whether linear constraint and slack variable are active */
334  unsigned int implicationadded:1; /**< whether corresponding implication has been added */
335  unsigned int slacktypechecked:1; /**< whether it has been checked to convert the slack variable to be implicit integer */
336 };
337 
338 
339 /** indicator constraint handler data */
340 struct SCIP_ConshdlrData
341 {
342  SCIP_EVENTHDLR* eventhdlrbound; /**< event handler for bound change events */
343  SCIP_EVENTHDLR* eventhdlrrestart; /**< event handler for performing restarts */
344  SCIP_Bool removable; /**< whether the separated cuts should be removable */
345  SCIP_Bool scaled; /**< if first row of alt. LP has been scaled */
346  SCIP_Bool objindicatoronly; /**< whether the objective is nonzero only for indicator variables */
347  SCIP_Bool objothervarsonly; /**< whether the objective is nonzero only for non-indicator variables */
348  SCIP_Real minabsobj; /**< minimum absolute nonzero objective of indicator variables */
349  SCIP_LPI* altlp; /**< alternative LP for cut separation */
350  int nrows; /**< # rows in the alt. LP corr. to original variables in linear constraints and slacks */
351  int nlbbounds; /**< # lower bounds of original variables */
352  int nubbounds; /**< # upper bounds of original variables */
353  SCIP_HASHMAP* varhash; /**< hash map from variable to row index in alternative LP */
354  SCIP_HASHMAP* lbhash; /**< hash map from variable to index of lower bound column in alternative LP */
355  SCIP_HASHMAP* ubhash; /**< hash map from variable to index of upper bound column in alternative LP */
356  SCIP_HASHMAP* slackhash; /**< hash map from slack variable to row index in alternative LP */
357  SCIP_HASHMAP* binvarhash; /**< hash map from binary indicator variable to indicator constraint */
358  int nslackvars; /**< # slack variables */
359  int niiscutsgen; /**< number of IIS-cuts generated */
360  int nperspcutsgen; /**< number of cuts based on perspective formulation generated */
361  int objcutindex; /**< index of objective cut in alternative LP (-1 if not added) */
362  SCIP_Real objupperbound; /**< best upper bound on objective known */
363  SCIP_Real objaltlpbound; /**< upper objective bound stored in alternative LP (infinity if not added) */
364  int maxroundingrounds; /**< maximal number of rounds that produced cuts in separation */
365  SCIP_Real roundingminthres; /**< minimal value for rounding in separation */
366  SCIP_Real roundingmaxthres; /**< maximal value for rounding in separation */
367  SCIP_Real roundingoffset; /**< offset for rounding in separation */
368  SCIP_Bool branchindicators; /**< Branch on indicator constraints in enforcing? */
369  SCIP_Bool genlogicor; /**< Generate logicor constraints instead of cuts? */
370  SCIP_Bool addcoupling; /**< whether the coupling inequalities should be added at the beginning */
371  SCIP_Bool addcouplingcons; /**< Add initial variable upper bound constraints, if 'addcoupling' is true? */
372  SCIP_Bool sepacouplingcuts; /**< Should the coupling inequalities be separated dynamically? */
373  SCIP_Bool sepacouplinglocal; /**< Allow to use local bounds in order to separate coupling inequalities? */
374  SCIP_Bool sepaperspective; /**< Separate cuts based on perspective formulation? */
375  SCIP_Bool sepapersplocal; /**< Allow to use local bounds in order to separate perspectice cuts? */
376  SCIP_Bool removeindicators; /**< Remove indicator constraint if corresponding variable bound constraint has been added? */
377  SCIP_Bool updatebounds; /**< whether the bounds of the original variables should be changed for separation */
378  SCIP_Bool trysolutions; /**< Try to make solutions feasible by setting indicator variables? */
379  SCIP_Bool enforcecuts; /**< in enforcing try to generate cuts (only if sepaalternativelp is true) */
380  SCIP_Bool dualreductions; /**< Should dual reduction steps be performed? */
381  SCIP_Bool addopposite; /**< Add opposite inequality in nodes in which the binary variable has been fixed to 0? */
382  SCIP_Bool generatebilinear; /**< Do not generate indicator constraint, but a bilinear constraint instead? */
383  SCIP_Bool scaleslackvar; /**< Scale slack variable coefficient at construction time? */
384  SCIP_Bool conflictsupgrade; /**< Try to upgrade bounddisjunction conflicts by replacing slack variables? */
385  SCIP_Bool performedrestart; /**< whether a restart has been performed already */
386  int maxsepacuts; /**< maximal number of cuts separated per separation round */
387  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in root node */
388  int maxsepanonviolated; /**< maximal number of separated non violated IISs, before separation is stopped */
389  int nbinvarszero; /**< binary variables globally fixed to zero */
390  int ninitconss; /**< initial number of indicator constraints (needed in event handlers) */
391  SCIP_Real maxcouplingvalue; /**< maximum coefficient for binary variable in initial coupling constraint */
392  SCIP_Real sepacouplingvalue; /**< maximum coefficient for binary variable in separated coupling constraint */
393  SCIP_Real maxconditionaltlp; /**< maximum estimated condition number of the alternative LP to trust its solution */
394  SCIP_Real restartfrac; /**< fraction of binary variables that need to be fixed before restart occurs (in forcerestart) */
395  SCIP_HEUR* heurtrysol; /**< trysol heuristic */
396  SCIP_Bool addedcouplingcons; /**< whether the coupling constraints have been added already */
397  SCIP_CONS** addlincons; /**< additional linear constraints that should be added to the alternative LP */
398  int naddlincons; /**< number of additional constraints */
399  int maxaddlincons; /**< maximal number of additional constraints */
400  SCIP_Bool useotherconss; /**< Collect other constraints to alternative LP? */
401  SCIP_Bool useobjectivecut; /**< Use objective cut with current best solution to alternative LP? */
402  SCIP_Bool trysolfromcover; /**< Try to construct a feasible solution from a cover? */
403  SCIP_Bool upgradelinear; /**< Try to upgrade linear constraints to indicator constraints? */
404  char normtype; /**< norm type for cut computation */
405  /* parameters that should not be changed after problem stage: */
406  SCIP_Bool sepaalternativelp; /**< Separate using the alternative LP? */
407  SCIP_Bool sepaalternativelp_; /**< used to store the sepaalternativelp parameter */
408  SCIP_Bool nolinconscont; /**< decompose problem - do not generate linear constraint if all variables are continuous */
409  SCIP_Bool nolinconscont_; /**< used to store the nolinconscont parameter */
410  SCIP_Bool forcerestart; /**< Force restart if absolute gap is 1 or enough binary variables have been fixed? */
411  SCIP_Bool forcerestart_; /**< used to store the forcerestart parameter */
412 };
413 
414 
415 /** indicator conflict handler data */
416 struct SCIP_ConflicthdlrData
417 {
418  SCIP_CONSHDLR* conshdlr; /**< indicator constraint handler */
419  SCIP_CONSHDLRDATA* conshdlrdata; /**< indicator constraint handler data */
420 };
421 
422 
423 /** type of enforcing/separation call */
425 {
426  SCIP_TYPE_ENFOLP = 0, /**< enforce LP */
427  SCIP_TYPE_ENFOPS = 1, /**< enforce pseudo solution */
428  SCIP_TYPE_ENFORELAX = 2, /**< enforce relaxation solution */
429  SCIP_TYPE_SEPALP = 3, /**< separate LP */
430  SCIP_TYPE_SEPARELAX = 4, /**< separate relaxation solution */
431  SCIP_TYPE_SEPASOL = 5 /**< separate relaxation solution */
432 };
435 
436 /* macro for parameters */
437 #define SCIP_CALL_PARAM(x) /*lint -e527 */ do \
438 { \
439  SCIP_RETCODE _restat_; \
440  if ( (_restat_ = (x)) != SCIP_OKAY && (_restat_ != SCIP_PARAMETERUNKNOWN) ) \
441  { \
442  SCIPerrorMessage("[%s:%d] Error <%d> in function call\n", __FILE__, __LINE__, _restat_); \
443  SCIPABORT(); \
444  return _restat_; \
445  } \
446 } \
447 while ( FALSE )
448 
449 
450 /* ---------------- Callback methods of event handlers ---------------- */
451 
452 /** execute the event handler for getting variable bound changes
453  *
454  * We update the number of variables fixed to be nonzero.
455  */
456 static
457 SCIP_DECL_EVENTEXEC(eventExecIndicatorBound)
458 {
459  SCIP_EVENTTYPE eventtype;
460  SCIP_CONSDATA* consdata;
461  SCIP_Real oldbound;
462  SCIP_Real newbound;
463 
464  assert( eventhdlr != NULL );
465  assert( eventdata != NULL );
466  assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_BOUND_NAME) == 0 );
467  assert( event != NULL );
468 
469  consdata = (SCIP_CONSDATA*)eventdata;
470  assert( consdata != NULL );
471  assert( 0 <= consdata->nfixednonzero && consdata->nfixednonzero <= 2 );
472  assert( consdata->linconsactive );
473 
474  oldbound = SCIPeventGetOldbound(event);
475  newbound = SCIPeventGetNewbound(event);
476 
477  eventtype = SCIPeventGetType(event);
478  switch ( eventtype )
479  {
481  /* if variable is now fixed to be positive */
482  if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
483  ++(consdata->nfixednonzero);
484 #ifdef SCIP_MORE_DEBUG
485  SCIPdebugMsg(scip, "Changed lower bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
486  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
487 #endif
488  break;
489 
491  /* if variable is now fixed to be negative */
492  if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
493  ++(consdata->nfixednonzero);
494 #ifdef SCIP_MORE_DEBUG
495  SCIPdebugMsg(scip, "Changed upper bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
496  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
497 #endif
498  break;
499 
501  /* if variable is not fixed to be positive anymore */
502  if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
503  --(consdata->nfixednonzero);
504 #ifdef SCIP_MORE_DEBUG
505  SCIPdebugMsg(scip, "Changed lower bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
506  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
507 #endif
508  break;
509 
511  /* if variable is not fixed to be negative anymore */
512  if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
513  --(consdata->nfixednonzero);
514 #ifdef SCIP_MORE_DEBUG
515  SCIPdebugMsg(scip, "Changed upper bound of variable <%s> from %g to %g (nfixednonzero: %d).\n",
516  SCIPvarGetName(SCIPeventGetVar(event)), oldbound, newbound, consdata->nfixednonzero);
517 #endif
518  break;
519 
520  default:
521  SCIPerrorMessage("Invalid event type.\n");
522  SCIPABORT();
523  return SCIP_INVALIDDATA; /*lint !e527*/
524  }
525  assert( 0 <= consdata->nfixednonzero && consdata->nfixednonzero <= 2 );
526 
527  return SCIP_OKAY;
528 }
529 
530 
531 /** exec the event handler for forcing a restart
532  *
533  * There are two cases in which we perform a (user) restart:
534  * - If we have a max FS instance, i.e., the objective is 1 for indicator variables and 0 otherwise,
535  * we can force a restart if the gap is 1. In this case, the remaining work consists of proving
536  * infeasibility of the non-fixed indicators.
537  * - If a large fraction of the binary indicator variables have been globally fixed, it makes sense
538  * to force a restart.
539  */
540 static
541 SCIP_DECL_EVENTEXEC(eventExecIndicatorRestart)
542 {
543  SCIP_CONSHDLRDATA* conshdlrdata;
544  SCIP_EVENTTYPE eventtype;
545 
546  assert( scip != NULL );
547  assert( eventhdlr != NULL );
548  assert( eventdata != NULL );
549  assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_RESTART_NAME) == 0 );
550  assert( event != NULL );
551 
552  conshdlrdata = (SCIP_CONSHDLRDATA*)eventdata;
553  assert( conshdlrdata != NULL );
554  assert( conshdlrdata->forcerestart );
555 
556  eventtype = SCIPeventGetType(event);
557  switch ( eventtype )
558  {
561  {
562 #ifndef NDEBUG
563  SCIP_Real oldbound;
564  SCIP_Real newbound;
565 
567  oldbound = SCIPeventGetOldbound(event);
568  newbound = SCIPeventGetNewbound(event);
569  assert( SCIPisIntegral(scip, oldbound) );
570  assert( SCIPisIntegral(scip, newbound) );
571  assert( ! SCIPisEQ(scip, oldbound, newbound) );
572  assert( SCIPisZero(scip, oldbound) || SCIPisEQ(scip, oldbound, 1.0) );
573  assert( SCIPisZero(scip, newbound) || SCIPisEQ(scip, newbound, 1.0) );
574 #endif
575 
576  /* do not treat this case if we have performed a restart already */
577  if ( conshdlrdata->performedrestart )
578  return SCIP_OKAY;
579 
580  /* variable is now fixed */
581  ++(conshdlrdata->nbinvarszero);
582  SCIPdebugMsg(scip, "Fixed variable <%s> (nbinvarszero: %d, total: %d).\n",
583  SCIPvarGetName(SCIPeventGetVar(event)), conshdlrdata->nbinvarszero, conshdlrdata->ninitconss);
584 
586  break;
587 
588  /* if enough variables have been fixed */
589  if ( conshdlrdata->nbinvarszero > (int) ((SCIP_Real) conshdlrdata->ninitconss * conshdlrdata->restartfrac) )
590  {
592  "Forcing restart, since %d binary variables among %d have been fixed.\n", conshdlrdata->nbinvarszero, conshdlrdata->ninitconss);
594 
595  /* drop event */
596  if ( conshdlrdata->objindicatoronly )
597  {
598  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, eventhdlr, (SCIP_EVENTDATA*) conshdlrdata, -1) );
599  }
600  conshdlrdata->performedrestart = TRUE;
601  }
602  break;
603  }
604 
606  assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
607  assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0 ) );
608 
610  break;
611 
612  if ( ! conshdlrdata->objindicatoronly )
613  break;
614 
615  /* if the absolute gap is equal to minabsobj */
616  if ( SCIPisEQ(scip, REALABS(SCIPgetPrimalbound(scip) - SCIPgetDualbound(scip)), conshdlrdata->minabsobj) )
617  {
618  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Forcing restart, since the absolute gap is %f.\n", conshdlrdata->minabsobj);
620 
621  /* use inference branching, since the objective is not meaningful */
622  if ( SCIPfindBranchrule(scip, "inference") != NULL && !SCIPisParamFixed(scip, "branching/inference/priority") )
623  {
624  SCIP_CALL( SCIPsetIntParam(scip, "branching/inference/priority", INT_MAX/4) );
625  }
626 
627  /* drop event */
628  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, eventhdlr, (SCIP_EVENTDATA*) conshdlrdata, -1) );
629  conshdlrdata->performedrestart = TRUE;
630  }
631  break;
632 
633  default:
634  SCIPerrorMessage("invalid event type.\n");
635  SCIPABORT();
636  return SCIP_INVALIDDATA; /*lint !e527*/
637  }
638 
639  return SCIP_OKAY;
640 }
641 
642 
643 /* ------------------------ conflict handler ---------------------------------*/
644 
645 /** destructor of conflict handler to free conflict handler data (called when SCIP is exiting) */
646 static
647 SCIP_DECL_CONFLICTFREE(conflictFreeIndicator)
648 {
649  SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
650 
651  assert( scip != NULL );
652  assert( conflicthdlr != NULL );
653  assert( strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0 );
654 
655  conflicthdlrdata = SCIPconflicthdlrGetData(conflicthdlr);
656  SCIPfreeBlockMemory(scip, &conflicthdlrdata);
657 
658  return SCIP_OKAY;
659 }
660 
661 
662 /** conflict processing method of conflict handler (called when conflict was found)
663  *
664  * In this conflict handler we try to replace slack variables by binary indicator variables and
665  * generate a logicor constraint if possible.
666  *
667  * @todo Extend to integral case.
668  */
669 static
670 SCIP_DECL_CONFLICTEXEC(conflictExecIndicator)
671 { /*lint --e{715}*/
672  SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
673  SCIP_Bool haveslack;
674  SCIP_VAR* var;
675  int i;
676 
677  assert( conflicthdlr != NULL );
678  assert( strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0 );
679  assert( bdchginfos != NULL || nbdchginfos == 0 );
680  assert( result != NULL );
681 
682  /* don't process already resolved conflicts */
683  if ( resolved )
684  {
685  *result = SCIP_DIDNOTRUN;
686  return SCIP_OKAY;
687  }
688 
689  SCIPdebugMsg(scip, "Indicator conflict handler.\n");
690 
691  conflicthdlrdata = SCIPconflicthdlrGetData(conflicthdlr);
692  assert( conflicthdlrdata != NULL );
693 
694  /* possibly skip conflict handler */
695  if ( ! ((SCIP_CONFLICTHDLRDATA*) conflicthdlrdata)->conshdlrdata->conflictsupgrade )
696  return SCIP_OKAY;
697 
698  *result = SCIP_DIDNOTFIND;
699 
700  /* check whether there seems to be one slack variable and all other variables are binary */
701  haveslack = FALSE;
702  for (i = 0; i < nbdchginfos; ++i)
703  {
704  assert( bdchginfos != NULL ); /* for flexelint */
705  assert( bdchginfos[i] != NULL );
706 
707  var = SCIPbdchginfoGetVar(bdchginfos[i]);
708 
709  /* quick check for slack variable that is implicitly integral or continuous */
711  {
712  /* check string */
713  if ( strstr(SCIPvarGetName(var), "indslack") != NULL )
714  {
715  /* make sure that the slack variable occurs with its lower bound */
717  break;
718 
719  /* make sure that the lower bound is 0 */
720  if ( ! SCIPisFeasZero(scip, SCIPbdchginfoGetNewbound(bdchginfos[i])) )
721  break;
722 
723  haveslack = TRUE;
724  continue;
725  }
726  }
727 
728  /* we only treat binary variables (other than slack variables) */
729  if ( ! SCIPvarIsBinary(var) )
730  break;
731  }
732 
733  /* if we have found at least one slack variable and all other variables are binary */
734  if ( haveslack && i == nbdchginfos )
735  {
736  SCIP_CONS** conss;
737  SCIP_VAR** vars;
738  int nconss;
739  int j;
740 
741  SCIPdebugMsg(scip, "Found conflict involving slack variables that can be remodelled.\n");
742 
743  assert( conflicthdlrdata->conshdlr != NULL );
744  assert( strcmp(SCIPconshdlrGetName(conflicthdlrdata->conshdlr), CONSHDLR_NAME) == 0 );
745 
746  nconss = SCIPconshdlrGetNConss(conflicthdlrdata->conshdlr);
747  conss = SCIPconshdlrGetConss(conflicthdlrdata->conshdlr);
748 
749  /* create array of variables in conflict constraint */
750  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nbdchginfos) );
751  for (i = 0; i < nbdchginfos; ++i)
752  {
753  assert( bdchginfos != NULL ); /* for flexelint */
754  assert( bdchginfos[i] != NULL );
755 
756  var = SCIPbdchginfoGetVar(bdchginfos[i]);
757 
758  SCIPdebugMsg(scip, " <%s> %s %g\n", SCIPvarGetName(var), SCIPbdchginfoGetBoundtype(bdchginfos[i]) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
759  SCIPbdchginfoGetNewbound(bdchginfos[i]));
760 
761  /* quick check for slack variable that is implicitly integral or continuous */
762  if ( (SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS) && strstr(SCIPvarGetName(var), "indslack") != NULL )
763  {
764  SCIP_VAR* slackvar;
765 
766  /* search for slack variable */
767  for (j = 0; j < nconss; ++j)
768  {
769  assert( conss[j] != NULL );
770  slackvar = SCIPgetSlackVarIndicator(conss[j]);
771  assert( slackvar != NULL );
772 
773  /* check whether we found the variable */
774  if ( slackvar == var )
775  {
776  /* replace slack variable by binary variable */
777  var = SCIPgetBinaryVarIndicator(conss[j]);
778  break;
779  }
780  }
781 
782  /* check whether we found the slack variable */
783  if ( j >= nconss )
784  {
785  SCIPdebugMsg(scip, "Could not find slack variable <%s>.\n", SCIPvarGetName(var));
786  break;
787  }
788  }
789  else
790  {
791  /* if the variable is fixed to one in the conflict set, we have to use its negation */
792  if ( SCIPbdchginfoGetNewbound(bdchginfos[i]) > 0.5 )
793  {
794  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
795  }
796  }
797 
798  vars[i] = var;
799  }
800 
801  /* whether all slack variables have been found */
802  if ( i == nbdchginfos )
803  {
804  SCIP_CONS* cons;
805  char consname[SCIP_MAXSTRLEN];
806 
807  SCIPdebugMsg(scip, "Generated logicor conflict constraint.\n");
808 
809  /* create a logicor constraint out of the conflict set */
810  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cf%d_%" SCIP_LONGINT_FORMAT, SCIPgetNRuns(scip), SCIPgetNConflictConssApplied(scip));
811  SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, consname, nbdchginfos, vars,
812  FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) );
813 
814 #ifdef SCIP_OUTPUT
815  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
816  SCIPinfoMessage(scip, NULL, ";\n");
817 #endif
818 
819  /* add constraint to SCIP */
820  SCIP_CALL( SCIPaddConflict(scip, node, cons, validnode, conftype, cutoffinvolved) );
821 
822  *result = SCIP_CONSADDED;
823  }
824 
825  /* free temporary memory */
826  SCIPfreeBufferArray(scip, &vars);
827  }
828 
829  return SCIP_OKAY;
830 }
831 
832 
833 /* ------------------------ parameter handling ---------------------------------*/
834 
835 /** check whether we transfer a changed parameter to the given value
836  *
837  * @see paramChangedIndicator()
838  */
839 static
841  SCIP* scip, /**< SCIP data structure */
842  SCIP_PARAM* param, /**< parameter */
843  const char* name, /**< parameter name to check */
844  SCIP_Bool newvalue, /**< new value */
845  SCIP_Bool* value /**< old and possibly changed value of parameter */
846  )
847 {
848  const char* paramname;
849 
850  assert( scip != NULL );
851  assert( param != NULL );
852  assert( name != NULL );
853  assert( value != NULL );
854 
855  if ( SCIPparamGetType(param) != SCIP_PARAMTYPE_BOOL )
856  return SCIP_OKAY;
857 
858  if ( *value == newvalue )
859  return SCIP_OKAY;
860 
861  paramname = SCIPparamGetName(param);
862  assert( paramname != NULL );
863 
864  /* check whether the change parameter corresponds to our name to check */
865  if ( strcmp(paramname, name) == 0 )
866  {
867  /* check stage and possibly ignore parameter change */
868  if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM )
869  {
870  SCIPwarningMessage(scip, "Cannot change parameter <%s> stage %d - reset to old value %s.\n", name, SCIPgetStage(scip), *value ? "true" : "false");
871  /* Note that the following command will create a recursive call, but then *value == newvalue above. */
872  SCIP_CALL( SCIPchgBoolParam(scip, param, *value) );
873  }
874  else
875  {
876  /* otherwise copy value */
877  *value = newvalue;
878  }
879  }
880 
881  return SCIP_OKAY;
882 }
883 
884 
885 /** called after a parameter has been changed */
886 static
887 SCIP_DECL_PARAMCHGD(paramChangedIndicator)
888 {
889  SCIP_CONSHDLR* conshdlr;
890  SCIP_CONSHDLRDATA* conshdlrdata;
891 
892  assert( scip != NULL );
893  assert( param != NULL );
894 
895  /* get indicator constraint handler */
896  conshdlr = SCIPfindConshdlr(scip, "indicator");
897  assert( conshdlr != NULL );
898 
899  /* get constraint handler data */
900  conshdlrdata = SCIPconshdlrGetData(conshdlr);
901  assert( conshdlrdata != NULL );
902 
903  SCIP_CALL( checkTransferBoolParam(scip, param, "constraints/indicator/sepaalternativelp", conshdlrdata->sepaalternativelp_, &conshdlrdata->sepaalternativelp) );
904  SCIP_CALL( checkTransferBoolParam(scip, param, "constraints/indicator/forcerestart", conshdlrdata->forcerestart_, &conshdlrdata->forcerestart) );
905  SCIP_CALL( checkTransferBoolParam(scip, param, "constraints/indicator/nolinconscont", conshdlrdata->nolinconscont_, &conshdlrdata->nolinconscont) );
906 
907  return SCIP_OKAY;
908 }
909 
910 
911 /* ------------------------ debugging routines ---------------------------------*/
912 
913 #ifdef SCIP_ENABLE_IISCHECK
914 /** Check that indicator constraints corresponding to nonnegative entries in @a vector are infeasible in original problem
915  *
916  * @note This function will probably fail if the has been presolved by the cons_linear presolver. To make it complete
917  * we would have to substitute active variables.
918  */
919 static
920 SCIP_RETCODE checkIIS(
921  SCIP* scip, /**< SCIP pointer */
922  int nconss, /**< number of constraints */
923  SCIP_CONS** conss, /**< indicator constraints */
924  SCIP_Real* vector /**< vector */
925  )
926 {
927  SCIP_CONSHDLRDATA* conshdlrdata;
928  SCIP_CONSHDLR* conshdlr;
929  SCIP_HASHMAP* varhash; /* hash map from variable to column index in auxiliary LP */
930  SCIP_LPI* lp;
931  int nvars = 0;
932  int c;
933 
934  assert( scip != NULL );
935  assert( vector != NULL );
936 
937  SCIPdebugMsg(scip, "Checking IIS ...\n");
938 
939  /* now check indicator constraints */
940  conshdlr = SCIPfindConshdlr(scip, "indicator");
941  assert( conshdlr != NULL );
942 
943  conshdlrdata = SCIPconshdlrGetData(conshdlr);
944  assert( conshdlrdata != NULL );
945 
946  conss = SCIPconshdlrGetConss(conshdlr);
947  nconss = SCIPconshdlrGetNConss(conshdlr);
948 
949  /* create LP */
951 
952  /* set up hash map */
953  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
954 
955  /* loop through indicator constraints */
956  for (c = 0; c < nconss; ++c)
957  {
958  SCIP_CONSDATA* consdata;
959  consdata = SCIPconsGetData(conss[c]);
960  assert( consdata != NULL );
961 
962  /* check whether constraint should be included */
963  if ( consdata->colindex >= 0 && (! SCIPisFeasZero(scip, vector[consdata->colindex]) || ! SCIPconsIsEnabled(conss[c])) )
964  {
965  SCIP_CONS* lincons;
966  SCIP_VAR** linvars;
967  SCIP_Real* linvals;
968  SCIP_Real linrhs;
969  SCIP_Real linlhs;
970  SCIP_VAR* slackvar;
971  int nlinvars;
972  SCIP_Real sign = 1.0;
973  int matbeg;
974  int* matind;
975  SCIP_Real* matval;
976  SCIP_VAR** newvars;
977  int nnewvars;
978  SCIP_Real lhs;
979  SCIP_Real rhs;
980  int cnt;
981  int v;
982 
983  lincons = consdata->lincons;
984  assert( lincons != NULL );
985  assert( ! SCIPconsIsEnabled(conss[c]) || SCIPconsIsActive(lincons) );
986  assert( ! SCIPconsIsEnabled(conss[c]) || SCIPconsIsEnabled(lincons) );
987 
988  slackvar = consdata->slackvar;
989  assert( slackvar != NULL );
990 
991  /* if the slack variable is aggregated (multi-aggregation should not happen) */
992  assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
993  if ( SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
994  {
995  SCIP_VAR* var;
996  SCIP_Real scalar = 1.0;
997  SCIP_Real constant = 0.0;
998 
999  var = slackvar;
1000 
1001  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
1002  assert( ! SCIPisZero(scip, scalar) );
1003 
1004  /* SCIPdebugMsg(scip, "slack variable aggregated (scalar: %f, constant: %f)\n", scalar, constant); */
1005 
1006  /* otherwise construct a linear constraint */
1007  SCIP_CALL( SCIPallocBufferArray(scip, &linvars, 1) );
1008  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, 1) );
1009  linvars[0] = var;
1010  linvals[0] = scalar;
1011  nlinvars = 1;
1012  linlhs = -SCIPinfinity(scip);
1013  linrhs = constant;
1014  }
1015  else
1016  {
1017  /* in this case, the linear constraint is directly usable */
1018  linvars = SCIPgetVarsLinear(scip, lincons);
1019  linvals = SCIPgetValsLinear(scip, lincons);
1020  nlinvars = SCIPgetNVarsLinear(scip, lincons);
1021  linlhs = SCIPgetLhsLinear(scip, lincons);
1022  linrhs = SCIPgetRhsLinear(scip, lincons);
1023  }
1024 
1025  /* adapt rhs of linear constraint */
1026  assert( SCIPisInfinity(scip, -linlhs) || SCIPisInfinity(scip, linrhs) );
1027  if ( SCIPisInfinity(scip, linrhs) )
1028  {
1029  linrhs = -linlhs;
1030  assert( linrhs > -SCIPinfinity(scip) );
1031  sign = -1.0;
1032  }
1033 
1034  SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4*nlinvars) );
1035  SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4*nlinvars) );
1036  SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nlinvars) );
1037 
1038  /* set up row */
1039  nnewvars = 0;
1040  for (v = 0; v < nlinvars; ++v)
1041  {
1042  SCIP_VAR* var;
1043  var = linvars[v];
1044  assert( var != NULL );
1045 
1046  /* skip slack variable */
1047  if ( var == slackvar )
1048  continue;
1049 
1050  /* if variable is new */
1051  if ( ! SCIPhashmapExists(varhash, var) )
1052  {
1053  /* add variable in map */
1054  SCIP_CALL( SCIPhashmapInsertInt(varhash, var, nvars) );
1055  assert( nvars == SCIPhashmapGetImageInt(varhash, var) );
1056  /* SCIPdebugMsg(scip, "Inserted variable <%s> into hashmap (%d).\n", SCIPvarGetName(var), nvars); */
1057  nvars++;
1058 
1059  /* store new variables */
1060  newvars[nnewvars++] = var;
1061  }
1062  assert( SCIPhashmapExists(varhash, var) );
1063  }
1064 
1065  /* add new columns */
1066  if ( nnewvars > 0 )
1067  {
1068  SCIP_Real* lb;
1069  SCIP_Real* ub;
1070  SCIP_Real* obj;
1071  char** colnames;
1072 
1073  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nnewvars) );
1074  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nnewvars) );
1075  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nnewvars) );
1076  SCIP_CALL( SCIPallocBufferArray(scip, &colnames, nnewvars) );
1077 
1078  for (v = 0; v < nnewvars; ++v)
1079  {
1080  SCIP_VAR* var;
1081  var = newvars[v];
1082  obj[v] = 0.0;
1083  lb[v] = SCIPvarGetLbLocal(var);
1084  ub[v] = SCIPvarGetUbLocal(var);
1085  SCIP_CALL( SCIPallocBufferArray(scip, &(colnames[v]), SCIP_MAXSTRLEN) ); /*lint !e866*/
1086  (void) SCIPsnprintf(colnames[v], SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var));
1087  }
1088 
1089  /* now add columns */
1090  SCIP_CALL( SCIPlpiAddCols(lp, nnewvars, obj, lb, ub, colnames, 0, NULL, NULL, NULL) );
1091 
1092  for (v = nnewvars - 1; v >= 0; --v)
1093  {
1094  SCIPfreeBufferArray(scip, &(colnames[v]));
1095  }
1096  SCIPfreeBufferArray(scip, &colnames);
1097  SCIPfreeBufferArray(scip, &obj);
1098  SCIPfreeBufferArray(scip, &ub);
1099  SCIPfreeBufferArray(scip, &lb);
1100  }
1101 
1102  /* set up row */
1103  cnt = 0;
1104  for (v = 0; v < nlinvars; ++v)
1105  {
1106  SCIP_VAR* var;
1107  var = linvars[v];
1108  assert( var != NULL );
1109 
1110  /* skip slack variable */
1111  if ( var == slackvar )
1112  continue;
1113 
1114  assert( SCIPhashmapExists(varhash, var) );
1115  matind[cnt] = SCIPhashmapGetImageInt(varhash, var);
1116  matval[cnt] = sign * linvals[v];
1117  ++cnt;
1118  }
1119 
1120  lhs = -SCIPlpiInfinity(lp);
1121  rhs = linrhs;
1122 
1123  /* add new row */
1124  matbeg = 0;
1125  SCIP_CALL( SCIPlpiAddRows(lp, 1, &lhs, &rhs, NULL, cnt, &matbeg, matind, matval) );
1126 
1127  SCIPfreeBufferArray(scip, &matind);
1128  SCIPfreeBufferArray(scip, &matval);
1129  SCIPfreeBufferArray(scip, &newvars);
1130 
1131  assert( slackvar != NULL );
1132  if ( SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
1133  {
1134  SCIPfreeBufferArray(scip, &linvals);
1135  SCIPfreeBufferArray(scip, &linvars);
1136  }
1137  }
1138  }
1139 
1140  /* possibly handle additional linear constraints */
1141  if ( conshdlrdata->useotherconss )
1142  {
1143  /* get all linear constraints */
1144  conss = SCIPgetConss(scip);
1145  nconss = SCIPgetNConss(scip);
1146 
1147  /* loop through constraints */
1148  for (c = 0; c < nconss; ++c)
1149  {
1150  SCIP_CONS* cons;
1151  SCIP_VAR** linvars;
1152  SCIP_Real* linvals;
1153  SCIP_Real linrhs;
1154  SCIP_Real linlhs;
1155  SCIP_Real* matval;
1156  SCIP_VAR** newvars;
1157  int nnewvars = 0;
1158  int* matind;
1159  int nlinvars;
1160  int matbeg = 0;
1161  int cnt = 0;
1162  int v;
1163 
1164  cons = conss[c];
1165  assert( cons != NULL );
1166 
1167  /* avoid non-active, local constraints */
1168  if ( ! SCIPconsIsEnabled(cons) || ! SCIPconsIsActive(cons) || SCIPconsIsLocal(cons) )
1169  continue;
1170 
1171  /* check type of constraint (only take linear constraints) */
1172  if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") != 0 )
1173  continue;
1174 
1175  /* avoid adding linear constraints that correspond to indicator constraints */
1176  if ( strncmp(SCIPconsGetName(cons), "indlin", 6) == 0 )
1177  continue;
1178 
1179  /* get data of linear constraint */
1180  linvars = SCIPgetVarsLinear(scip, cons);
1181  linvals = SCIPgetValsLinear(scip, cons);
1182  nlinvars = SCIPgetNVarsLinear(scip, cons);
1183  linlhs = SCIPgetLhsLinear(scip, cons);
1184  linrhs = SCIPgetRhsLinear(scip, cons);
1185 
1186  /* reserve space */
1187  SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4*nlinvars) );
1188  SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4*nlinvars) );
1189  SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nlinvars) );
1190 
1191  /* collect possibly new variables */
1192  for (v = 0; v < nlinvars; ++v)
1193  {
1194  SCIP_VAR* var;
1195  var = linvars[v];
1196  assert( var != NULL );
1197 
1198  /* if variable is new */
1199  if ( ! SCIPhashmapExists(varhash, var) )
1200  {
1201  /* add variable in map */
1202  SCIP_CALL( SCIPhashmapInsertInt(varhash, var, nvars) );
1203  assert( nvars == SCIPhashmapGetImageInt(varhash, var) );
1204  /* SCIPdebugMsg(scip, "Inserted variable <%s> into hashmap (%d).\n", SCIPvarGetName(var), nvars); */
1205  nvars++;
1206 
1207  /* store new variables */
1208  newvars[nnewvars++] = var;
1209  }
1210  assert( SCIPhashmapExists(varhash, var) );
1211  }
1212 
1213  /* add new columns */
1214  if ( nnewvars > 0 )
1215  {
1216  SCIP_Real* lb;
1217  SCIP_Real* ub;
1218  SCIP_Real* obj;
1219  char** colnames;
1220 
1221  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nnewvars) );
1222  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nnewvars) );
1223  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nnewvars) );
1224  SCIP_CALL( SCIPallocBufferArray(scip, &colnames, nnewvars) );
1225 
1226  for (v = 0; v < nnewvars; ++v)
1227  {
1228  SCIP_VAR* var;
1229  var = newvars[v];
1230  obj[v] = 0.0;
1231  lb[v] = SCIPvarGetLbLocal(var);
1232  ub[v] = SCIPvarGetUbLocal(var);
1233  SCIP_CALL( SCIPallocBufferArray(scip, &(colnames[v]), SCIP_MAXSTRLEN) ); /*lint !e866*/
1234  (void) SCIPsnprintf(colnames[v], SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var));
1235  }
1236 
1237  /* now add columns */
1238  SCIP_CALL( SCIPlpiAddCols(lp, nnewvars, obj, lb, ub, colnames, 0, NULL, NULL, NULL) );
1239 
1240  for (v = nnewvars - 1; v >= 0; --v)
1241  {
1242  SCIPfreeBufferArray(scip, &(colnames[v]));
1243  }
1244  SCIPfreeBufferArray(scip, &colnames);
1245  SCIPfreeBufferArray(scip, &obj);
1246  SCIPfreeBufferArray(scip, &ub);
1247  SCIPfreeBufferArray(scip, &lb);
1248  }
1249 
1250  /* set up row */
1251  for (v = 0; v < nlinvars; ++v)
1252  {
1253  SCIP_VAR* var;
1254  var = linvars[v];
1255  assert( var != NULL );
1256 
1257  assert( SCIPhashmapExists(varhash, var) );
1258  matind[cnt] = SCIPhashmapGetImageInt(varhash, var);
1259  matval[cnt] = linvals[v];
1260  ++cnt;
1261  }
1262 
1263  /* add new row */
1264  SCIP_CALL( SCIPlpiAddRows(lp, 1, &linlhs, &linrhs, NULL, cnt, &matbeg, matind, matval) );
1265 
1266  SCIPfreeBufferArray(scip, &matind);
1267  SCIPfreeBufferArray(scip, &matval);
1268  SCIPfreeBufferArray(scip, &newvars);
1269  }
1270  }
1271 
1272  /* solve LP and check status */
1274 
1275  if ( ! SCIPlpiIsPrimalInfeasible(lp) )
1276  {
1277  SCIPerrorMessage("Detected IIS is not infeasible in original problem!\n");
1278 
1279  SCIP_CALL( SCIPlpiWriteLP(lp, "check.lp") );
1280  SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "altdebug.lp") );
1281  SCIPABORT();
1282  return SCIP_ERROR; /*lint !e527*/
1283  }
1284  SCIPdebugMsg(scip, "Check successful!\n");
1285 
1286  SCIPhashmapFree(&varhash);
1287  SCIP_CALL( SCIPlpiFree(&lp) );
1288 
1289  return SCIP_OKAY;
1290 }
1291 #endif
1292 
1293 
1294 /* ------------------------ auxiliary operations -------------------------------*/
1295 
1296 /** return objective contribution of variable
1297  *
1298  * Special treatment of negated variables: return negative of objective of original
1299  * variable. SCIPvarGetObj() would return 0 in these cases.
1300  */
1301 static
1303  SCIP_VAR* var /**< variable */
1304  )
1305 {
1306  if ( SCIPvarIsBinary(var) && SCIPvarIsNegated(var) )
1307  {
1308  assert( SCIPvarGetNegatedVar(var) != NULL );
1309  return -SCIPvarGetObj(SCIPvarGetNegatedVar(var));
1310  }
1311  else if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED )
1312  {
1313  assert( SCIPvarGetAggrVar(var) != NULL );
1315  }
1316 
1317  return SCIPvarGetObj(var);
1318 }
1319 
1320 
1321 /** ensures that the addlincons array can store at least num entries */
1322 static
1324  SCIP* scip, /**< SCIP data structure */
1325  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1326  int num /**< minimum number of entries to store */
1327  )
1328 {
1329  SCIP_CONSHDLRDATA* conshdlrdata;
1330 
1331  assert( scip != NULL );
1332  assert( conshdlr != NULL );
1333  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1334 
1335  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1336  assert( conshdlrdata != NULL );
1337  assert( conshdlrdata->naddlincons <= conshdlrdata->maxaddlincons );
1338 
1339  if ( num > conshdlrdata->maxaddlincons )
1340  {
1341  int newsize;
1342 
1343  newsize = SCIPcalcMemGrowSize(scip, num);
1344  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons, newsize) );
1345  conshdlrdata->maxaddlincons = newsize;
1346  }
1347  assert( num <= conshdlrdata->maxaddlincons );
1348 
1349  return SCIP_OKAY;
1350 }
1351 
1352 
1353 /* ------------------------ operations on the alternative LP -------------------*/
1354 
1355 /** initialize alternative LP
1356  *
1357  * The alternative system is organized as follows:
1358  * - The first row corresponds to the right hand side of the original system.
1359  * - The next nconss constraints correspond to the slack variables.
1360  * - The rows after that correspond to the original variables.
1361  */
1362 static
1364  SCIP* scip, /**< SCIP pointer */
1365  SCIP_CONSHDLR* conshdlr /**< constraint handler */
1366  )
1367 {
1368  SCIP_CONSHDLRDATA* conshdlrdata;
1369  SCIP_Real lhs = -1.0;
1370  SCIP_Real rhs = -1.0;
1371 
1372  assert( scip != NULL );
1373  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1374 
1375  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1376  assert( conshdlrdata != NULL );
1377  assert( conshdlrdata->altlp == NULL );
1378  assert( conshdlrdata->varhash == NULL );
1379  assert( conshdlrdata->lbhash == NULL );
1380  assert( conshdlrdata->ubhash == NULL );
1381  assert( conshdlrdata->slackhash != NULL );
1382 
1383  /* create hash map of variables */
1384  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
1385  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->lbhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
1386  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->ubhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
1387 
1388  /* create alternative LP */
1389  SCIP_CALL( SCIPlpiCreate(&conshdlrdata->altlp, SCIPgetMessagehdlr(scip), "altlp", SCIP_OBJSEN_MINIMIZE) );
1390 
1391  /* add first row */
1392  SCIP_CALL( SCIPlpiAddRows(conshdlrdata->altlp, 1, &lhs, &rhs, NULL, 0, NULL, NULL, NULL) );
1393  conshdlrdata->nrows = 1;
1394 
1395  /* set parameters */
1397  SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_PRESOLVING, TRUE) );
1398  SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_SCALING, 1) );
1399  SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_FASTMIP, FALSE) );
1400 
1401  SCIPdebugMsg(scip, "Initialized alternative LP.\n");
1402 
1403  /* uncomment the following for debugging */
1404  /* SCIP_CALL_PARAM( SCIPlpiSetIntpar(conshdlrdata->altlp, SCIP_LPPAR_LPINFO, TRUE) ); */
1405 
1406  return SCIP_OKAY;
1407 }
1408 
1409 
1410 /** check whether the bounds in given (alternative) LP are set correctly (for debugging) */
1411 #ifndef NDEBUG
1412 static
1414  SCIP* scip, /**< SCIP pointer */
1415  SCIP_LPI* lp, /**< LP for which bounds should be checked */
1416  int nconss, /**< number of constraints */
1417  SCIP_CONS** conss /**< constraints */
1418  )
1419 {
1420  SCIP_Real* lb;
1421  SCIP_Real* ub;
1422  SCIP_Bool* covered;
1423  int nCols;
1424  int j;
1425 
1426  assert( scip != NULL );
1427  assert( lp != NULL );
1428 
1429  SCIP_CALL( SCIPlpiGetNCols(lp, &nCols) );
1430 
1431  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nCols) );
1432  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nCols) );
1433  SCIP_CALL( SCIPallocBufferArray(scip, &covered, nCols) );
1434 
1435  for (j = 0; j < nCols; ++j)
1436  covered[j] = FALSE;
1437 
1438  /* check columns used by constraints */
1439  SCIP_CALL( SCIPlpiGetBounds(lp, 0, nCols-1, lb, ub) );
1440  for (j = 0; j < nconss; ++j)
1441  {
1442  SCIP_CONSDATA* consdata;
1443  int ind;
1444 
1445  assert( conss[j] != NULL );
1446  consdata = SCIPconsGetData(conss[j]);
1447  assert( consdata != NULL );
1448  ind = consdata->colindex;
1449 
1450  if ( ind >= 0 )
1451  {
1452  assert( ind < nCols );
1453  covered[ind] = TRUE;
1454  if ( ! SCIPisFeasZero(scip, lb[ind]) || ! SCIPlpiIsInfinity(lp, ub[ind]) )
1455  {
1456  SCIPABORT();
1457  }
1458  }
1459  }
1460 
1461  /* check other columns */
1462  for (j = 0; j < nCols; ++j)
1463  {
1464  if (! covered[j] )
1465  {
1466  /* some columns can be fixed to 0, since they correspond to disabled constraints */
1467  if ( ( ! SCIPlpiIsInfinity(lp, -lb[j]) && ! SCIPisFeasZero(scip, lb[j])) || (! SCIPlpiIsInfinity(lp, ub[j]) && ! SCIPisFeasZero(scip, ub[j])) )
1468  {
1469  SCIPABORT();
1470  }
1471  }
1472  }
1473 
1474  SCIPfreeBufferArray(scip, &covered);
1475  SCIPfreeBufferArray(scip, &lb);
1476  SCIPfreeBufferArray(scip, &ub);
1477 
1478  return SCIP_OKAY;
1479 }
1480 #endif
1481 
1482 
1483 /** set the alternative system objective function
1484  *
1485  * We assume that the objective function coefficients of the variables other than the binary
1486  * indicators are always 0 and hence do not have to be changed.
1487  *
1488  * We already use the tranformation \f$y' = 1 - y\f$.
1489  */
1490 static
1492  SCIP* scip, /**< SCIP pointer */
1493  SCIP_LPI* lp, /**< alternative LP */
1494  SCIP_SOL* sol, /**< solution to be dealt with */
1495  int nconss, /**< number of constraints */
1496  SCIP_CONS** conss /**< indicator constraints */
1497  )
1498 {
1499  int j;
1500  SCIP_Real* obj = NULL;
1501  int* indices = NULL;
1502  int cnt = 0;
1503 
1504  assert( scip != NULL );
1505  assert( lp != NULL );
1506  assert( conss != NULL );
1507 
1508  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nconss) );
1509  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1510 
1511  for (j = 0; j < nconss; ++j)
1512  {
1513  SCIP_CONSDATA* consdata;
1514 
1515  assert( conss[j] != NULL );
1516  consdata = SCIPconsGetData(conss[j]);
1517  assert( consdata != NULL );
1518 
1519  if ( consdata->colindex >= 0 )
1520  {
1521  SCIP_Real val = SCIPgetSolVal(scip, sol, consdata->binvar);
1522  if ( SCIPisFeasEQ(scip, val, 1.0) )
1523  obj[cnt] = OBJEPSILON; /* set objective to some small number to get small IISs */
1524  else
1525  obj[cnt] = 1.0 - val;
1526  indices[cnt++] = consdata->colindex;
1527  }
1528  }
1529 
1530  if ( cnt > 0 )
1531  {
1532  SCIP_CALL( SCIPlpiChgObj(lp, cnt, indices, obj) );
1533  }
1534 
1535  SCIPfreeBufferArray(scip, &indices);
1536  SCIPfreeBufferArray(scip, &obj);
1537 
1538  return SCIP_OKAY;
1539 }
1540 
1541 
1542 /** set the alternative system objective function to some small value */
1543 static
1545  SCIP* scip, /**< SCIP pointer */
1546  SCIP_LPI* lp, /**< alternative LP */
1547  int nconss, /**< number of constraints */
1548  SCIP_CONS** conss /**< indicator constraints */
1549  )
1550 {
1551  int j;
1552  SCIP_Real* obj = NULL;
1553  int* indices = NULL;
1554  int cnt = 0;
1555 
1556  assert( scip != NULL );
1557  assert( lp != NULL );
1558  assert( conss != NULL );
1559 
1560  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nconss) );
1561  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1562 
1563  for (j = 0; j < nconss; ++j)
1564  {
1565  SCIP_CONSDATA* consdata;
1566 
1567  assert( conss[j] != NULL );
1568  consdata = SCIPconsGetData(conss[j]);
1569  assert( consdata != NULL );
1570 
1571  if ( consdata->colindex >= 0 )
1572  {
1573  obj[cnt] = OBJEPSILON;
1574  indices[cnt++] = consdata->colindex;
1575  }
1576  }
1577 
1578  if ( cnt > 0 )
1579  {
1580  SCIP_CALL( SCIPlpiChgObj(lp, cnt, indices, obj) );
1581  }
1582 
1583  SCIPfreeBufferArray(scip, &indices);
1584  SCIPfreeBufferArray(scip, &obj);
1585 
1586  return SCIP_OKAY;
1587 }
1588 
1589 
1590 /** fix variable given by @a S to 0 */
1591 static
1593  SCIP* scip, /**< SCIP pointer */
1594  SCIP_LPI* lp, /**< alternative LP */
1595  int nconss, /**< number of constraints */
1596  SCIP_CONS** conss, /**< indicator constraints */
1597  SCIP_Bool* S /**< bitset of variables */
1598  )
1599 {
1600  SCIP_Real* lb = NULL;
1601  SCIP_Real* ub = NULL;
1602  int* indices = NULL;
1603  int cnt = 0;
1604  int j;
1605 
1606  assert( scip != NULL );
1607  assert( lp != NULL );
1608  assert( conss != NULL );
1609 
1610  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nconss) );
1611  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nconss) );
1612  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1613 
1614  /* collect bounds to be changed */
1615  for (j = 0; j < nconss; ++j)
1616  {
1617  SCIP_CONSDATA* consdata;
1618 
1619  assert( conss[j] != NULL );
1620  consdata = SCIPconsGetData(conss[j]);
1621  assert( consdata != NULL );
1622 
1623  if ( consdata->colindex >= 0 )
1624  {
1625  if ( S[j] )
1626  {
1627  indices[cnt] = consdata->colindex;
1628  lb[cnt] = 0.0;
1629  ub[cnt] = 0.0;
1630  ++cnt;
1631  }
1632  }
1633  }
1634 
1635  /* change bounds */
1636  if ( cnt > 0 )
1637  {
1638  SCIP_CALL( SCIPlpiChgBounds(lp, cnt, indices, lb, ub) );
1639  }
1640 
1641  SCIPfreeBufferArray(scip, &indices);
1642  SCIPfreeBufferArray(scip, &ub);
1643  SCIPfreeBufferArray(scip, &lb);
1644 
1645  return SCIP_OKAY;
1646 }
1647 
1648 
1649 /** fix variable @a ind to 0 */
1650 static
1652  SCIP_LPI* lp, /**< alternative LP */
1653  int ind /**< variable that should be fixed to 0 */
1654  )
1655 {
1656  SCIP_Real lb = 0.0;
1657  SCIP_Real ub = 0.0;
1658 
1659  /* change bounds */
1660  SCIP_CALL( SCIPlpiChgBounds(lp, 1, &ind, &lb, &ub) );
1661 
1662  return SCIP_OKAY;
1663 }
1664 
1665 
1666 /** unfix variable @a ind to 0 */
1667 static
1669  SCIP_LPI* lp, /**< alternative LP */
1670  int ind /**< variable that should be fixed to 0 */
1671  )
1672 {
1673  SCIP_Real lb = 0.0;
1674  SCIP_Real ub = SCIPlpiInfinity(lp);
1675 
1676  /* change bounds */
1677  SCIP_CALL( SCIPlpiChgBounds(lp, 1, &ind, &lb, &ub) );
1678 
1679  return SCIP_OKAY;
1680 }
1681 
1682 /** unfix variable given by @a S to 0 */
1683 static
1685  SCIP* scip, /**< SCIP pointer */
1686  SCIP_LPI* lp, /**< alternative LP */
1687  int nconss, /**< number of constraints */
1688  SCIP_CONS** conss, /**< indicator constraints */
1689  SCIP_Bool* S /**< bitset of variables */
1690  )
1691 {
1692  SCIP_Real* lb = NULL;
1693  SCIP_Real* ub = NULL;
1694  int* indices = NULL;
1695  int cnt = 0;
1696  int j;
1697 
1698  assert( scip != NULL );
1699  assert( lp != NULL );
1700  assert( conss != NULL );
1701 
1702  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nconss) );
1703  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nconss) );
1704  SCIP_CALL( SCIPallocBufferArray(scip, &indices, nconss) );
1705 
1706  /* collect bounds to be changed */
1707  for (j = 0; j < nconss; ++j)
1708  {
1709  if ( S[j] )
1710  {
1711  SCIP_CONSDATA* consdata;
1712 
1713  assert( conss[j] != NULL );
1714  consdata = SCIPconsGetData(conss[j]);
1715  assert( consdata != NULL );
1716 
1717  if ( consdata->colindex >= 0 )
1718  {
1719  indices[cnt] = consdata->colindex;
1720  lb[cnt] = 0.0;
1721  ub[cnt] = SCIPlpiInfinity(lp);
1722  ++cnt;
1723  }
1724  }
1725  }
1726 
1727  /* change bounds */
1728  if ( cnt > 0 )
1729  {
1730  SCIP_CALL( SCIPlpiChgBounds(lp, cnt, indices, lb, ub) );
1731  }
1732 
1733  SCIPfreeBufferArray(scip, &indices);
1734  SCIPfreeBufferArray(scip, &ub);
1735  SCIPfreeBufferArray(scip, &lb);
1736 
1737  return SCIP_OKAY;
1738 }
1739 
1740 
1741 /** update bounds in first row to the current ones */
1742 static
1744  SCIP* scip, /**< SCIP pointer */
1745  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
1746  )
1747 {
1748  SCIP_HASHMAP* lbhash;
1749  SCIP_HASHMAP* ubhash;
1750  SCIP_VAR** vars;
1751  SCIP_LPI* altlp;
1752  int nvars;
1753  int cnt;
1754  int v;
1755 
1756  assert( scip != NULL );
1757  assert( conshdlrdata != NULL );
1758 
1759  altlp = conshdlrdata->altlp;
1760  lbhash = conshdlrdata->lbhash;
1761  ubhash = conshdlrdata->ubhash;
1762  assert( lbhash != NULL && ubhash != NULL );
1763 
1764  /* check all variables */
1765  vars = SCIPgetVars(scip);
1766  nvars = SCIPgetNVars(scip);
1767  cnt = 0;
1768 
1769  for (v = 0; v < nvars; ++v)
1770  {
1771  SCIP_VAR* var;
1772  var = vars[v];
1773  if ( SCIPhashmapExists(lbhash, var) )
1774  {
1775  int col;
1776 
1777  col = SCIPhashmapGetImageInt(lbhash, var);
1778  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, -SCIPvarGetLbLocal(var)) );
1779  if ( ! SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var)) )
1780  ++cnt;
1781  }
1782  if ( SCIPhashmapExists(ubhash, var) )
1783  {
1784  int col;
1785 
1786  col = SCIPhashmapGetImageInt(ubhash, var);
1787  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, SCIPvarGetUbLocal(var)) );
1788  if ( ! SCIPisEQ(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var)) )
1789  ++cnt;
1790  }
1791  }
1792  if ( cnt > 10 )
1793  {
1794  /* possible force a rescaling: */
1795  conshdlrdata->scaled = FALSE;
1796 
1797  /* SCIP_CALL( SCIPlpiWriteLP(altlp, "altChg.lp") ); */
1798  SCIPdebugMsg(scip, "Updated bounds of original variables: %d.\n", cnt);
1799  }
1800 
1801  return SCIP_OKAY;
1802 }
1803 
1804 
1805 /** update bounds in first row to the global bounds */
1806 static
1808  SCIP* scip, /**< SCIP pointer */
1809  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
1810  )
1811 {
1812  SCIP_HASHMAP* lbhash;
1813  SCIP_HASHMAP* ubhash;
1814  SCIP_VAR** vars;
1815  SCIP_LPI* altlp;
1816  int nvars;
1817  int cnt;
1818  int v;
1819 
1820  assert( scip != NULL );
1821  assert( conshdlrdata != NULL );
1822 
1823  altlp = conshdlrdata->altlp;
1824  lbhash = conshdlrdata->lbhash;
1825  ubhash = conshdlrdata->ubhash;
1826  assert( lbhash != NULL && ubhash != NULL );
1827 
1828  /* check all variables */
1829  vars = SCIPgetVars(scip);
1830  nvars = SCIPgetNVars(scip);
1831  cnt = 0;
1832 
1833  for (v = 0; v < nvars; ++v)
1834  {
1835  SCIP_VAR* var;
1836  int col;
1837 
1838  var = vars[v];
1839  if ( SCIPhashmapExists(lbhash, var) )
1840  {
1841  col = SCIPhashmapGetImageInt(lbhash, var);
1842  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, -SCIPvarGetLbGlobal(var)) );
1843  ++cnt;
1844  }
1845  if ( SCIPhashmapExists(ubhash, var) )
1846  {
1847  col = SCIPhashmapGetImageInt(ubhash, var);
1848  SCIP_CALL( SCIPlpiChgCoef(altlp, 0, col, SCIPvarGetUbGlobal(var)) );
1849  ++cnt;
1850  }
1851  }
1852 
1853  if ( cnt > 0 )
1854  {
1855  /* SCIP_CALL( SCIPlpiWriteLP(altlp, "altChg.lp") ); */
1856  SCIPdebugMsg(scip, "Updated bounds of original variables: %d.\n", cnt);
1857  }
1858 
1859  /* possible force a rescaling: */
1860  /* conshdlrdata->scaled = FALSE; */
1861 
1862  return SCIP_OKAY;
1863 }
1864 
1865 
1866 /** check whether IIS defined by @a vector corresponds to a local cut */
1867 static
1869  SCIP* scip, /**< SCIP pointer */
1870  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler */
1871  SCIP_Real* vector, /**< solution to alternative LP defining IIS */
1872  SCIP_Bool* isLocal /**< whether the IIS uses local bounds different from the global ones */
1873  )
1874 {
1875  SCIP_HASHMAP* lbhash;
1876  SCIP_HASHMAP* ubhash;
1877  SCIP_VAR** vars;
1878 #ifndef NDEBUG
1879  int nCols;
1880 #endif
1881  int nvars;
1882  int v;
1883 
1884  assert( scip != NULL );
1885  assert( conshdlrdata != NULL );
1886  assert( vector != NULL );
1887  assert( isLocal != NULL );
1888 
1889  *isLocal = FALSE;
1890 
1891 #ifndef NDEBUG
1892  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &nCols) );
1893 #endif
1894 
1895  lbhash = conshdlrdata->lbhash;
1896  ubhash = conshdlrdata->ubhash;
1897  assert( lbhash != NULL && ubhash != NULL );
1898 
1899  /* get all variables */
1900  vars = SCIPgetVars(scip);
1901  nvars = SCIPgetNVars(scip);
1902 
1903  /* check all variables */
1904  for (v = 0; v < nvars; ++v)
1905  {
1906  SCIP_VAR* var;
1907  var = vars[v];
1908 
1909  /* if local bound is different from global bound */
1910  if ( ! SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var)) )
1911  {
1912  /* check whether the variable corresponding to the lower bounds has been used */
1913  if ( SCIPhashmapExists(lbhash, var) )
1914  {
1915  int col;
1916 
1917  col = SCIPhashmapGetImageInt(lbhash, var);
1918  assert( 0 <= col && col < nCols );
1919  if ( ! SCIPisFeasZero(scip, vector[col]) )
1920  {
1921  *isLocal = TRUE;
1922  return SCIP_OKAY;
1923  }
1924  }
1925  }
1926 
1927  /* if local bound is different from global bound */
1928  if ( ! SCIPisEQ(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var)) )
1929  {
1930  /* check whether the variable corresponding to the upper bounds has been used */
1931  if ( SCIPhashmapExists(ubhash, var) )
1932  {
1933  int col;
1934 
1935  col = SCIPhashmapGetImageInt(ubhash, var);
1936  assert( 0 <= col && col < nCols );
1937  if ( ! SCIPisFeasZero(scip, vector[col]) )
1938  {
1939  *isLocal = TRUE;
1940  return SCIP_OKAY;
1941  }
1942  }
1943  }
1944  }
1945 
1946  return SCIP_OKAY;
1947 }
1948 
1949 
1950 /** compute scaling for first row
1951  *
1952  * If the coefficients in the first row are large, a right hand side of -1 might not be
1953  * adequate. Here, we replace the right hand side by the sum of the coefficients divided by the
1954  * number of nonzeros.
1955  */
1956 static
1958  SCIP* scip, /**< SCIP pointer */
1959  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler */
1960  )
1961 {
1962  assert( scip != NULL );
1963  assert( conshdlrdata != NULL );
1964 
1965  if ( ! conshdlrdata->scaled )
1966  {
1967  SCIP_Real* val;
1968  SCIP_LPI* altlp;
1969  int* ind;
1970  SCIP_Real sum = 0.0;
1971  int beg[1];
1972  int nCols;
1973  int cnt;
1974  int j;
1975 
1976  altlp = conshdlrdata->altlp;
1977  SCIP_CALL( SCIPlpiGetNCols(altlp, &nCols) );
1978  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nCols) );
1979  SCIP_CALL( SCIPallocBufferArray(scip, &val, nCols) );
1980 
1981  SCIP_CALL( SCIPlpiGetRows(altlp, 0, 0, NULL, NULL, &cnt, beg, ind, val) );
1982 
1983  if ( cnt > 0 )
1984  {
1985  /* compute sum */
1986  for (j = 0; j < cnt; ++j)
1987  sum += REALABS(val[j]);
1988 
1989  /* set rhs */
1990  sum = - REALABS(sum) / ((double) cnt);
1991  j = 0;
1992  SCIP_CALL( SCIPlpiChgSides(altlp, 1, &j, &sum, &sum) );
1993  }
1994 
1995  SCIPfreeBufferArray(scip, &val);
1996  SCIPfreeBufferArray(scip, &ind);
1997 
1998  conshdlrdata->scaled = TRUE;
1999  }
2000 
2001  return SCIP_OKAY;
2002 }
2003 
2004 
2005 /** add column to alternative LP
2006  *
2007  * See the description at the top of the file for more information.
2008  */
2009 static
2011  SCIP* scip, /**< SCIP pointer */
2012  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2013  SCIP_CONSHDLRDATA* conshdlrdata, /**< data of constraint handler */
2014  SCIP_VAR* slackvar, /**< slack variable or NULL */
2015  int nvars, /**< number of variables in column */
2016  SCIP_VAR** vars, /**< variables for column */
2017  SCIP_Real* vals, /**< values for column */
2018  SCIP_Real rhscoef, /**< coefficient for first row */
2019  SCIP_Real objcoef, /**< objective in alternative LP */
2020  SCIP_Real sign, /**< sign (+1,-1) for column */
2021  SCIP_Bool colfree, /**< whether column should be free, e.g., for equations */
2022  int* colindex /**< index of new column (return value) */
2023  )
2024 {
2025  SCIP_VAR** newvars;
2026  SCIP_Real val;
2027  SCIP_Real* matval;
2028  SCIP_Bool* newrowsslack;
2029  SCIP_Real* obj;
2030  SCIP_Real* lb;
2031  SCIP_Real* ub;
2032  int* matbeg;
2033  int* matind;
2034  int nnewvars = 0;
2035  int nnewcols = 0;
2036  int nnewrows = 0;
2037  int ncols = 0;
2038  int cnt = 0;
2039  int v;
2040 
2041  assert( scip != NULL );
2042  assert( conshdlrdata != NULL );
2043  assert( vars != NULL || nvars == 0 );
2044  assert( vals != NULL || nvars == 0 );
2045  assert( ! SCIPisInfinity(scip, rhscoef) && ! SCIPisInfinity(scip, -rhscoef) );
2046  assert( SCIPisEQ(scip, sign, 1.0) || SCIPisEQ(scip, sign, -1.0) );
2047  assert( colindex != NULL );
2048 
2049  *colindex = -1;
2050 
2051  if ( conshdlrdata->altlp == NULL )
2052  {
2053  SCIP_CALL( initAlternativeLP(scip, conshdlr) );
2054  }
2055  assert( conshdlrdata->altlp != NULL );
2056  assert( conshdlrdata->varhash != NULL );
2057  assert( conshdlrdata->lbhash != NULL );
2058  assert( conshdlrdata->ubhash != NULL );
2059  assert( conshdlrdata->slackhash != NULL );
2060 
2061 #ifndef NDEBUG
2062  {
2063  int nrows;
2064  SCIP_CALL( SCIPlpiGetNRows(conshdlrdata->altlp, &nrows) );
2065  assert( nrows == conshdlrdata->nrows );
2066  }
2067 #endif
2068 
2069  /* set up data for construction */
2070  SCIP_CALL( SCIPallocBufferArray(scip, &matbeg, nvars) );
2071  SCIP_CALL( SCIPallocBufferArray(scip, &matind, 4 * nvars) );
2072  SCIP_CALL( SCIPallocBufferArray(scip, &matval, 4 * nvars) );
2073  SCIP_CALL( SCIPallocBufferArray(scip, &obj, 2 * nvars) );
2074  SCIP_CALL( SCIPallocBufferArray(scip, &lb, 2 * nvars) );
2075  SCIP_CALL( SCIPallocBufferArray(scip, &ub, 2 * nvars) );
2076  SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nvars) );
2077  SCIP_CALL( SCIPallocBufferArray(scip, &newrowsslack, 2 * nvars) );
2078 
2079  /* store index of column in constraint */
2080  /* coverity[var_deref_model] */
2081  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &ncols) );
2082  *colindex = ncols;
2083 
2084  /* handle first row */
2085  if ( ! SCIPisFeasZero(scip, rhscoef) )
2086  {
2087  matind[cnt] = 0;
2088  matval[cnt++] = sign * rhscoef;
2089  }
2090 
2091  /* set up column (recognize new original variables) */
2092  for (v = 0; v < nvars; ++v)
2093  {
2094  SCIP_VAR* var;
2095 
2096  var = vars[v];
2097  assert( var != NULL );
2098 
2099  /* if variable is a slack variable */
2100  if ( SCIPhashmapExists(conshdlrdata->slackhash, var) )
2101  {
2102  /* to avoid trivial rows: only add row corresponding to slack variable if it appears outside its own constraint */
2103  if ( var != slackvar )
2104  {
2105  int ind;
2106 
2107  ind = SCIPhashmapGetImageInt(conshdlrdata->slackhash, var);
2108 
2109  if ( ind < INT_MAX )
2110  matind[cnt] = ind;
2111  else
2112  {
2113  /* correct number of variable already in map/array and remember to add a new row */
2114  SCIP_CALL( SCIPhashmapSetImageInt(conshdlrdata->slackhash, var, conshdlrdata->nrows) );
2115  assert( conshdlrdata->nrows == SCIPhashmapGetImageInt(conshdlrdata->slackhash, var) );
2116  SCIPdebugMsg(scip, "Inserted slack variable <%s> into hashmap (row: %d).\n", SCIPvarGetName(var), conshdlrdata->nrows);
2117  matind[cnt] = (conshdlrdata->nrows)++;
2118 
2119  /* store new variables */
2120  newrowsslack[nnewrows++] = TRUE;
2121  }
2122  assert( conshdlrdata->nrows >= SCIPhashmapGetImageInt(conshdlrdata->slackhash, var) );
2123  matval[cnt++] = sign * vals[v];
2124  }
2125  }
2126  else
2127  {
2128  /* if variable exists */
2129  if ( SCIPhashmapExists(conshdlrdata->varhash, var) )
2130  matind[cnt] = SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
2131  else
2132  {
2133  /* add variable in map and array and remember to add a new row */
2134  SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->varhash, var, conshdlrdata->nrows) );
2135  assert( conshdlrdata->nrows == SCIPhashmapGetImageInt(conshdlrdata->varhash, var) );
2136  SCIPdebugMsg(scip, "Inserted variable <%s> into hashmap (row: %d).\n", SCIPvarGetName(var), conshdlrdata->nrows);
2137  matind[cnt] = (conshdlrdata->nrows)++;
2138 
2139  /* store new variables */
2140  newrowsslack[nnewrows++] = FALSE;
2141  newvars[nnewvars++] = var;
2142  }
2143  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2144  matval[cnt++] = sign * vals[v];
2145  }
2146  }
2147 
2148  /* add new rows */
2149  if ( nnewrows > 0 )
2150  {
2151  SCIP_Real* lhs;
2152  SCIP_Real* rhs;
2153  int i;
2154 
2155  SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nnewrows) );
2156  SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nnewrows) );
2157  for (i = 0; i < nnewrows; ++i)
2158  {
2159  if ( newrowsslack[i] )
2160  lhs[i] = -SCIPlpiInfinity(conshdlrdata->altlp);
2161  else
2162  lhs[i] = 0.0;
2163  rhs[i] = 0.0;
2164  }
2165  /* add new rows */
2166  SCIP_CALL( SCIPlpiAddRows(conshdlrdata->altlp, nnewrows, lhs, rhs, NULL, 0, NULL, NULL, NULL) );
2167 
2168  SCIPfreeBufferArray(scip, &lhs);
2169  SCIPfreeBufferArray(scip, &rhs);
2170  }
2171 
2172  /* now add column */
2173  obj[0] = objcoef;
2174  if ( colfree )
2175  {
2176  /* create a free variable -> should only happen for additional linear constraints */
2177  assert( slackvar == NULL );
2178  lb[0] = -SCIPlpiInfinity(conshdlrdata->altlp);
2179  }
2180  else
2181  lb[0] = 0.0;
2182  ub[0] = SCIPlpiInfinity(conshdlrdata->altlp);
2183  matbeg[0] = 0;
2184 
2185  SCIP_CALL( SCIPlpiAddCols(conshdlrdata->altlp, 1, obj, lb, ub, NULL, cnt, matbeg, matind, matval) );
2186 
2187  /* add columns corresponding to bounds of original variables - no bounds needed for slack vars */
2188  cnt = 0;
2189  for (v = 0; v < nnewvars; ++v)
2190  {
2191  SCIP_VAR* var = newvars[v];
2192  assert( var != NULL );
2193 
2194  /* if the lower bound is finite */
2195  val = SCIPvarGetLbGlobal(var);
2196  if ( ! SCIPisInfinity(scip, -val) )
2197  {
2198  matbeg[nnewcols] = cnt;
2199  if ( ! SCIPisZero(scip, val) )
2200  {
2201  matind[cnt] = 0;
2202  matval[cnt++] = -val;
2203  }
2204  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2205 
2206  matind[cnt] = SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
2207  matval[cnt++] = -1.0;
2208  obj[nnewcols] = 0.0;
2209  lb[nnewcols] = 0.0;
2210  ub[nnewcols] = SCIPlpiInfinity(conshdlrdata->altlp);
2211  ++conshdlrdata->nlbbounds;
2212 
2213  SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->lbhash, var, ncols + 1 + nnewcols) );
2214  assert( SCIPhashmapExists(conshdlrdata->lbhash, var) );
2215  SCIPdebugMsg(scip, "Added column for lower bound (%f) of variable <%s> to alternative polyhedron (col: %d).\n",
2216  val, SCIPvarGetName(var), ncols + 1 + nnewcols);
2217  ++nnewcols;
2218  }
2219 
2220  /* if the upper bound is finite */
2221  val = SCIPvarGetUbGlobal(var);
2222  if ( ! SCIPisInfinity(scip, val) )
2223  {
2224  matbeg[nnewcols] = cnt;
2225  if ( ! SCIPisZero(scip, val) )
2226  {
2227  matind[cnt] = 0;
2228  matval[cnt++] = val;
2229  }
2230  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
2231 
2232  matind[cnt] = SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
2233  matval[cnt++] = 1.0;
2234  obj[nnewcols] = 0.0;
2235  lb[nnewcols] = 0.0;
2236  ub[nnewcols] = SCIPlpiInfinity(conshdlrdata->altlp);
2237  ++conshdlrdata->nubbounds;
2238 
2239  SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->ubhash, var, ncols + 1 + nnewcols) );
2240  assert( SCIPhashmapExists(conshdlrdata->ubhash, var) );
2241  SCIPdebugMsg(scip, "Added column for upper bound (%f) of variable <%s> to alternative polyhedron (col: %d).\n",
2242  val, SCIPvarGetName(var), ncols + 1 + nnewcols);
2243  ++nnewcols;
2244  }
2245  }
2246 
2247  /* add columns if necessary */
2248  if ( nnewcols > 0 )
2249  {
2250  SCIP_CALL( SCIPlpiAddCols(conshdlrdata->altlp, nnewcols, obj, lb, ub, NULL, cnt, matbeg, matind, matval) );
2251  }
2252 
2253 #ifndef NDEBUG
2254  SCIP_CALL( SCIPlpiGetNCols(conshdlrdata->altlp, &cnt) );
2255  assert( cnt == ncols + nnewcols + 1 );
2256 #endif
2257 
2258  SCIPfreeBufferArray(scip, &ub);
2259  SCIPfreeBufferArray(scip, &lb);
2260  SCIPfreeBufferArray(scip, &obj);
2261  SCIPfreeBufferArray(scip, &matind);
2262  SCIPfreeBufferArray(scip, &matval);
2263  SCIPfreeBufferArray(scip, &matbeg);
2264  SCIPfreeBufferArray(scip, &newvars);
2265  SCIPfreeBufferArray(scip, &newrowsslack);
2266 
2267  conshdlrdata->scaled = FALSE;
2268 
2269 #ifdef SCIP_OUTPUT
2270  SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "alt.lp") );
2271 #endif
2272 
2273  return SCIP_OKAY;
2274 }
2275 
2276 
2277 /** add column corresponding to constraint to alternative LP
2278  *
2279  * See the description at the top of the file for more information.
2280  */
2281 static
2283  SCIP* scip, /**< SCIP pointer */
2284  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2285  SCIP_CONS* lincons, /**< linear constraint */
2286  SCIP_VAR* slackvar, /**< slack variable or NULL */
2287  SCIP_Real objcoef, /**< objective coefficient */
2288  int* colindex /**< index of new column */
2289  )
2290 {
2291  SCIP_CONSHDLRDATA* conshdlrdata;
2292  SCIP_VAR** linvars;
2293  SCIP_Real* linvals;
2294  SCIP_Real linrhs;
2295  SCIP_Real linlhs;
2296  int nlinvars;
2297 
2298  assert( scip != NULL );
2299  assert( conshdlr != NULL );
2300  assert( lincons != NULL );
2301  assert( colindex != NULL );
2302  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2303 
2304  *colindex = -1;
2305 
2306  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2307  assert( conshdlrdata != NULL );
2308 
2309  /* if the slack variable is aggregated (multi-aggregation should not happen) */
2310  assert( slackvar == NULL || SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
2311  if ( slackvar != NULL && SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
2312  {
2313  SCIP_VAR* var;
2314  SCIP_Real scalar = 1.0;
2315  SCIP_Real constant = 0.0;
2316 
2317  var = slackvar;
2318 
2319  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
2320 
2321  SCIPdebugMsg(scip, "Slack variable is aggregated (scalar: %f, constant: %f).\n", scalar, constant);
2322 
2323  /* if the slack variable is fixed */
2324  if ( SCIPisZero(scip, scalar) && ! SCIPconsIsActive(lincons) )
2325  return SCIP_OKAY;
2326 
2327  /* otherwise construct a linear constraint */
2328  SCIP_CALL( SCIPallocBufferArray(scip, &linvars, 1) );
2329  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, 1) );
2330  linvars[0] = var;
2331  linvals[0] = scalar;
2332  nlinvars = 1;
2333  linlhs = -SCIPinfinity(scip);
2334  linrhs = constant;
2335  }
2336  else
2337  {
2338  /* exit if linear constraint is not active */
2339  if ( ! SCIPconsIsActive(lincons) && slackvar != NULL )
2340  return SCIP_OKAY;
2341 
2342  /* in this case, the linear constraint is directly usable */
2343  linvars = SCIPgetVarsLinear(scip, lincons);
2344  linvals = SCIPgetValsLinear(scip, lincons);
2345  nlinvars = SCIPgetNVarsLinear(scip, lincons);
2346  linlhs = SCIPgetLhsLinear(scip, lincons);
2347  linrhs = SCIPgetRhsLinear(scip, lincons);
2348  }
2349 
2350  /* create column */
2351  if ( SCIPisEQ(scip, linlhs, linrhs) )
2352  {
2353  /* create free variable for equations (should only happen for additional linear constraints) */
2354  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, slackvar, nlinvars, linvars, linvals, linrhs, objcoef, 1.0, TRUE, colindex) );
2355  }
2356  else if ( ! SCIPisInfinity(scip, linrhs) )
2357  {
2358  /* create column for rhs */
2359  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, slackvar, nlinvars, linvars, linvals, linrhs, objcoef, 1.0, FALSE, colindex) );
2360  }
2361  else
2362  {
2363  /* create column for lhs */
2364  assert( ! SCIPisInfinity(scip, -linlhs) );
2365  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, slackvar, nlinvars, linvars, linvals, linlhs, objcoef, -1.0, FALSE, colindex) );
2366  }
2367 
2368  if ( slackvar != NULL && SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
2369  {
2370  SCIPfreeBufferArray(scip, &linvals);
2371  SCIPfreeBufferArray(scip, &linvars);
2372  }
2373 
2374  return SCIP_OKAY;
2375 }
2376 
2377 
2378 /** add column corresponding to row to alternative LP
2379  *
2380  * See the description at the top of the file for more information.
2381  */
2382 static
2384  SCIP* scip, /**< SCIP pointer */
2385  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2386  SCIP_ROW* row, /**< row to add */
2387  SCIP_Real objcoef, /**< objective coefficient */
2388  int* colindex /**< index of new column */
2389  )
2390 {
2391  SCIP_CONSHDLRDATA* conshdlrdata;
2392  SCIP_COL** rowcols;
2393  SCIP_Real* rowvals;
2394  SCIP_VAR** rowvars;
2395  SCIP_Real rowrhs;
2396  SCIP_Real rowlhs;
2397  int nrowcols;
2398  int j;
2399 
2400  assert( scip != NULL );
2401  assert( conshdlr != NULL );
2402  assert( row != NULL );
2403  assert( colindex != NULL );
2404  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2405 
2406  /* initialize data */
2407  *colindex = -1;
2408 
2409  /* exit if row is not global */
2410  if ( SCIProwIsLocal(row) )
2411  return SCIP_OKAY;
2412 
2413  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2414  assert( conshdlrdata != NULL );
2415 
2416  /* get row data */
2417  rowcols = SCIProwGetCols(row);
2418  rowvals = SCIProwGetVals(row);
2419  nrowcols = SCIProwGetNNonz(row);
2420  rowlhs = SCIProwGetLhs(row) - SCIProwGetConstant(row);
2421  rowrhs = SCIProwGetRhs(row) - SCIProwGetConstant(row);
2422 
2423  SCIP_CALL( SCIPallocBufferArray(scip, &rowvars, nrowcols) );
2424  for (j = 0; j < nrowcols; ++j)
2425  {
2426  rowvars[j] = SCIPcolGetVar(rowcols[j]);
2427  assert( rowvars[j] != NULL );
2428  }
2429 
2430  /* create column */
2431  if ( SCIPisEQ(scip, rowlhs, rowrhs) )
2432  {
2433  /* create free variable for equations (should only happen for additional linear constraints) */
2434  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nrowcols, rowvars, rowvals, rowrhs, objcoef, 1.0, TRUE, colindex) );
2435  }
2436  else if ( ! SCIPisInfinity(scip, rowrhs) )
2437  {
2438  /* create column for rhs */
2439  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nrowcols, rowvars, rowvals, rowrhs, objcoef, 1.0, FALSE, colindex) );
2440  }
2441  else
2442  {
2443  /* create column for lhs */
2444  assert( ! SCIPisInfinity(scip, -rowlhs) );
2445  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nrowcols, rowvars, rowvals, rowlhs, objcoef, -1.0, FALSE, colindex) );
2446  }
2447 
2448  SCIPfreeBufferArray(scip, &rowvars);
2449 
2450  return SCIP_OKAY;
2451 }
2452 
2453 
2454 /** try to add objective cut as column to alternative LP */
2455 static
2457  SCIP* scip, /**< SCIP pointer */
2458  SCIP_CONSHDLR* conshdlr /**< constraint handler */
2459  )
2460 {
2461  SCIP_CONSHDLRDATA* conshdlrdata;
2462  SCIP_VAR** objvars;
2463  SCIP_Real* objvals;
2464  SCIP_VAR** vars;
2465  int nobjvars = 0;
2466  int nvars;
2467  int v;
2468 
2469  assert( scip != NULL );
2470  assert( conshdlr != NULL );
2471  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2472 
2473  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2474  assert( conshdlrdata != NULL );
2475 
2476  /* skip procedure if already added */
2477  if ( conshdlrdata->objcutindex >= 0 )
2478  return SCIP_OKAY;
2479 
2480  /* check whether we can add objective cut: all indicator variables have zero objective */
2481  if ( ! conshdlrdata->objothervarsonly )
2482  return SCIP_OKAY;
2483 
2484  assert( ! SCIPisInfinity(scip, conshdlrdata->objupperbound) );
2485  SCIPdebugMsg(scip, "Add objective cut to alternative LP (obj. bound: %g).\n", conshdlrdata->objupperbound);
2486 
2487  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2488  SCIP_CALL( SCIPallocBufferArray(scip, &objvars, nvars) );
2489  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
2490 
2491  /* collect nonzeros */
2492  for (v = 0; v < nvars; ++v)
2493  {
2494  SCIP_VAR* var;
2495  SCIP_Real objval;
2496 
2497  var = vars[v];
2498  assert( var != NULL );
2499  objval = SCIPvarGetObj(var);
2500 
2501  /* skip variables with zero objective - this includes slack and indicator variables */
2502  if ( ! SCIPisZero(scip, objval) )
2503  {
2504  objvars[nobjvars] = var;
2505  objvals[nobjvars++] = objval;
2506  }
2507  }
2508 
2509  /* create column (with rhs = upperbound, objective 0, and scaling factor 1.0) */
2510  SCIP_CALL( addAltLPColumn(scip, conshdlr, conshdlrdata, NULL, nobjvars, objvars, objvals, conshdlrdata->objupperbound, 0.0, 1.0, FALSE, &conshdlrdata->objcutindex) );
2511  assert( conshdlrdata->objcutindex >= 0 );
2512  conshdlrdata->objaltlpbound = conshdlrdata->objupperbound;
2513 
2514  SCIPfreeBufferArray(scip, &objvals);
2515  SCIPfreeBufferArray(scip, &objvars);
2516 
2517  return SCIP_OKAY;
2518 }
2519 
2520 
2521 /** delete column corresponding to constraint in alternative LP
2522  *
2523  * We currently just fix the corresponding variable to 0.
2524  */
2525 static
2527  SCIP* scip, /**< SCIP pointer */
2528  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2529  SCIP_CONS* cons /**< indicator constraint */
2530  )
2531 {
2532  SCIP_CONSHDLRDATA* conshdlrdata;
2533 
2534  assert( scip != NULL );
2535  assert( conshdlr != NULL );
2536  assert( cons != NULL );
2537  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2538 
2539  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2540  assert( conshdlrdata != NULL );
2541 
2542  if ( conshdlrdata->altlp != NULL )
2543  {
2544  SCIP_CONSDATA* consdata;
2545 
2546  consdata = SCIPconsGetData(cons);
2547  assert( consdata != NULL );
2548 
2549  if ( consdata->colindex >= 0 )
2550  {
2551  SCIP_CALL( fixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
2552  }
2553  consdata->colindex = -1;
2554 
2555  SCIPdebugMsg(scip, "Fixed variable for column %d (constraint: <%s>) from alternative LP to 0.\n", consdata->colindex, SCIPconsGetName(cons));
2556  }
2557  conshdlrdata->scaled = FALSE;
2558 
2559  return SCIP_OKAY;
2560 }
2561 
2562 
2563 /** update upper bound in alternative LP */
2564 static
2566  SCIP* scip, /**< SCIP pointer */
2567  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2568  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
2569  )
2570 {
2571  SCIP_Real objbnd;
2572 
2573  assert( scip != NULL );
2574  assert( conshdlrdata != NULL );
2575 
2576  if ( ! conshdlrdata->useobjectivecut )
2577  return SCIP_OKAY;
2578 
2579  if ( conshdlrdata->altlp == NULL )
2580  return SCIP_OKAY;
2581 
2582  /* first check whether we can improve the upper bound */
2583  objbnd = SCIPgetUpperbound(scip);
2584  if ( ! SCIPisInfinity(scip, objbnd) )
2585  {
2586  if ( SCIPisObjIntegral(scip) )
2587  objbnd = SCIPfeasCeil(scip, objbnd) - (1.0 - SCIPcutoffbounddelta(scip));
2588  else
2589  objbnd -= SCIPcutoffbounddelta(scip);
2590 
2591  if ( SCIPisLT(scip, objbnd, conshdlrdata->objupperbound) )
2592  conshdlrdata->objupperbound = objbnd;
2593  }
2594 
2595  if ( SCIPisInfinity(scip, conshdlrdata->objupperbound) )
2596  return SCIP_OKAY;
2597 
2598  /* if we can improve on the bound stored in the alternative LP */
2599  if ( SCIPisLT(scip, conshdlrdata->objupperbound, conshdlrdata->objaltlpbound) )
2600  {
2601  SCIPdebugMsg(scip, "Update objective bound to %g.\n", conshdlrdata->objupperbound);
2602 
2603  /* possibly add column for objective cut */
2604  if ( conshdlrdata->objcutindex < 0 )
2605  {
2606  SCIP_CALL( addObjcut(scip, conshdlr) );
2607  }
2608  else
2609  {
2610 #ifndef NDEBUG
2611  SCIP_Real oldbnd;
2612  SCIP_CALL( SCIPlpiGetCoef(conshdlrdata->altlp, 0, conshdlrdata->objcutindex, &oldbnd) );
2613  assert( SCIPisEQ(scip, oldbnd, conshdlrdata->objaltlpbound) );
2614 #endif
2615 
2616  /* update bound */
2617  SCIP_CALL( SCIPlpiChgCoef(conshdlrdata->altlp, 0, conshdlrdata->objcutindex, conshdlrdata->objupperbound) );
2618  conshdlrdata->objaltlpbound = conshdlrdata->objupperbound;
2619 
2620 #ifdef SCIP_OUTPUT
2621  SCIP_CALL( SCIPlpiWriteLP(conshdlrdata->altlp, "alt.lp") );
2622 #endif
2623  }
2624  }
2625 
2626  return SCIP_OKAY;
2627 }
2628 
2629 
2630 /** check whether the given LP is infeasible
2631  *
2632  * If @a primal is false we assume that the problem is <em>dual feasible</em>, e.g., the problem
2633  * was only changed by fixing bounds!
2634  *
2635  * This is the workhorse for all methods that have to solve the alternative LP. We try in several
2636  * ways to recover from possible stability problems.
2637  *
2638  * @pre It is assumed that all parameters for the alternative LP are set.
2639  */
2640 static
2642  SCIP* scip, /**< SCIP pointer */
2643  SCIP_LPI* lp, /**< LP */
2644  SCIP_Real maxcondition, /**< maximal allowed condition of LP solution basis matrix */
2645  SCIP_Bool primal, /**< whether we are using the primal or dual simplex */
2646  SCIP_Bool* infeasible, /**< output: whether the LP is infeasible */
2647  SCIP_Bool* error /**< output: whether an error occurred */
2648  )
2649 {
2650  SCIP_RETCODE retcode;
2651  SCIP_Real condition;
2652 
2653  assert( scip != NULL );
2654  assert( lp != NULL );
2655  assert( infeasible != NULL );
2656  assert( error != NULL );
2657 
2658  *error = FALSE;
2659 
2660  /* solve LP */
2661  if ( primal )
2662  retcode = SCIPlpiSolvePrimal(lp); /* use primal simplex */
2663  else
2664  retcode = SCIPlpiSolveDual(lp); /* use dual simplex */
2665  if ( retcode == SCIP_LPERROR )
2666  {
2667  *error = TRUE;
2668  return SCIP_OKAY;
2669  }
2670  SCIP_CALL( retcode );
2671 
2672  /* resolve if LP is not stable */
2673  if ( ! SCIPlpiIsStable(lp) )
2674  {
2677  SCIPwarningMessage(scip, "Numerical problems, retrying ...\n");
2678 
2679  /* re-solve LP */
2680  if ( primal )
2681  retcode = SCIPlpiSolvePrimal(lp); /* use primal simplex */
2682  else
2683  retcode = SCIPlpiSolveDual(lp); /* use dual simplex */
2684 
2685  /* reset parameters */
2688 
2689  if ( retcode == SCIP_LPERROR )
2690  {
2691  *error = TRUE;
2692  return SCIP_OKAY;
2693  }
2694  SCIP_CALL( retcode );
2695  }
2696 
2697  /* check whether we want to ignore the result, because the condition number is too large */
2698  if ( maxcondition > 0.0 )
2699  {
2700  /* check estimated condition number of basis matrix */
2702  if ( condition != SCIP_INVALID && condition > maxcondition ) /*lint !e777*/
2703  {
2704  SCIPdebugMsg(scip, "Estimated condition number of basis matrix (%e) exceeds maximal allowance (%e).\n", condition, maxcondition);
2705 
2706  *error = TRUE;
2707 
2708  return SCIP_OKAY;
2709  }
2710  else if ( condition != SCIP_INVALID ) /*lint !e777*/
2711  {
2712  SCIPdebugMsg(scip, "Estimated condition number of basis matrix (%e) is below maximal allowance (%e).\n", condition, maxcondition);
2713  }
2714  else
2715  {
2716  SCIPdebugMsg(scip, "Estimated condition number of basis matrix not available.\n");
2717  }
2718  }
2719 
2720  /* check whether we are in the paradoxical situation that
2721  * - the primal is not infeasible
2722  * - the primal is not unbounded
2723  * - the LP is not optimal
2724  * - we have a primal ray
2725  *
2726  * If we ran the dual simplex algorithm, then we run again with the primal simplex
2727  */
2729  ! SCIPlpiIsOptimal(lp) && SCIPlpiExistsPrimalRay(lp) && ! primal )
2730  {
2731  SCIPwarningMessage(scip, "The dual simplex produced a primal ray. Retrying with primal ...\n");
2732 
2733  /* the following settings might be changed: */
2737 
2738  SCIP_CALL( SCIPlpiSolvePrimal(lp) ); /* use primal simplex */
2739 
2740  /* reset parameters */
2744  }
2745 
2746  /* examine LP solution status */
2747  if ( SCIPlpiIsPrimalInfeasible(lp) ) /* the LP is provably infeasible */
2748  {
2749  assert( ! SCIPlpiIsPrimalUnbounded(lp) ); /* can't be unbounded or optimal */
2750  assert( ! SCIPlpiIsOptimal(lp) ); /* if it is infeasible! */
2751 
2752  *infeasible = TRUE; /* LP is infeasible */
2753  return SCIP_OKAY;
2754  }
2755  else
2756  {
2757  /* By assumption the dual is feasible if the dual simplex is run, therefore
2758  * the status has to be primal unbounded or optimal. */
2759  if ( ! SCIPlpiIsPrimalUnbounded(lp) && ! SCIPlpiIsOptimal(lp) )
2760  {
2761  /* We have a status different from unbounded or optimal. This should not be the case ... */
2762  if (primal)
2763  SCIPwarningMessage(scip, "Primal simplex returned with unknown status: %d\n", SCIPlpiGetInternalStatus(lp));
2764  else
2765  SCIPwarningMessage(scip, "Dual simplex returned with unknown status: %d\n", SCIPlpiGetInternalStatus(lp));
2766 
2767  /* SCIP_CALL( SCIPlpiWriteLP(lp, "debug.lp") ); */
2768  *error = TRUE;
2769  return SCIP_OKAY;
2770  }
2771  }
2772 
2773  /* at this point we have a feasible solution */
2774  *infeasible = FALSE;
2775  return SCIP_OKAY;
2776 }
2777 
2778 
2779 /** tries to extend a given set of variables to a cover
2780  *
2781  * At each step we include a variable which covers a new IIS. The corresponding IIS inequalities are added to the LP,
2782  * if this not already happened.
2783  *
2784  * @pre It is assumed that all parameters for the alternative LP are set and that the variables
2785  * corresponding to @a S are fixed. Furthermore @c xVal_ should contain the current LP solution.
2786  */
2787 static
2789  SCIP* scip, /**< SCIP pointer */
2790  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2791  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
2792  SCIP_LPI* lp, /**< LP */
2793  SCIP_SOL* sol, /**< solution to be separated */
2794  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
2795  SCIP_Bool removable, /**< whether cuts should be removable */
2796  SCIP_Bool genlogicor, /**< should logicor constraints be generated? */
2797  int nconss, /**< number of constraints */
2798  SCIP_CONS** conss, /**< indicator constraints */
2799  SCIP_Bool* S, /**< bitset of variables */
2800  int* size, /**< size of S */
2801  SCIP_Real* value, /**< objective value of S */
2802  SCIP_Bool* error, /**< output: whether an error occurred */
2803  SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
2804  int* nGen /**< number of generated cuts */
2805  )
2806 {
2807 #ifdef SCIP_DEBUG
2808  char name[SCIP_MAXSTRLEN];
2809 #endif
2810  SCIP_Real* primsol;
2811  int nnonviolated = 0;
2812  int step = 0;
2813  int nCols;
2814 
2815  assert( scip != NULL );
2816  assert( lp != NULL );
2817  assert( conss != NULL );
2818  assert( S != NULL );
2819  assert( size != NULL );
2820  assert( value != NULL );
2821  assert( error != NULL );
2822  assert( cutoff != NULL );
2823  assert( nGen != NULL );
2824 
2825  *error = FALSE;
2826  *cutoff = FALSE;
2827  *nGen = 0;
2828 
2829  SCIP_CALL( SCIPlpiGetNCols(lp, &nCols) );
2830  SCIP_CALL( SCIPallocBufferArray(scip, &primsol, nCols) );
2831  assert( nconss <= nCols );
2832 
2833  do
2834  {
2835  SCIP_Bool infeasible;
2836  SCIP_Real sum = 0.0;
2837  SCIP_Real candobj = -1.0;
2838  SCIP_Real candval = 2.0;
2839  SCIP_Real norm = 1.0;
2840  int sizeIIS = 0;
2841  int candidate = -1;
2842  int candindex = -1;
2843  int j;
2844 
2845  if ( step == 0 )
2846  {
2847  /* the first LP is solved without warm start, after that we use a warmstart. */
2849  SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, TRUE, &infeasible, error) );
2851  }
2852  else
2853  SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, FALSE, &infeasible, error) );
2854 
2855  if ( *error )
2856  break;
2857 
2858  /* if the alternative polyhedron is infeasible, we found a cover */
2859  if ( infeasible )
2860  {
2861  /* Note: checking for a primal solution is done in extendToCover(). */
2862  SCIPdebugMsg(scip, " size: %4d produced possible cover with indicator variable objective value %f.\n", *size, *value);
2863 
2864  /* we currently cannot call probing if there are cuts in the sepastore; @todo fix this */
2865  if ( conshdlrdata->trysolfromcover )
2866  {
2867  /* Check whether we want to try to construct a feasible solution: there should be no integer/binary variables
2868  * except the indicator variables. Thus, there should be no integral variables and the number of indicator
2869  * variables should be at least (actually equal to) the number of binary variables. */
2870  if ( SCIPgetNIntVars(scip) == 0 && nconss >= SCIPgetNBinVars(scip) )
2871  {
2872  SCIP_HEUR* heurindicator;
2873 
2874  heurindicator = SCIPfindHeur(scip, "indicator");
2875  if ( heurindicator == NULL )
2876  {
2877  SCIPerrorMessage("Could not find heuristic \"indicator\".\n");
2878  return SCIP_PLUGINNOTFOUND;
2879  }
2880 
2881  SCIP_CALL( SCIPheurPassIndicator(scip, heurindicator, nconss, conss, S, -*value) );
2882  SCIPdebugMsg(scip, "Passed feasible solution to indicator heuristic.\n");
2883  }
2884  }
2885  break;
2886  }
2887 
2888  /* get solution of alternative LP */
2889  SCIP_CALL( SCIPlpiGetSol(lp, NULL, primsol, NULL, NULL, NULL) );
2890 
2891  /* get value of cut and find candidate for variable to add */
2892  for (j = 0; j < nconss; ++j)
2893  {
2894  SCIP_CONSDATA* consdata;
2895  int ind;
2896 
2897  consdata = SCIPconsGetData(conss[j]);
2898  assert( consdata != NULL );
2899  ind = consdata->colindex;
2900 
2901  if ( ind >= 0 )
2902  {
2903  assert( ind < nCols );
2904 
2905  /* check support of the solution, i.e., the corresponding IIS */
2906  if ( ! SCIPisFeasZero(scip, primsol[ind]) )
2907  {
2908  SCIP_Real val;
2909 
2910  assert( ! S[j] );
2911  ++sizeIIS;
2912  val = SCIPgetSolVal(scip, sol, consdata->binvar);
2913  sum += val;
2914 
2915  /* take element with smallest relaxation value */
2916  if ( val < candval )
2917  {
2918  candidate = j;
2919  candindex = ind;
2920  candval = val;
2921  candobj = varGetObjDelta(consdata->binvar);
2922  }
2923  }
2924  }
2925  }
2926 
2927  /* check for error */
2928  if ( candidate < 0 )
2929  {
2930  /* Because of numerical problems it might happen that the solution primsol above is zero
2931  * within the tolerances. In this case we quit. */
2932  break;
2933  }
2934  assert( candidate >= 0 );
2935  assert( ! S[candidate] );
2936  assert( sizeIIS > 0 );
2937 
2938  /* get the type of norm to use for efficacy calculations */
2939  switch ( conshdlrdata->normtype )
2940  {
2941  case 'e':
2942  norm = sqrt((SCIP_Real) sizeIIS);
2943  break;
2944  case 'm':
2945  norm = 1.0;
2946  break;
2947  case 's':
2948  norm = (SCIP_Real) sizeIIS;
2949  break;
2950  case 'd':
2951  norm = 1.0;
2952  break;
2953  default:
2954  SCIPerrorMessage("Invalid efficacy norm parameter '%c'.\n", conshdlrdata->normtype);
2955  SCIPABORT();
2956  norm = 1.0; /*lint !e527*/
2957  }
2958 
2959  SCIPdebugMsg(scip, " size: %4d, add var. %4d (obj: %-6g, alt-LP sol: %-8.4f); IIS size: %4d, eff.: %g.\n",
2960  *size, candidate, candobj, primsol[SCIPconsGetData(conss[candidate])->colindex], sizeIIS, (sum - (SCIP_Real) (sizeIIS - 1))/norm);
2961 
2962  /* update new set S */
2963  S[candidate] = TRUE;
2964  ++(*size);
2965  *value += candobj;
2966 
2967  /* fix chosen variable to 0 */
2968  SCIP_CALL( fixAltLPVariable(lp, candindex) );
2969 
2970  /* if cut is violated, i.e., sum - sizeIIS + 1 > 0 */
2971  if ( SCIPisEfficacious(scip, (sum - (SCIP_Real) (sizeIIS - 1))/norm) )
2972  {
2973  SCIP_Bool isLocal = FALSE;
2974 
2975 #ifdef SCIP_ENABLE_IISCHECK
2976  /* check whether we really have an infeasible subsystem */
2977  SCIP_CALL( checkIIS(scip, nconss, conss, primsol) );
2978 #endif
2979 
2980  /* check whether IIS corresponds to a local cut */
2981  if ( conshdlrdata->updatebounds )
2982  {
2983  SCIP_CALL( checkIISlocal(scip, conshdlrdata, primsol, &isLocal) );
2984  }
2985 
2986  if ( genlogicor )
2987  {
2988  SCIP_RESULT result;
2989  SCIP_CONS* cons;
2990  SCIP_VAR** vars;
2991  int cnt = 0;
2992 
2993  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nconss) );
2994 
2995  /* collect variables corresponding to support to cut */
2996  for (j = 0; j < nconss; ++j)
2997  {
2998  SCIP_CONSDATA* consdata;
2999  int ind;
3000 
3001  consdata = SCIPconsGetData(conss[j]);
3002  ind = consdata->colindex;
3003 
3004  if ( ind >= 0 )
3005  {
3006  assert( ind < nCols );
3007  assert( consdata->binvar != NULL );
3008 
3009  /* check support of the solution, i.e., the corresponding IIS */
3010  if ( ! SCIPisFeasZero(scip, primsol[ind]) )
3011  {
3012  SCIP_VAR* var;
3013  SCIP_CALL( SCIPgetNegatedVar(scip, consdata->binvar, &var) );
3014  vars[cnt++] = var;
3015  }
3016  }
3017  }
3018  assert( cnt == sizeIIS );
3019 
3020 #ifdef SCIP_DEBUG
3021  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "iis%d", conshdlrdata->niiscutsgen + *nGen);
3022  SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, name, cnt, vars, FALSE, TRUE, TRUE, TRUE, TRUE, isLocal, FALSE, TRUE, removable, FALSE) );
3023 #else
3024  SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, "", cnt, vars, FALSE, TRUE, TRUE, TRUE, TRUE, isLocal, FALSE, TRUE, removable, FALSE) );
3025 #endif
3026 
3027 #ifdef SCIP_OUTPUT
3028  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
3029  SCIPinfoMessage(scip, NULL, ";\n");
3030 #endif
3031 
3032  /* enforce or separate logicor constraint to make sure that this has an effect in this round */
3033  switch ( enfosepatype )
3034  {
3035  case SCIP_TYPE_ENFOLP:
3036  SCIP_CALL( SCIPenfolpCons(scip, cons, FALSE, &result) );
3037  break;
3038  case SCIP_TYPE_ENFOPS:
3039  SCIP_CALL( SCIPenfopsCons(scip, cons, FALSE, FALSE, &result) );
3040  break;
3041  case SCIP_TYPE_ENFORELAX:
3042  SCIP_CALL( SCIPenforelaxCons(scip, cons, sol, FALSE, &result) );
3043  break;
3044  case SCIP_TYPE_SEPALP:
3045  SCIP_CALL( SCIPsepalpCons(scip, cons, &result) );
3046  break;
3047  case SCIP_TYPE_SEPARELAX:
3048  case SCIP_TYPE_SEPASOL:
3049  SCIP_CALL( SCIPsepasolCons(scip, cons, sol, &result) );
3050  break;
3051  default:
3052  SCIPerrorMessage("Wrong enforcing/separation type.\n");
3053  SCIPABORT();
3054  }
3055 
3056  SCIP_CALL( SCIPaddCons(scip, cons) );
3057  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3058 
3059  SCIPfreeBufferArray(scip, &vars);
3060  ++(*nGen);
3061  }
3062  else
3063  {
3064  SCIP_ROW* row;
3065 
3066  /* create row */
3067 #ifdef SCIP_DEBUG
3068  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "iis%d", conshdlrdata->niiscutsgen + *nGen);
3069  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, name, -SCIPinfinity(scip), (SCIP_Real) (sizeIIS - 1), isLocal, FALSE, removable) );
3070 #else
3071  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, "", -SCIPinfinity(scip), (SCIP_Real) (sizeIIS - 1), isLocal, FALSE, removable) );
3072 #endif
3073  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
3074 
3075  /* add variables corresponding to support to cut */
3076  for (j = 0; j < nconss; ++j)
3077  {
3078  int ind;
3079  SCIP_CONSDATA* consdata;
3080 
3081  consdata = SCIPconsGetData(conss[j]);
3082  ind = consdata->colindex;
3083 
3084  if ( ind >= 0 )
3085  {
3086  assert( ind < nCols );
3087  assert( consdata->binvar != NULL );
3088 
3089  /* check support of the solution, i.e., the corresponding IIS */
3090  if ( ! SCIPisFeasZero(scip, primsol[ind]) )
3091  {
3092  SCIP_VAR* var = consdata->binvar;
3093  SCIP_CALL( SCIPaddVarToRow(scip, row, var, 1.0) );
3094  }
3095  }
3096  }
3097  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
3098 #ifdef SCIP_OUTPUT
3099  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
3100 #endif
3101  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
3102  if ( *cutoff )
3103  {
3104  SCIPfreeBufferArray(scip, &primsol);
3105  return SCIP_OKAY;
3106  }
3107 
3108  /* cut should be violated: */
3109  assert( SCIPisFeasNegative(scip, SCIPgetRowSolFeasibility(scip, row, sol)) );
3110 
3111  /* add cuts to pool if they are globally valid */
3112  if ( ! isLocal )
3113  SCIP_CALL( SCIPaddPoolCut(scip, row) );
3114  SCIP_CALL( SCIPreleaseRow(scip, &row));
3115  ++(*nGen);
3116  }
3117  nnonviolated = 0;
3118  }
3119  else
3120  ++nnonviolated;
3121  ++step;
3122 
3123  if ( nnonviolated > conshdlrdata->maxsepanonviolated )
3124  {
3125  SCIPdebugMsg(scip, "Stop separation after %d non violated IISs.\n", nnonviolated);
3126  break;
3127  }
3128  }
3129  while (step < nconss);
3130 
3131  SCIPfreeBufferArray(scip, &primsol);
3132 
3133  return SCIP_OKAY;
3134 }
3135 
3136 
3137 /* ---------------------------- constraint handler local methods ----------------------*/
3138 
3139 /** creates and initializes consdata */
3140 static
3142  SCIP* scip, /**< SCIP data structure */
3143  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3144  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3145  const char* consname, /**< name of constraint (or NULL) */
3146  SCIP_CONSDATA** consdata, /**< pointer to linear constraint data */
3147  SCIP_EVENTHDLR* eventhdlrbound, /**< event handler for bound change events */
3148  SCIP_EVENTHDLR* eventhdlrrestart, /**< event handler for handling restarts */
3149  SCIP_VAR* binvar, /**< binary variable (or NULL) */
3150  SCIP_Bool activeone, /**< whether the constraint is active on 1 or not */
3151  SCIP_Bool lessthanineq, /**< whether the original linear constraint is a less-than-rhs (TRUE) or not */
3152  SCIP_VAR* slackvar, /**< slack variable */
3153  SCIP_CONS* lincons, /**< linear constraint (or NULL) */
3154  SCIP_Bool linconsactive /**< whether the linear constraint is active */
3155  )
3156 {
3157  SCIP_VAR* binvarinternal;
3158 
3159  assert( scip != NULL );
3160  assert( conshdlr != NULL );
3161  assert( conshdlrdata != NULL );
3162  assert( consdata != NULL );
3163  assert( slackvar != NULL );
3164  assert( eventhdlrbound != NULL );
3165  assert( eventhdlrrestart != NULL );
3166 
3167  /* if active on 0, the binary variable is reversed */
3168  if ( activeone )
3169  {
3170  binvarinternal = binvar;
3171  }
3172  else
3173  {
3174  SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
3175  }
3176 
3177  /* create constraint data */
3178  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
3179  (*consdata)->nfixednonzero = 0;
3180  (*consdata)->colindex = -1;
3181  (*consdata)->linconsactive = linconsactive;
3182  (*consdata)->binvar = binvarinternal;
3183  (*consdata)->slackvar = slackvar;
3184  (*consdata)->activeone = activeone;
3185  (*consdata)->lessthanineq = lessthanineq;
3186  (*consdata)->lincons = lincons;
3187  (*consdata)->implicationadded = FALSE;
3188  (*consdata)->slacktypechecked = FALSE;
3189 
3190  /* if we are transformed, obtain transformed variables and catch events */
3191  if ( SCIPisTransformed(scip) )
3192  {
3193  SCIP_VAR* var;
3194 
3195  /* handle binary variable */
3196  if ( binvarinternal != NULL )
3197  {
3198  SCIP_CALL( SCIPgetTransformedVar(scip, binvarinternal, &var) );
3199  assert( var != NULL );
3200  (*consdata)->binvar = var;
3201 
3202  /* check type */
3203  if ( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY )
3204  {
3205  SCIPerrorMessage("Indicator variable <%s> is not binary %d.\n", SCIPvarGetName(var), SCIPvarGetType(var));
3206  return SCIP_ERROR;
3207  }
3208 
3209  /* the indicator variable must not be multi-aggregated because the constraint handler propagation tries
3210  * to tighten its bounds, which is not allowed for multi-aggregated variables
3211  */
3212  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) );
3213 
3214  /* catch local bound change events on binary variable */
3215  if ( linconsactive )
3216  {
3217  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlrbound, (SCIP_EVENTDATA*)*consdata, NULL) );
3218  }
3219 
3220  /* catch global bound change events on binary variable */
3221  if ( conshdlrdata->forcerestart )
3222  {
3223  SCIPdebugMsg(scip, "Catching GBDCHANGED event for <%s>.\n", SCIPvarGetName(var));
3224  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
3225  }
3226 
3227  /* if binary variable is fixed to be nonzero */
3228  if ( SCIPvarGetLbLocal(var) > 0.5 )
3229  ++((*consdata)->nfixednonzero);
3230  }
3231 
3232  /* handle slack variable */
3233  SCIP_CALL( SCIPgetTransformedVar(scip, slackvar, &var) );
3234  assert( var != NULL );
3235  (*consdata)->slackvar = var;
3236 
3237  /* catch bound change events on slack variable and adjust nfixednonzero */
3238  if ( linconsactive )
3239  {
3240  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlrbound, (SCIP_EVENTDATA*)*consdata, NULL) );
3241 
3242  /* if slack variable is fixed to be nonzero */
3243  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) )
3244  ++((*consdata)->nfixednonzero);
3245  }
3246 
3247  /* add corresponding column to alternative LP if the constraint is new */
3248  if ( conshdlrdata->sepaalternativelp && SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && lincons != NULL )
3249  {
3250  assert( lincons != NULL );
3251  assert( consname != NULL );
3252 
3253  SCIP_CALL( addAltLPConstraint(scip, conshdlr, lincons, var, 1.0, &(*consdata)->colindex) );
3254 
3255  SCIPdebugMsg(scip, "Added column for <%s> to alternative LP with column index %d.\n", consname, (*consdata)->colindex);
3256 #ifdef SCIP_OUTPUT
3257  SCIP_CALL( SCIPprintCons(scip, lincons, NULL) );
3258  SCIPinfoMessage(scip, NULL, ";\n");
3259 #endif
3260  }
3261 
3262 #ifdef SCIP_DEBUG
3263  if ( (*consdata)->nfixednonzero > 0 )
3264  {
3265  SCIPdebugMsg(scip, "Constraint <%s> has %d variables fixed to be nonzero.\n", consname, (*consdata)->nfixednonzero);
3266  }
3267 #endif
3268  }
3269 
3270  return SCIP_OKAY;
3271 }
3272 
3273 
3274 /** create variable upper bounds for constraints */
3275 static
3277  SCIP* scip, /**< SCIP pointer */
3278  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3279  SCIP_CONS** conss, /**< constraints */
3280  int nconss, /**< number of constraints */
3281  int* ngen /**< number of successful operations */
3282  )
3283 {
3284  char name[50];
3285  int c;
3286 
3287  assert( scip != NULL );
3288  assert( conshdlrdata != NULL );
3289  assert( ngen != NULL );
3290 
3291  *ngen = 0;
3292 
3293  /* check each constraint */
3294  for (c = 0; c < nconss; ++c)
3295  {
3296  SCIP_CONSDATA* consdata;
3297  SCIP_Real ub;
3298 
3299  consdata = SCIPconsGetData(conss[c]);
3300  assert( consdata != NULL );
3301 
3302  ub = SCIPvarGetUbGlobal(consdata->slackvar);
3303  assert( ! SCIPisNegative(scip, ub) );
3304 
3305  /* insert corresponding row if helpful and coefficient is not too large */
3306  if ( ub <= conshdlrdata->maxcouplingvalue )
3307  {
3308  SCIP_CONS* cons;
3309 
3310 #ifndef NDEBUG
3311  (void) SCIPsnprintf(name, 50, "couple%d", c);
3312 #else
3313  name[0] = '\0';
3314 #endif
3315 
3316  SCIPdebugMsg(scip, "Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
3317 
3318  /* add variable upper bound:
3319  * - check constraint if we remove the indicator constraint afterwards
3320  * - constraint is dynamic if we do not remove indicator constraints
3321  * - constraint is removable if we do not remove indicator constraints
3322  */
3323  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
3324  TRUE, TRUE, TRUE, conshdlrdata->removeindicators, TRUE, FALSE, FALSE,
3325  !conshdlrdata->removeindicators, !conshdlrdata->removeindicators, FALSE) );
3326 
3327  SCIP_CALL( SCIPaddCons(scip, cons) );
3328  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3329 
3330  /* remove indicator constraint if required */
3331  if ( conshdlrdata->removeindicators )
3332  {
3333  SCIPdebugMsg(scip, "Removing indicator constraint <%s>.\n", SCIPconsGetName(conss[c]));
3334  assert( ! SCIPconsIsModifiable(conss[c]) );
3335 
3336  /* mark linear constraint to be upgrade-able */
3337  if ( SCIPconsIsActive(consdata->lincons) )
3338  {
3339  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3340  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3341  }
3342 
3343  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
3344  }
3345 
3346  ++(*ngen);
3347  }
3348  }
3349 
3350  return SCIP_OKAY;
3351 }
3352 
3353 
3354 /** perform one presolving round */
3355 static
3357  SCIP* scip, /**< SCIP pointer */
3358  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3359  SCIP_CONS* cons, /**< constraint */
3360  SCIP_CONSDATA* consdata, /**< constraint data */
3361  SCIP_Bool dualreductions, /**< should dual reductions be performed? */
3362  SCIP_Bool* cutoff, /**< whether a cutoff happened */
3363  SCIP_Bool* success, /**< whether we performed a successful reduction */
3364  int* ndelconss, /**< number of deleted constraints */
3365  int* nfixedvars /**< number of fixed variables */
3366  )
3367 {
3368  SCIP_Bool infeasible;
3369  SCIP_Bool fixed;
3370 
3371  assert( scip != NULL );
3372  assert( cons != NULL );
3373  assert( consdata != NULL );
3374  assert( cutoff != NULL );
3375  assert( success != NULL );
3376  assert( ndelconss != NULL );
3377  assert( nfixedvars != NULL );
3378  assert( consdata->binvar != NULL );
3379  assert( consdata->slackvar != NULL );
3380 
3381  *cutoff = FALSE;
3382  *success = FALSE;
3383 
3384  /* if the binary variable is fixed to nonzero */
3385  if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3386  {
3387  SCIPdebugMsg(scip, "Presolving <%s>: Binary variable fixed to 1.\n", SCIPconsGetName(cons));
3388 
3389  /* if slack variable is fixed to nonzero, we are infeasible */
3390  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3391  {
3392  SCIPdebugMsg(scip, "The problem is infeasible: binary and slack variable are fixed to be nonzero.\n");
3393  *cutoff = TRUE;
3394  return SCIP_OKAY;
3395  }
3396 
3397  /* otherwise fix slack variable to 0 */
3398  SCIPdebugMsg(scip, "Fix slack variable to 0 and delete constraint.\n");
3399  SCIP_CALL( SCIPfixVar(scip, consdata->slackvar, 0.0, &infeasible, &fixed) );
3400  assert( ! infeasible );
3401  if ( fixed )
3402  ++(*nfixedvars);
3403 
3404  /* mark linear constraint to be update-able */
3405  if ( SCIPconsIsActive(consdata->lincons) )
3406  {
3407  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3408  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3409  }
3410 
3411  /* delete indicator constraint (leave linear constraint) */
3412  assert( ! SCIPconsIsModifiable(cons) );
3413  SCIP_CALL( SCIPdelCons(scip, cons) );
3414  ++(*ndelconss);
3415  *success = TRUE;
3416  return SCIP_OKAY;
3417  }
3418 
3419  /* if the binary variable is fixed to zero */
3420  if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
3421  {
3422  SCIPdebugMsg(scip, "Presolving <%s>: Binary variable <%s> fixed to 0, deleting indicator constraint.\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->binvar));
3423 
3424  /* mark linear constraint to be update-able */
3425  if ( SCIPconsIsActive(consdata->lincons) )
3426  {
3427  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3428  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3429  }
3430 
3431  /* delete indicator constraint */
3432  assert( ! SCIPconsIsModifiable(cons) );
3433  SCIP_CALL( SCIPdelCons(scip, cons) );
3434  ++(*ndelconss);
3435  *success = TRUE;
3436  return SCIP_OKAY;
3437  }
3438 
3439  /* if the slack variable is fixed to nonzero */
3440  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3441  {
3442  SCIPdebugMsg(scip, "Presolving <%s>: Slack variable fixed to nonzero.\n", SCIPconsGetName(cons));
3443 
3444  /* if binary variable is fixed to nonzero, we are infeasible */
3445  if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3446  {
3447  SCIPdebugMsg(scip, "The problem is infeasible: binary and slack variable are fixed to be nonzero.\n");
3448  *cutoff = TRUE;
3449  return SCIP_OKAY;
3450  }
3451 
3452  /* otherwise fix binary variable to 0 */
3453  SCIPdebugMsg(scip, "Fix binary variable to 0 and delete indicator constraint.\n");
3454  SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
3455  assert( ! infeasible );
3456  if ( fixed )
3457  ++(*nfixedvars);
3458 
3459  /* mark linear constraint to be update-able */
3460  if ( SCIPconsIsActive(consdata->lincons) )
3461  {
3462  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3463  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3464  }
3465 
3466  /* delete constraint */
3467  assert( ! SCIPconsIsModifiable(cons) );
3468  SCIP_CALL( SCIPdelCons(scip, cons) );
3469  ++(*ndelconss);
3470  *success = TRUE;
3471  return SCIP_OKAY;
3472  }
3473 
3474  /* if the slack variable is fixed to zero */
3475  if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3476  {
3477  /* perform dual reductions - if required */
3478  if ( dualreductions )
3479  {
3480  SCIP_VAR* binvar;
3481  SCIP_Real obj;
3482 
3483  /* check objective of binary variable */
3484  binvar = consdata->binvar;
3485  obj = varGetObjDelta(binvar);
3486 
3487  /* if obj = 0, we prefer fixing the binary variable to 1 (if possible) */
3488  if ( obj <= 0.0 )
3489  {
3490  /* In this case we would like to fix the binary variable to 1, if it is not locked up
3491  except by this indicator constraint. If more than one indicator constraint is
3492  effected, we have to hope that they are all fulfilled - in this case the last
3493  constraint will fix the binary variable to 1. */
3494  if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
3495  {
3496  if ( SCIPvarGetUbGlobal(binvar) > 0.5 )
3497  {
3498  SCIPdebugMsg(scip, "Presolving <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
3499  SCIP_CALL( SCIPfixVar(scip, binvar, 1.0, &infeasible, &fixed) );
3500  assert( ! infeasible );
3501  if ( fixed )
3502  ++(*nfixedvars);
3503  /* make sure that the other case does not occur */
3504  obj = -1.0;
3505  }
3506  }
3507  }
3508  if ( obj >= 0.0 )
3509  {
3510  /* In this case we would like to fix the binary variable to 0, if it is not locked down
3511  (should also have been performed by other dual reductions). */
3512  if ( SCIPvarGetNLocksDownType(binvar, SCIP_LOCKTYPE_MODEL) == 0 )
3513  {
3514  if ( SCIPvarGetLbGlobal(binvar) < 0.5 )
3515  {
3516  SCIPdebugMsg(scip, "Presolving <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
3517  SCIP_CALL( SCIPfixVar(scip, binvar, 0.0, &infeasible, &fixed) );
3518  assert( ! infeasible );
3519  if ( fixed )
3520  ++(*nfixedvars);
3521  }
3522  }
3523  }
3524  }
3525 
3526  SCIPdebugMsg(scip, "Presolving <%s>: Slack variable fixed to zero, delete redundant indicator constraint.\n", SCIPconsGetName(cons));
3527 
3528  /* mark linear constraint to be upgrade-able */
3529  if ( SCIPconsIsActive(consdata->lincons) )
3530  {
3531  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3532  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3533  }
3534 
3535  /* delete constraint */
3536  assert( ! SCIPconsIsModifiable(cons) );
3537  SCIP_CALL( SCIPdelCons(scip, cons) );
3538  ++(*ndelconss);
3539  *success = TRUE;
3540  return SCIP_OKAY;
3541  }
3542 
3543  /* check whether indicator variable is aggregated */
3544  if ( SCIPvarGetStatus(consdata->binvar) == SCIP_VARSTATUS_AGGREGATED )
3545  {
3546  SCIP_Bool negated = FALSE;
3547  SCIP_VAR* var;
3548 
3549  /* possibly get representation of indicator variable by active variable */
3550  var = consdata->binvar;
3551  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
3552  assert( var == consdata->binvar || SCIPvarIsActive(var) || SCIPvarIsNegated(var) );
3553 
3554  /* we can replace the binary variable by the active variable if it is not negated */
3555  if ( var != consdata->binvar && ! negated )
3556  {
3557  SCIPdebugMsg(scip, "Indicator variable <%s> is aggregated and replaced by active/negated variable <%s>.\n", SCIPvarGetName(consdata->binvar), SCIPvarGetName(var) );
3558 
3559  /* we need to update the events and locks */
3560  assert( conshdlrdata->eventhdlrbound != NULL );
3561  SCIP_CALL( SCIPdropVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, -1) );
3562  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, NULL) );
3563 
3564  /* We also need to update the events and locks if restart is forced, since global bound change events on binary
3565  * variables are also caught in this case. If it would not be updated and forcerestart = TRUE, then an event
3566  * might be dropped on a wrong variable. */
3567  if ( conshdlrdata->forcerestart )
3568  {
3569  assert( conshdlrdata->eventhdlrrestart != NULL );
3570  SCIP_CALL( SCIPdropVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_GBDCHANGED,
3571  conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, -1) );
3572  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
3573  (SCIP_EVENTDATA*) conshdlrdata, NULL) );
3574  }
3575 
3576  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->binvar, SCIP_LOCKTYPE_MODEL, 0, -1) );
3577  SCIP_CALL( SCIPaddVarLocksType(scip, var, SCIP_LOCKTYPE_MODEL, 0, 1) );
3578 
3579  /* change binvary variable */
3580  consdata->binvar = var;
3581  }
3582  }
3583  else if ( SCIPvarGetStatus(consdata->binvar) == SCIP_VARSTATUS_NEGATED )
3584  {
3585  SCIP_VAR* var;
3586 
3587  var = SCIPvarGetNegatedVar(consdata->binvar);
3588  assert( var != NULL );
3589 
3590  /* if the binary variable is the negated slack variable, we have 1 - s = 1 -> s = 0, i.e., the constraint is redundant */
3591  if ( var == consdata->slackvar )
3592  {
3593  /* delete constraint */
3594  assert( ! SCIPconsIsModifiable(cons) );
3595  SCIP_CALL( SCIPdelCons(scip, cons) );
3596  ++(*ndelconss);
3597  *success = TRUE;
3598  return SCIP_OKAY;
3599  }
3600  }
3601 
3602  /* check whether slack variable is aggregated */
3603  if ( SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_AGGREGATED || SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_NEGATED )
3604  {
3606  SCIP_Real bound;
3607  SCIP_VAR* var;
3608 
3609  /* possibly get representation of slack variable by active variable */
3610  var = consdata->slackvar;
3611  bound = SCIPvarGetLbGlobal(var);
3612 
3613  SCIP_CALL( SCIPvarGetProbvarBound(&var, &bound, &boundtype) );
3614  assert( var != consdata->slackvar );
3615 
3616  /* we can replace the slack variable by the active variable if it is also a >= variable */
3617  if ( var != consdata->binvar && boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisEQ(scip, bound, 0.0) )
3618  {
3619  assert( SCIPvarIsActive(var) );
3620  SCIPdebugMsg(scip, "Slack variable <%s> is aggregated or negated and replaced by active variable <%s>.\n", SCIPvarGetName(consdata->slackvar), SCIPvarGetName(var) );
3621 
3622  /* we need to update the events, locks, and captures */
3623  assert( conshdlrdata->eventhdlrbound != NULL );
3624  SCIP_CALL( SCIPdropVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, -1) );
3625  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) consdata, NULL) );
3626 
3627  SCIP_CALL( SCIPunlockVarCons(scip, consdata->slackvar, cons, FALSE, TRUE) );
3628  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
3629 
3630  SCIP_CALL( SCIPreleaseVar(scip, &consdata->slackvar) );
3631  SCIP_CALL( SCIPcaptureVar(scip, var) );
3632 
3633  /* change slack variable */
3634  consdata->slackvar = var;
3635  }
3636  else if ( var == consdata->binvar )
3637  {
3638  /* check special case that aggregating variable is equal to the indicator variable */
3639  assert( SCIPisEQ(scip, bound, 0.0) || SCIPisEQ(scip, bound, 1.0) );
3640 
3641  /* if the lower bound is transformed to an upper bound, we have "y = 1 -> 1 - y = 0", i.e., the constraint is redundant */
3642  if ( boundtype == SCIP_BOUNDTYPE_UPPER )
3643  {
3644  SCIPdebugMsg(scip, "Slack variable <%s> is aggregated to negated indicator variable <%s> -> constraint redundant.\n",
3645  SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3646  assert( SCIPisEQ(scip, bound, 1.0) );
3647 
3648  /* delete constraint */
3649  assert( ! SCIPconsIsModifiable(cons) );
3650  SCIP_CALL( SCIPdelCons(scip, cons) );
3651  ++(*ndelconss);
3652  *success = TRUE;
3653  return SCIP_OKAY;
3654  }
3655  else
3656  {
3657  /* 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 */
3658  SCIPdebugMsg(scip, "Slack variable <%s> is aggregated to the indicator variable <%s> -> fix indicator variable to 0.\n",
3659  SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3660  assert( boundtype == SCIP_BOUNDTYPE_LOWER );
3661  assert( SCIPisEQ(scip, bound, 0.0) );
3662 
3663  SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
3664  assert( ! infeasible );
3665 
3666  if ( fixed )
3667  ++(*nfixedvars);
3668 
3669  SCIP_CALL( SCIPdelCons(scip, cons) );
3670 
3671  ++(*ndelconss);
3672  *success = TRUE;
3673 
3674  return SCIP_OKAY;
3675  }
3676  }
3677  }
3678 
3679  /* Note that because of possible multi-aggregation we cannot simply remove the indicator
3680  * constraint if the linear constraint is not active or disabled - see the note in @ref
3681  * PREPROC. */
3682 
3683  return SCIP_OKAY;
3684 }
3685 
3686 
3687 /** propagate indicator constraint */
3688 static
3690  SCIP* scip, /**< SCIP pointer */
3691  SCIP_CONS* cons, /**< constraint */
3692  SCIP_CONSDATA* consdata, /**< constraint data */
3693  SCIP_Bool dualreductions, /**< should dual reductions be performed? */
3694  SCIP_Bool addopposite, /**< add opposite inequalities if binary var = 0? */
3695  SCIP_Bool* cutoff, /**< whether a cutoff happened */
3696  int* nGen /**< number of domain changes */
3697  )
3698 {
3699  SCIP_Bool infeasible;
3700  SCIP_Bool tightened;
3701 
3702  assert( scip != NULL );
3703  assert( cons != NULL );
3704  assert( consdata != NULL );
3705  assert( cutoff != NULL );
3706  assert( nGen != NULL );
3707 
3708  *cutoff = FALSE;
3709  *nGen = 0;
3710 
3711  /* if the linear constraint has not been generated, we do nothing */
3712  if ( ! consdata->linconsactive )
3713  return SCIP_OKAY;
3714 
3715  assert( consdata->slackvar != NULL );
3716  assert( consdata->binvar != NULL );
3717  assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(consdata->slackvar), 0.0) );
3718 
3719  /* if both slackvar and binvar are fixed to be nonzero */
3720  if ( consdata->nfixednonzero > 1 )
3721  {
3722  SCIPdebugMsg(scip, "The node is infeasible, both the slack variable and the binary variable are fixed to be nonzero.\n");
3723  *cutoff = TRUE;
3724 
3725  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3726  assert( SCIPvarGetLbLocal(consdata->binvar) > 0.5 );
3727  assert( SCIPisPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) );
3728 
3729  /* check if conflict analysis is turned on */
3730  if ( ! SCIPisConflictAnalysisApplicable(scip) )
3731  return SCIP_OKAY;
3732 
3733  /* conflict analysis can only be applied in solving stage */
3734  assert( SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip) );
3735 
3736  /* perform conflict analysis */
3738 
3739  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->binvar) );
3740  SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, NULL) );
3741  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
3742 
3743  return SCIP_OKAY;
3744  }
3745 
3746  /* if exactly one of the variables is fixed to be nonzero */
3747  if ( consdata->nfixednonzero == 1 )
3748  {
3749  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
3750  if ( ! SCIPinRepropagation(scip) )
3751  SCIP_CALL( SCIPincConsAge(scip, cons) );
3752 
3753  /* if binvar is fixed to be nonzero */
3754  if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3755  {
3756  assert( SCIPvarGetStatus(consdata->slackvar) != SCIP_VARSTATUS_MULTAGGR );
3757 
3758  /* if slack variable is not already fixed to 0 */
3759  if ( ! SCIPisZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3760  {
3761  SCIPdebugMsg(scip, "Binary variable <%s> is fixed to be nonzero, fixing slack variable <%s> to 0.\n",
3762  SCIPvarGetName(consdata->binvar), SCIPvarGetName(consdata->slackvar));
3763 
3764  /* fix slack variable to 0 */
3765  SCIP_CALL( SCIPinferVarUbCons(scip, consdata->slackvar, 0.0, cons, 0, FALSE, &infeasible, &tightened) );
3766  assert( ! infeasible );
3767  if ( tightened )
3768  ++(*nGen);
3769  }
3770  }
3771 
3772  /* if slackvar is fixed to be nonzero */
3773  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3774  {
3775  /* if binary variable is not yet fixed to 0 */
3776  if ( SCIPvarGetUbLocal(consdata->binvar) > 0.5 )
3777  {
3778  SCIPdebugMsg(scip, "Slack variable <%s> is fixed to be nonzero, fixing binary variable <%s> to 0.\n",
3779  SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3780 
3781  /* fix binary variable to 0 */
3782  SCIP_CALL( SCIPinferVarUbCons(scip, consdata->binvar, 0.0, cons, 1, FALSE, &infeasible, &tightened) );
3783  assert( ! infeasible );
3784  if ( tightened )
3785  ++(*nGen);
3786  }
3787  }
3788 
3789  /* reset constraint age counter */
3790  if ( *nGen > 0 )
3791  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3792 
3793  /* remove constraint if we are not in probing */
3794  if ( ! SCIPinProbing(scip) )
3795  {
3796  /* mark linear constraint to be update-able */
3797  if ( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && SCIPconsIsActive(consdata->lincons) )
3798  {
3799  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3800  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3801  }
3802 
3803  /* delete constraint locally */
3804  assert( ! SCIPconsIsModifiable(cons) );
3805  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3806  }
3807  }
3808  else
3809  {
3810  /* if the binary variable is fixed to zero */
3811  if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
3812  {
3813  if ( addopposite && consdata->linconsactive )
3814  {
3815  char name[SCIP_MAXSTRLEN];
3816  SCIP_CONS* reversecons;
3817  SCIP_VAR** linvars;
3818  SCIP_Real* linvals;
3819  SCIP_Bool allintegral = TRUE;
3820  SCIP_VAR* slackvar;
3821  SCIP_VAR** vars;
3822  SCIP_Real* vals;
3823  SCIP_Real lhs;
3824  SCIP_Real rhs;
3825  int nlinvars;
3826  int nvars = 0;
3827  int j;
3828 
3829  /* determine lhs/rhs (first exchange lhs/rhs) */
3830  lhs = SCIPgetRhsLinear(scip, consdata->lincons);
3831  if ( SCIPisInfinity(scip, lhs) )
3832  lhs = -SCIPinfinity(scip);
3833  rhs = SCIPgetLhsLinear(scip, consdata->lincons);
3834  if ( SCIPisInfinity(scip, -rhs) )
3835  rhs = SCIPinfinity(scip);
3836 
3837  assert( ! SCIPisInfinity(scip, lhs) );
3838  assert( ! SCIPisInfinity(scip, -rhs) );
3839 
3840  /* consider only finite lhs/rhs */
3841  if ( ! SCIPisInfinity(scip, -lhs) || ! SCIPisInfinity(scip, rhs) )
3842  {
3843  /* ignore equations (cannot add opposite constraint) */
3844  if ( ! SCIPisEQ(scip, lhs, rhs) )
3845  {
3846  assert( consdata->lincons != NULL );
3847  nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
3848  linvars = SCIPgetVarsLinear(scip, consdata->lincons);
3849  linvals = SCIPgetValsLinear(scip, consdata->lincons);
3850  slackvar = consdata->slackvar;
3851  assert( slackvar != NULL );
3852 
3853  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlinvars) );
3854  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlinvars) );
3855 
3856  /* copy data and check whether the linear constraint is integral */
3857  for (j = 0; j < nlinvars; ++j)
3858  {
3859  if ( linvars[j] != slackvar )
3860  {
3861  if (! SCIPvarIsIntegral(linvars[j]) || ! SCIPisIntegral(scip, linvals[j]) )
3862  allintegral = FALSE;
3863 
3864  vars[nvars] = linvars[j];
3865  vals[nvars++] = linvals[j];
3866  }
3867  }
3868  assert( nlinvars == nvars + 1 );
3869 
3870  /* possibly adjust lhs/rhs */
3871  if ( allintegral && ! SCIPisInfinity(scip, REALABS(lhs)) )
3872  lhs += 1.0;
3873 
3874  if ( allintegral && ! SCIPisInfinity(scip, REALABS(rhs)) )
3875  rhs -= 1.0;
3876 
3877  /* create reverse constraint */
3878  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "reverse_%s", SCIPconsGetName(consdata->lincons));
3879 
3880  /* constraint is initial, separated, not enforced, not checked, propagated, local, not modifiable, dynamic, removable */
3881  SCIP_CALL( SCIPcreateConsLinear(scip, &reversecons, name, nvars, vars, vals, lhs, rhs,
3882  TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE) );
3883 
3884  SCIPdebugMsg(scip, "Binary variable <%s> fixed to 0. Adding opposite linear inequality.\n", SCIPvarGetName(consdata->binvar));
3885  SCIPdebugPrintCons(scip, reversecons, NULL);
3886 
3887  /* add constraint */
3888  SCIP_CALL( SCIPaddCons(scip, reversecons) );
3889  SCIP_CALL( SCIPreleaseCons(scip, &reversecons) );
3890 
3891  SCIPfreeBufferArray(scip, &vals);
3892  SCIPfreeBufferArray(scip, &vars);
3893  }
3894  }
3895  }
3896 
3897  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3898  }
3899 
3900  /* if the slack variable is fixed to zero */
3901  if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3902  {
3903  /* perform dual reduction - if required */
3904  if ( dualreductions )
3905  {
3906  SCIP_VAR* binvar;
3907  SCIP_Real obj;
3908 
3909  /* check objective of binary variable */
3910  binvar = consdata->binvar;
3911  obj = varGetObjDelta(binvar);
3912 
3913  /* if obj = 0, we prefer setting the binary variable to 1 (if possible) */
3914  if ( obj <= 0.0 )
3915  {
3916  /* In this case we would like to fix the binary variable to 1, if it is not locked up
3917  except by this indicator constraint. If more than one indicator constraint is
3918  affected, we have to hope that they are all fulfilled - in this case the last
3919  constraint will fix the binary variable to 1. */
3920  if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
3921  {
3922  if ( SCIPvarGetUbLocal(binvar) > 0.5 )
3923  {
3924  SCIPdebugMsg(scip, "Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
3925  SCIP_CALL( SCIPinferVarLbCons(scip, binvar, 1.0, cons, 2, FALSE, &infeasible, &tightened) );
3926  assert( ! infeasible );
3927  if ( tightened )
3928  ++(*nGen);
3929  /* Make sure that the other case does not occur, since we are not sure whether SCIPinferVarLbCons() directly changes the bounds. */
3930  obj = -1.0;
3931  }
3932  }
3933  }
3934  if ( obj >= 0.0 )
3935  {
3936  /* In this case we would like to fix the binary variable to 0, if it is not locked down
3937  (should also have been performed by other dual reductions). */
3938  if ( SCIPvarGetNLocksDownType(binvar, SCIP_LOCKTYPE_MODEL) == 0 )
3939  {
3940  if ( SCIPvarGetLbLocal(binvar) < 0.5 )
3941  {
3942  SCIPdebugMsg(scip, "Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
3943  SCIP_CALL( SCIPinferVarUbCons(scip, binvar, 0.0, cons, 2, FALSE, &infeasible, &tightened) );
3944  assert( ! infeasible );
3945  if ( tightened )
3946  ++(*nGen);
3947  }
3948  }
3949  }
3950  }
3951 
3952  SCIPdebugMsg(scip, "Slack variable fixed to zero, delete redundant indicator constraint <%s>.\n", SCIPconsGetName(cons));
3953 
3954  /* delete constraint */
3955  assert( ! SCIPconsIsModifiable(cons) );
3956 
3957  /* remove constraint if we are not in probing */
3958  if ( ! SCIPinProbing(scip) )
3959  {
3960  /* mark linear constraint to be update-able */
3961  if ( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && SCIPconsIsActive(consdata->lincons) )
3962  {
3963  SCIPconsAddUpgradeLocks(consdata->lincons, -1);
3964  assert( SCIPconsGetNUpgradeLocks(consdata->lincons) == 0 );
3965  }
3966 
3967  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3968  }
3969  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3970  }
3971 
3972  /* Note that because of possible multi-aggregation we cannot simply remove the indicator
3973  * constraint if the linear constraint is not active or disabled - see the note in @ref
3974  * PREPROC and consPresolIndicator(). Moreover, it would drastically increase memory
3975  * consumption, because the linear constraints have to be stored in each node. */
3976  }
3977 
3978  return SCIP_OKAY;
3979 }
3980 
3981 
3982 /** enforcement method that produces cuts if possible
3983  *
3984  * This is a variant of the enforcement method that generates cuts/constraints via the alternative
3985  * LP, if possible.
3986  */
3987 static
3989  SCIP* scip, /**< SCIP pointer */
3990  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3991  int nconss, /**< number of constraints */
3992  SCIP_CONS** conss, /**< indicator constraints */
3993  SCIP_SOL* sol, /**< solution to be enforced */
3994  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
3995  SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
3996  SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
3997  int* nGen /**< number of cuts generated */
3998  )
3999 {
4000  SCIP_CONSHDLRDATA* conshdlrdata;
4001  SCIP_LPI* lp;
4002  SCIP_Bool* S;
4003  SCIP_Real value = 0.0;
4004  SCIP_Bool error;
4005  int size = 0;
4006  int nCuts;
4007  int j;
4008 
4009  assert( scip != NULL );
4010  assert( conshdlr != NULL );
4011  assert( conss != NULL );
4012  assert( cutoff != NULL );
4013  assert( nGen != NULL );
4014 
4015  SCIPdebugMsg(scip, "Enforcing via cuts ...\n");
4016  *cutoff = FALSE;
4017  *nGen = 0;
4018 
4019  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4020  assert( conshdlrdata != NULL );
4021  lp = conshdlrdata->altlp;
4022  assert( lp != NULL );
4023 
4024 #ifndef NDEBUG
4025  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4026 #endif
4027 
4028  /* change coefficients of bounds in alternative LP */
4029  if ( conshdlrdata->updatebounds )
4030  SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
4031 
4032  /* possibly update upper bound */
4033  SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4034 
4035  /* scale first row if necessary */
4036  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
4037 
4038  /* set objective function to current solution */
4039  SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
4040 
4041  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
4042 
4043  /* set up variables fixed to 1 */
4044  for (j = 0; j < nconss; ++j)
4045  {
4046  SCIP_CONSDATA* consdata;
4047 
4048  assert( conss[j] != NULL );
4049  consdata = SCIPconsGetData(conss[j]);
4050  assert( consdata != NULL );
4051 
4052  assert( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
4053  if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
4054  {
4055  ++size;
4056  value += varGetObjDelta(consdata->binvar);
4057  S[j] = TRUE;
4058  }
4059  else
4060  S[j] = FALSE;
4061  }
4062 
4063  /* fix the variables in S */
4064  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
4065 
4066  /* extend set S to a cover and generate cuts */
4067  error = FALSE;
4068  SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, genlogicor, nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
4069  *nGen = nCuts;
4070 
4071  /* return with an error if no cuts have been produced and and error occurred in extendToCover() */
4072  if ( nCuts == 0 && error )
4073  return SCIP_LPERROR;
4074 
4075  SCIPdebugMsg(scip, "Generated %d IIS-cuts.\n", nCuts);
4076 
4077  /* reset bounds */
4078  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
4079 
4080 #ifndef NDEBUG
4081  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4082 #endif
4083 
4084  SCIPfreeBufferArray(scip, &S);
4085 
4086  return SCIP_OKAY;
4087 }
4088 
4089 
4090 /** enforcement method
4091  *
4092  * We check whether the current solution is feasible, i.e., if binvar = 1
4093  * implies that slackvar = 0. If not, we branch as follows:
4094  *
4095  * In one branch we fix binvar = 1 and slackvar = 0. In the other branch
4096  * we fix binvar = 0 and leave slackvar unchanged.
4097  */
4098 static
4100  SCIP* scip, /**< SCIP pointer */
4101  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4102  int nconss, /**< number of constraints */
4103  SCIP_CONS** conss, /**< indicator constraints */
4104  SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
4105  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4106  SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
4107  SCIP_RESULT* result /**< result */
4108  )
4109 {
4110  SCIP_CONSDATA* consdata;
4111  SCIP_CONSHDLRDATA* conshdlrdata;
4112  SCIP_NODE* node1;
4113  SCIP_NODE* node2;
4114  SCIP_VAR* slackvar;
4115  SCIP_VAR* binvar;
4117  SCIP_Real maxSlack = -1.0;
4118  SCIP_Bool someLinconsNotActive = FALSE;
4119  int c;
4120 
4121  assert( scip != NULL );
4122  assert( conshdlr != NULL );
4123  assert( conss != NULL );
4124  assert( result != NULL );
4125 
4126  *result = SCIP_FEASIBLE;
4127 
4128  SCIPdebugMsg(scip, "Enforcing indicator constraints for <%s> ...\n", SCIPconshdlrGetName(conshdlr) );
4129 
4130  /* get constraint handler data */
4131  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4132  assert( conshdlrdata != NULL );
4133 
4134 #ifdef SCIP_OUTPUT
4135  SCIP_CALL( SCIPwriteTransProblem(scip, "ind.cip", "cip", FALSE) );
4136 #endif
4137 
4138  /* check each constraint */
4139  for (c = 0; c < nconss; ++c)
4140  {
4141  SCIP_Bool cutoff;
4142  SCIP_Real valSlack;
4143  int cnt;
4144 
4145  assert( conss[c] != NULL );
4146  consdata = SCIPconsGetData(conss[c]);
4147  assert( consdata != NULL );
4148  assert( consdata->lincons != NULL );
4149 
4150  /* if the linear constraint has not been generated, we do nothing */
4151  if ( ! consdata->linconsactive )
4152  {
4153  someLinconsNotActive = TRUE;
4154  continue;
4155  }
4156 
4157  /* first perform propagation (it might happen that standard propagation is turned off) */
4158  SCIP_CALL( propIndicator(scip, conss[c], consdata,
4159  conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip), conshdlrdata->addopposite,
4160  &cutoff, &cnt) );
4161  if ( cutoff )
4162  {
4163  SCIPdebugMsg(scip, "Propagation in enforcing <%s> detected cutoff.\n", SCIPconsGetName(conss[c]));
4164  *result = SCIP_CUTOFF;
4165  return SCIP_OKAY;
4166  }
4167  if ( cnt > 0 )
4168  {
4169  SCIPdebugMsg(scip, "Propagation in enforcing <%s> reduced domains: %d.\n", SCIPconsGetName(conss[c]), cnt);
4170  *result = SCIP_REDUCEDDOM;
4171  return SCIP_OKAY;
4172  }
4173 
4174  /* check whether constraint is infeasible */
4175  binvar = consdata->binvar;
4176  valSlack = SCIPgetSolVal(scip, sol, consdata->slackvar);
4177  assert( ! SCIPisFeasNegative(scip, valSlack) );
4178  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, binvar)) && ! SCIPisFeasZero(scip, valSlack) )
4179  {
4180  /* binary variable is not fixed - otherwise we would not be infeasible */
4181  assert( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 );
4182 
4183  if ( valSlack > maxSlack )
4184  {
4185  maxSlack = valSlack;
4186  branchCons = conss[c];
4187 #ifdef SCIP_OUTPUT
4188  SCIPinfoMessage(scip, NULL, "Violated indicator constraint:\n");
4189  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
4190  SCIPinfoMessage(scip, NULL, ";\n");
4191  SCIPinfoMessage(scip, NULL, "Corresponding linear constraint:\n");
4192  SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
4193  SCIPinfoMessage(scip, NULL, ";\n");
4194 #endif
4195  }
4196  }
4197  }
4198 
4199  /* if some constraint has a linear constraint that is not active, we need to check feasibility via the alternative polyhedron */
4200  if ( (someLinconsNotActive || conshdlrdata->enforcecuts) && conshdlrdata->sepaalternativelp )
4201  {
4202  SCIP_Bool cutoff;
4203  int ngen;
4204 
4205  SCIP_CALL( enforceCuts(scip, conshdlr, nconss, conss, sol, enfosepatype, genlogicor, &cutoff, &ngen) );
4206  if ( cutoff )
4207  {
4208  conshdlrdata->niiscutsgen += ngen;
4209  *result = SCIP_CUTOFF;
4210  return SCIP_OKAY;
4211  }
4212 
4213  if ( ngen > 0 )
4214  {
4215  conshdlrdata->niiscutsgen += ngen;
4216  if ( genlogicor )
4217  {
4218  SCIPdebugMsg(scip, "Generated %d constraints.\n", ngen);
4219  *result = SCIP_CONSADDED;
4220  }
4221  else
4222  {
4223  SCIPdebugMsg(scip, "Generated %d cuts.\n", ngen);
4224  *result = SCIP_SEPARATED;
4225  }
4226  return SCIP_OKAY;
4227  }
4228  SCIPdebugMsg(scip, "Enforcing produced no cuts.\n");
4229 
4230  assert( ! someLinconsNotActive || branchCons == NULL );
4231  }
4232 
4233  /* if all constraints are feasible */
4234  if ( branchCons == NULL )
4235  {
4236  SCIPdebugMsg(scip, "All indicator constraints are feasible.\n");
4237  return SCIP_OKAY;
4238  }
4239 
4240  /* skip branching if required */
4241  if ( ! conshdlrdata->branchindicators )
4242  {
4243  *result = SCIP_INFEASIBLE;
4244  return SCIP_OKAY;
4245  }
4246 
4247  /* otherwise create branches */
4248  SCIPdebugMsg(scip, "Branching on constraint <%s> (slack value: %f).\n", SCIPconsGetName(branchCons), maxSlack);
4249  consdata = SCIPconsGetData(branchCons);
4250  assert( consdata != NULL );
4251  binvar = consdata->binvar;
4252  slackvar = consdata->slackvar;
4253 
4254  /* node1: binvar = 1, slackvar = 0 */
4255  SCIP_CALL( SCIPcreateChild(scip, &node1, 0.0, SCIPcalcChildEstimate(scip, binvar, 1.0) ) );
4256 
4257  if ( SCIPvarGetLbLocal(binvar) < 0.5 )
4258  {
4259  SCIP_CALL( SCIPchgVarLbNode(scip, node1, binvar, 1.0) );
4260  }
4261 
4262  /* if slack-variable is multi-aggregated */
4263  assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
4264  if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(slackvar)) )
4265  {
4266  SCIP_CALL( SCIPchgVarUbNode(scip, node1, slackvar, 0.0) );
4267  }
4268 
4269  /* node2: binvar = 0, no restriction on slackvar */
4270  SCIP_CALL( SCIPcreateChild(scip, &node2, 0.0, SCIPcalcChildEstimate(scip, binvar, 0.0) ) );
4271 
4272  if ( SCIPvarGetUbLocal(binvar) > 0.5 )
4273  {
4274  SCIP_CALL( SCIPchgVarUbNode(scip, node2, binvar, 0.0) );
4275  }
4276 
4277  SCIP_CALL( SCIPresetConsAge(scip, branchCons) );
4278  *result = SCIP_BRANCHED;
4279 
4280  return SCIP_OKAY;
4281 }
4282 
4283 
4284 /** separate IIS-cuts via rounding
4285  *
4286  * @todo Check whether the cover produced at the end is a feasible solution.
4287  */
4288 static
4290  SCIP* scip, /**< SCIP pointer */
4291  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4292  SCIP_SOL* sol, /**< solution to be separated */
4293  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4294  int nconss, /**< number of constraints */
4295  SCIP_CONS** conss, /**< indicator constraints */
4296  int maxsepacuts, /**< maximal number of cuts to be generated */
4297  SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
4298  int* nGen /**< number of domain changes */
4299  )
4300 { /*lint --e{850}*/
4301  SCIP_CONSHDLRDATA* conshdlrdata;
4302  SCIP_LPI* lp;
4303  int rounds;
4304  SCIP_Real threshold;
4305  SCIP_Bool* S;
4306  SCIP_Bool error;
4307  int oldsize = -1;
4308  SCIPdebug( int nGenOld = *nGen; )
4309 
4310  assert( scip != NULL );
4311  assert( conshdlr != NULL );
4312  assert( conss != NULL );
4313  assert( cutoff != NULL );
4314  assert( nGen != NULL );
4315 
4316  if ( *nGen >= maxsepacuts )
4317  return SCIP_OKAY;
4318 
4319  *cutoff = FALSE;
4320  rounds = 0;
4321 
4322  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4323  assert( conshdlrdata != NULL );
4324  lp = conshdlrdata->altlp;
4325  assert( lp != NULL );
4326 
4327  SCIPdebugMsg(scip, "Separating IIS-cuts by rounding ...\n");
4328 
4329 #ifndef NDEBUG
4330  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4331 #endif
4332 
4333  /* change coefficients of bounds in alternative LP */
4334  if ( conshdlrdata->updatebounds )
4335  {
4336  /* update to local bounds */
4337  SCIP_CALL( updateFirstRow(scip, conshdlrdata) );
4338  }
4339 
4340  /* possibly update upper bound */
4341  SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4342 
4343  /* scale first row if necessary */
4344  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
4345 
4346  /* set objective function to current solution */
4347  SCIP_CALL( setAltLPObj(scip, lp, sol, nconss, conss) );
4348 
4349  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
4350 
4351  /* loop through the possible thresholds */
4352  for (threshold = conshdlrdata->roundingmaxthres;
4353  rounds < conshdlrdata->maxroundingrounds && threshold >= conshdlrdata->roundingminthres && *nGen < maxsepacuts && ! (*cutoff);
4354  threshold -= conshdlrdata->roundingoffset )
4355  {
4356  SCIP_Real value = 0.0;
4357  int size = 0;
4358  int nCuts = 0;
4359  int j;
4360 #ifdef SCIP_DEBUG
4361  int nvarsone = 0;
4362  int nvarszero = 0;
4363  int nvarsfrac = 0;
4364 #endif
4365 
4366  SCIPdebugMsg(scip, "Threshold: %g.\n", threshold);
4367 
4368  /* choose variables that have a value < current threshold value */
4369  for (j = 0; j < nconss; ++j)
4370  {
4371  SCIP_CONSDATA* consdata;
4372  SCIP_Real binvarval;
4373  SCIP_VAR* binvarneg;
4374 
4375  assert( conss[j] != NULL );
4376  consdata = SCIPconsGetData(conss[j]);
4377  assert( consdata != NULL );
4378 
4379  binvarval = SCIPgetVarSol(scip, consdata->binvar);
4380 
4381 #ifdef SCIP_DEBUG
4382  if ( SCIPisFeasEQ(scip, binvarval, 1.0) )
4383  ++nvarsone;
4384  else if ( SCIPisFeasZero(scip, binvarval) )
4385  ++nvarszero;
4386  else
4387  ++nvarsfrac;
4388 #endif
4389 
4390  /* check whether complementary (negated) variable is present as well */
4391  binvarneg = SCIPvarGetNegatedVar(consdata->binvar);
4392  assert( binvarneg != NULL );
4393 
4394  /* negated variable is present as well */
4395  assert( conshdlrdata->binvarhash != NULL );
4396  if ( SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarneg) )
4397  {
4398  SCIP_Real binvarnegval = SCIPgetVarSol(scip, binvarneg);
4399 
4400  /* take larger one */
4401  if ( binvarval > binvarnegval )
4402  S[j] = TRUE;
4403  else
4404  S[j] = FALSE;
4405  continue;
4406  }
4407 
4408  /* check for threshold */
4409  if ( SCIPisFeasLT(scip, SCIPgetVarSol(scip, consdata->binvar), threshold) )
4410  {
4411  S[j] = TRUE;
4412  value += varGetObjDelta(consdata->binvar);
4413  ++size;
4414  }
4415  else
4416  S[j] = FALSE;
4417  }
4418 
4419  if ( size == nconss )
4420  {
4421  SCIPdebugMsg(scip, "All variables in the set. Continue ...\n");
4422  continue;
4423  }
4424 
4425  /* skip computation if size has not changed (computation is likely the same) */
4426  if ( size == oldsize )
4427  {
4428  SCIPdebugMsg(scip, "Skipping computation: size support has not changed.\n");
4429  continue;
4430  }
4431  oldsize = size;
4432 
4433 #ifdef SCIP_DEBUG
4434  SCIPdebugMsg(scip, " Vars with value 1: %d 0: %d and fractional: %d.\n", nvarsone, nvarszero, nvarsfrac);
4435 #endif
4436 
4437  /* fix the variables in S */
4438  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
4439 
4440  /* extend set S to a cover and generate cuts */
4441  SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, conshdlrdata->genlogicor,
4442  nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
4443 
4444  /* we ignore errors in extendToCover */
4445  if ( nCuts > 0 )
4446  {
4447  *nGen += nCuts;
4448  ++rounds;
4449  }
4450  else
4451  {
4452  /* possibly update upper bound */
4453  SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4454  }
4455 
4456  /* reset bounds */
4457  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
4458  }
4459  SCIPdebug( SCIPdebugMsg(scip, "Generated %d IISs.\n", *nGen - nGenOld); )
4460 
4461 #ifndef NDEBUG
4462  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4463 #endif
4464 
4465  SCIPfreeBufferArray(scip, &S);
4466 
4467  return SCIP_OKAY;
4468 }
4469 
4470 
4471 
4472 /** separate cuts based on perspective formulation
4473  *
4474  * Hijazi, Bonami, and Ouorou (2014) introduced the following cuts: We consider an indicator constraint
4475  * \f[
4476  * y = 1 \rightarrow \alpha^T x \leq \beta
4477  * \f]
4478  * and assume finite bounds \f$\ell \leq x \leq u\f$. Then for \f$I \subseteq \{1, \dots, n\}\f$ define
4479  * \f[
4480  * \Sigma(I,x,y) = \sum_{i \notin I} \alpha_i x_i +
4481  * y \Big(\sum_{i \in I, \alpha_i < 0} \alpha_i u_i + \sum_{i \in I, \alpha_i > 0} \alpha_i \ell_i +
4482  * \sum_{i \notin I, \alpha_i < 0} \alpha_i \ell_i + \sum_{i \notin I, \alpha_i > 0} \alpha_i u_i - \beta\Big).
4483  * \f]
4484  * Then the cuts
4485  * \f[
4486  * \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
4487  * \f]
4488  * are valid for the disjunction
4489  * \f[
4490  * \{y = 0,\; \ell \leq x \leq u\} \cup \{y = 1,\; \ell \leq x \leq u,\; \alpha^T x \leq \beta\}.
4491  * \f]
4492  * 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
4493  * \f[
4494  * y^*(\alpha_i\, u_i\, [\alpha_i < 0] + \alpha_i\, \ell_i\, [\alpha_i > 0]) >
4495  * \alpha_i x_i^* + y^* )\alpha_i \ell_i [\alpha_i < 0] + \alpha_i u_i [\alpha_i > 0]),
4496  * \f]
4497  * where \f$[C] = 1\f$ if condition \f$C\f$ is satisfied, otherwise it is 0.
4498  * If the above inequality holds, \f$i\f$ is included in \f$I\f$, otherwise not.
4499  */
4500 static
4502  SCIP* scip, /**< SCIP pointer */
4503  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4504  SCIP_SOL* sol, /**< solution to be separated */
4505  int nconss, /**< number of constraints */
4506  SCIP_CONS** conss, /**< indicator constraints */
4507  int maxsepacuts, /**< maximal number of cuts to be generated */
4508  int* nGen /**< number of generated cuts */
4509  )
4510 { /*lint --e{850}*/
4511  SCIP_CONSHDLRDATA* conshdlrdata;
4512  SCIP_VAR** cutvars;
4513  SCIP_Real* cutvals;
4514  int nvars;
4515  int c;
4516 
4517  assert( scip != NULL );
4518  assert( conshdlr != NULL );
4519  assert( conss != NULL );
4520  assert( nGen != NULL );
4521 
4522  if ( *nGen >= maxsepacuts )
4523  return SCIP_OKAY;
4524 
4525  nvars = SCIPgetNVars(scip);
4526  SCIP_CALL( SCIPallocBufferArray(scip, &cutvars, nvars+1) );
4527  SCIP_CALL( SCIPallocBufferArray(scip, &cutvals, nvars+1) );
4528 
4529  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4530  assert( conshdlrdata != NULL );
4531 
4532  /* loop through constraints */
4533  for (c = 0; c < nconss; ++c)
4534  {
4535  SCIP_CONSDATA* consdata;
4536  SCIP_CONS* lincons;
4537  SCIP_VAR* slackvar;
4538  SCIP_VAR* binvar;
4539  SCIP_Real binval;
4540 
4541  assert( conss[c] != NULL );
4542  consdata = SCIPconsGetData(conss[c]);
4543  assert( consdata != NULL );
4544  slackvar = consdata->slackvar;
4545 
4546  lincons = consdata->lincons;
4547  assert( lincons != NULL );
4548 
4549  binvar = consdata->binvar;
4550  assert( binvar != NULL );
4551  binval = SCIPgetSolVal(scip, sol, binvar);
4552 
4553  if ( SCIPconsIsActive(lincons) )
4554  {
4555  SCIP_VAR** linvars;
4556  SCIP_Real* linvals;
4557  SCIP_Real linrhs;
4558  SCIP_Bool finitebound = TRUE;
4559  SCIP_Real cutrhs = 0.0;
4560  SCIP_Real cutval;
4561  SCIP_Real signfactor = 1.0;
4562  SCIP_Real ypart;
4563  SCIP_Bool islocal = FALSE;
4564  int nlinvars;
4565  int cnt = 0;
4566  int j;
4567 
4568  linvars = SCIPgetVarsLinear(scip, lincons);
4569  linvals = SCIPgetValsLinear(scip, lincons);
4570  nlinvars = SCIPgetNVarsLinear(scip, lincons);
4571 
4572  linrhs = SCIPgetRhsLinear(scip, lincons);
4573  if ( SCIPisInfinity(scip, linrhs) )
4574  {
4575  if ( ! SCIPisInfinity(scip, SCIPgetLhsLinear(scip, lincons)) )
4576  {
4577  linrhs = -SCIPgetLhsLinear(scip, lincons);
4578  signfactor = -1.0;
4579  }
4580  else
4581  continue;
4582  }
4583  ypart = -linrhs;
4584  cutval = binval * ypart;
4585 
4586  for (j = 0; j < nlinvars; ++j)
4587  {
4588  SCIP_Real linval;
4589  SCIP_Real lb;
4590  SCIP_Real ub;
4591  SCIP_Real din = 0.0;
4592  SCIP_Real dout = 0.0;
4593  SCIP_Real xpart;
4594  SCIP_Real xval;
4595 
4596  if ( linvars[j] == slackvar )
4597  continue;
4598 
4599  if ( conshdlrdata->sepapersplocal )
4600  {
4601  lb = SCIPvarGetLbLocal(linvars[j]);
4602  ub = SCIPvarGetUbLocal(linvars[j]);
4603 
4604  if ( lb > SCIPvarGetLbGlobal(linvars[j]) )
4605  islocal = TRUE;
4606  if ( ub < SCIPvarGetUbGlobal(linvars[j]) )
4607  islocal = TRUE;
4608  }
4609  else
4610  {
4611  lb = SCIPvarGetLbGlobal(linvars[j]);
4612  ub = SCIPvarGetUbGlobal(linvars[j]);
4613  }
4614 
4615  /* skip cases with unbounded variables */
4616  if ( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
4617  {
4618  finitebound = FALSE;
4619  break;
4620  }
4621 
4622  /* compute rest parts for i in the set (din) or not in the set (dout) */
4623  linval = signfactor * linvals[j];
4624  if ( SCIPisNegative(scip, linval) )
4625  {
4626  din += linval * ub;
4627  dout += linval * lb;
4628  }
4629  else if ( SCIPisPositive(scip, linval) )
4630  {
4631  din += linval * lb;
4632  dout += linval * ub;
4633  }
4634 
4635  xval = SCIPgetSolVal(scip, sol, linvars[j]);
4636  xpart = linval * xval;
4637 
4638  /* if din > dout, we want to include i in the set */
4639  if ( SCIPisGT(scip, binval * din, binval * dout + xpart) )
4640  {
4641  ypart += din;
4642  cutval += binval * din;
4643  }
4644  else
4645  {
4646  /* otherwise i is not in the set */
4647  ypart += dout;
4648 
4649  cutrhs += dout;
4650  cutval += binval * dout + xpart;
4651 
4652  cutvars[cnt] = linvars[j];
4653  cutvals[cnt++] = linval;
4654  }
4655  }
4656 
4657  if ( ! finitebound )
4658  continue;
4659 
4660  if ( SCIPisEfficacious(scip, cutval - cutrhs) )
4661  {
4662  SCIP_ROW* row;
4663  SCIP_Bool infeasible;
4664  char name[50];
4665 
4666  /* add y-variable */
4667  cutvars[cnt] = binvar;
4668  cutvals[cnt] = ypart;
4669  ++cnt;
4670 
4671  SCIPdebugMsg(scip, "Found cut of lhs value %f > %f.\n", cutval, cutrhs);
4672  (void) SCIPsnprintf(name, 50, "persp%d", conshdlrdata->nperspcutsgen + *nGen);
4673  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), cutrhs, islocal, FALSE, conshdlrdata->removable) );
4674  SCIP_CALL( SCIPaddVarsToRow(scip, row, cnt, cutvars, cutvals) );
4675 #ifdef SCIP_OUTPUT
4676  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
4677 #endif
4678  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
4679  assert( ! infeasible );
4680  SCIP_CALL( SCIPreleaseRow(scip, &row));
4681  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
4682  ++(*nGen);
4683  }
4684  }
4685  if ( *nGen >= maxsepacuts )
4686  break;
4687  }
4688 
4689  SCIPfreeBufferArray(scip, &cutvals);
4690  SCIPfreeBufferArray(scip, &cutvars);
4691 
4692  return SCIP_OKAY;
4693 }
4694 
4695 
4696 /** separation method
4697  *
4698  * We first check whether coupling inequalities can be separated (if required). If not enough of
4699  * these could be generated, we check whether IIS inequalities can be separated.
4700  */
4701 static
4703  SCIP* scip, /**< SCIP pointer */
4704  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4705  int nconss, /**< number of constraints */
4706  int nusefulconss, /**< number of useful constraints */
4707  SCIP_CONS** conss, /**< indicator constraints */
4708  SCIP_SOL* sol, /**< solution to be separated */
4709  SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4710  SCIP_RESULT* result /**< result */
4711  )
4712 {
4713  SCIP_CONSHDLRDATA* conshdlrdata;
4714  int maxsepacuts;
4715  int ncuts;
4716 
4717  assert( scip != NULL );
4718  assert( conshdlr != NULL );
4719  assert( conss != NULL );
4720  assert( result != NULL );
4721 
4722  *result = SCIP_DIDNOTRUN;
4723 
4724  if ( nconss == 0 )
4725  return SCIP_OKAY;
4726 
4727  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4728  assert( conshdlrdata != NULL );
4729  ncuts = 0;
4730 
4731  /* get the maximal number of cuts allowed in a separation round */
4732  if ( SCIPgetDepth(scip) == 0 )
4733  maxsepacuts = conshdlrdata->maxsepacutsroot;
4734  else
4735  maxsepacuts = conshdlrdata->maxsepacuts;
4736 
4737  /* first separate coupling inequalities (if required) */
4738  if ( conshdlrdata->sepacouplingcuts )
4739  {
4740  int c;
4741 
4742  *result = SCIP_DIDNOTFIND;
4743 
4744  /* check each constraint */
4745  for (c = 0; c < nusefulconss && ncuts < maxsepacuts; ++c)
4746  {
4747  SCIP_CONSDATA* consdata;
4748  SCIP_Bool islocal;
4749  SCIP_Real ub;
4750 
4751  assert( conss != NULL );
4752  assert( conss[c] != NULL );
4753  consdata = SCIPconsGetData(conss[c]);
4754  assert( consdata != NULL );
4755  assert( consdata->slackvar != NULL );
4756  assert( consdata->binvar != NULL );
4757 
4758  /* get upper bound for slack variable in linear constraint */
4759  islocal = FALSE;
4760  if ( conshdlrdata->sepacouplinglocal )
4761  {
4762  ub = SCIPvarGetUbLocal(consdata->slackvar);
4763  if ( ub < SCIPvarGetUbGlobal(consdata->slackvar) )
4764  islocal = TRUE;
4765  }
4766  else
4767  ub = SCIPvarGetUbGlobal(consdata->slackvar);
4768  assert( ! SCIPisFeasNegative(scip, ub) );
4769 
4770  /* only use coefficients that are not too large */
4771  if ( ub <= conshdlrdata->sepacouplingvalue )
4772  {
4773  SCIP_Real activity;
4774 
4775  activity = SCIPgetSolVal(scip, sol, consdata->slackvar) + ub * SCIPgetSolVal(scip, sol, consdata->binvar) - ub;
4776  if ( SCIPisEfficacious(scip, activity) )
4777  {
4778  SCIP_ROW* row;
4779  SCIP_Bool infeasible;
4780 #ifndef NDEBUG
4781  char name[50];
4782 
4783  (void) SCIPsnprintf(name, 50, "couple%d", c);
4784  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
4785 #else
4786  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], "", -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
4787 #endif
4788  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4789 
4790  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
4791  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
4792  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4793 
4794  SCIPdebugMsg(scip, "Separated coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
4795 #ifdef SCIP_OUTPUT
4796  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
4797 #endif
4798  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
4799  assert( ! infeasible );
4800  SCIP_CALL( SCIPreleaseRow(scip, &row));
4801 
4802  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
4803  *result = SCIP_SEPARATED;
4804 
4805  ++ncuts;
4806  }
4807  }
4808  }
4809  SCIPdebugMsg(scip, "Number of separated coupling inequalities: %d.\n", ncuts);
4810  }
4811 
4812  /* separate cuts from the alternative lp (if required) */
4813  if ( conshdlrdata->sepaalternativelp && ncuts < SEPAALTTHRESHOLD )
4814  {
4815  SCIP_Bool cutoff;
4816  int noldcuts;
4817 
4818  SCIPdebugMsg(scip, "Separating inequalities for indicator constraints.\n");
4819 
4820  noldcuts = ncuts;
4821  if ( *result == SCIP_DIDNOTRUN )
4822  *result = SCIP_DIDNOTFIND;
4823 
4824  /* start separation */
4825  SCIP_CALL( separateIISRounding(scip, conshdlr, sol, enfosepatype, nconss, conss, maxsepacuts, &cutoff, &ncuts) );
4826  SCIPdebugMsg(scip, "Separated %d cuts from indicator constraints.\n", ncuts - noldcuts);
4827 
4828  if ( cutoff )
4829  *result = SCIP_CUTOFF;
4830  else if ( ncuts > noldcuts )
4831  {
4832  conshdlrdata->niiscutsgen += ncuts;
4833 
4834  /* possibly overwrite result from separation above */
4835  if ( conshdlrdata->genlogicor )
4836  *result = SCIP_CONSADDED;
4837  else
4838  *result = SCIP_SEPARATED;
4839  }
4840  }
4841 
4842  /* separate cuts based on perspective formulation */
4843  if ( conshdlrdata->sepaperspective && ncuts < SEPAALTTHRESHOLD )
4844  {
4845  int noldcuts;
4846 
4847  SCIPdebugMsg(scip, "Separating inequalities based on perspective formulation.\n");
4848 
4849  noldcuts = ncuts;
4850  if ( *result == SCIP_DIDNOTRUN )
4851  *result = SCIP_DIDNOTFIND;
4852 
4853  /* start separation */
4854  SCIP_CALL( separatePerspective(scip, conshdlr, sol, nconss, conss, maxsepacuts, &ncuts) );
4855  SCIPdebugMsg(scip, "Separated %d cuts from perspective formulation.\n", ncuts - noldcuts);
4856 
4857  if ( ncuts > noldcuts )
4858  {
4859  conshdlrdata->nperspcutsgen += ncuts;
4860 
4861  /* possibly overwrite result from separation above */
4862  *result = SCIP_SEPARATED;
4863  }
4864  }
4865 
4866  return SCIP_OKAY;
4867 }
4868 
4869 
4870 /** initializes the constraint handler data */
4871 static
4872 void initConshdlrData(
4873  SCIP* scip, /**< SCIP pointer */
4874  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
4875  )
4876 {
4877  assert( conshdlrdata != NULL );
4878 
4879  conshdlrdata->removable = TRUE;
4880  conshdlrdata->scaled = FALSE;
4881  conshdlrdata->altlp = NULL;
4882  conshdlrdata->nrows = 0;
4883  conshdlrdata->varhash = NULL;
4884  conshdlrdata->slackhash = NULL;
4885  conshdlrdata->lbhash = NULL;
4886  conshdlrdata->ubhash = NULL;
4887  conshdlrdata->nlbbounds = 0;
4888  conshdlrdata->nubbounds = 0;
4889  conshdlrdata->nslackvars = 0;
4890  conshdlrdata->objcutindex = -1;
4891  conshdlrdata->objupperbound = SCIPinfinity(scip);
4892  conshdlrdata->objaltlpbound = SCIPinfinity(scip);
4893  conshdlrdata->roundingminthres = 0.1;
4894  conshdlrdata->roundingmaxthres = 0.6;
4895  conshdlrdata->maxroundingrounds = MAXROUNDINGROUNDS;
4896  conshdlrdata->roundingoffset = 0.1;
4897  conshdlrdata->addedcouplingcons = FALSE;
4898  conshdlrdata->ninitconss = 0;
4899  conshdlrdata->nbinvarszero = 0;
4900  conshdlrdata->performedrestart = FALSE;
4901  conshdlrdata->objindicatoronly = FALSE;
4902  conshdlrdata->objothervarsonly = FALSE;
4903  conshdlrdata->minabsobj = 0.0;
4904  conshdlrdata->normtype = 'e';
4905  conshdlrdata->niiscutsgen = 0;
4906  conshdlrdata->nperspcutsgen = 0;
4907 }
4908 
4909 
4910 /* ---------------------------- upgrading methods -----------------------------------*/
4911 
4912 /** tries to upgrade a linear constraint into an indicator constraint
4913  *
4914  * 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
4915  * it to an indicator constraint if for the residual value \f$a^T x \geq \gamma\f$, we have \f$\alpha + \gamma \geq
4916  * \beta\f$: in this case, the constraint is always satisfied if \f$y = 1\f$.
4917  *
4918  * 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
4919  * upgrade it to an indicator constraint if for the residual value \f$a^T x \leq \gamma\f$, we have \f$\alpha + \gamma
4920  * \leq \beta\f$.
4921  */
4922 static
4923 SCIP_DECL_LINCONSUPGD(linconsUpgdIndicator)
4924 { /*lint --e{715}*/
4925  SCIP_CONSHDLRDATA* conshdlrdata;
4926  SCIP_CONSHDLR* conshdlr;
4927  SCIP_Real minactivity = 0.0;
4928  SCIP_Real maxactivity = 0.0;
4929  SCIP_Real maxabsval = -1.0;
4930  SCIP_Real secabsval = -1.0;
4931  int maxabsvalidx = -1;
4932  int j;
4933 
4934  assert( scip != NULL );
4935  assert( upgdcons != NULL );
4936  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0 );
4937  assert( ! SCIPconsIsModifiable(cons) );
4938 
4939  /* do not upgrade if there are at most 2 variables (2 variables should be upgraded to a varbound constraint) */
4940  if ( nvars <= 2 )
4941  return SCIP_OKAY;
4942 
4943  /* cannot currently ranged constraints, since we can only return one constraint (and we would need one for each side each) */
4944  if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
4945  return SCIP_OKAY;
4946 
4947  /* check whether upgrading is turned on */
4948  conshdlr = SCIPfindConshdlr(scip, "indicator");
4949  assert( conshdlr != NULL );
4950  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4951  assert( conshdlrdata != NULL );
4952 
4953  if ( ! conshdlrdata->upgradelinear )
4954  return SCIP_OKAY;
4955 
4956  /* calculate activities */
4957  for (j = 0; j < nvars; ++j)
4958  {
4959  SCIP_VAR* var;
4960  SCIP_Real val;
4961  SCIP_Real lb;
4962  SCIP_Real ub;
4963 
4964  val = vals[j];
4965  assert( ! SCIPisZero(scip, val) );
4966 
4967  var = vars[j];
4968  assert( var != NULL );
4969 
4970  /* store maximal (and second to largest) value of coefficients */
4971  if ( SCIPisGE(scip, REALABS(val), maxabsval) )
4972  {
4973  secabsval = maxabsval;
4974  maxabsval = REALABS(val);
4975  maxabsvalidx = j;
4976  }
4977 
4978  if ( ! SCIPvarIsBinary(var) )
4979  {
4980  if ( val > 0.0 )
4981  {
4982  lb = SCIPvarGetLbGlobal(var);
4983  ub = SCIPvarGetUbGlobal(var);
4984  }
4985  else
4986  {
4987  ub = SCIPvarGetLbGlobal(var);
4988  lb = SCIPvarGetUbGlobal(var);
4989  }
4990 
4991  /* compute minimal activity */
4992  if ( SCIPisInfinity(scip, -lb) )
4993  minactivity = -SCIPinfinity(scip);
4994  else
4995  {
4996  if ( ! SCIPisInfinity(scip, -minactivity) )
4997  minactivity += val * lb;
4998  }
4999 
5000  /* compute maximal activity */
5001  if ( SCIPisInfinity(scip, ub) )
5002  maxactivity = SCIPinfinity(scip);
5003  else
5004  {
5005  if ( ! SCIPisInfinity(scip, maxactivity) )
5006  maxactivity += val * ub;
5007  }
5008  }
5009  }
5010  assert( maxabsval >= 0.0 );
5011  assert( 0 <= maxabsvalidx && maxabsvalidx < nvars );
5012 
5013  /* exit if largest coefficient does not belong to binary variable */
5014  if ( ! SCIPvarIsBinary(vars[maxabsvalidx]) )
5015  return SCIP_OKAY;
5016 
5017  /* exit if the second largest coefficient is as large as largest */
5018  if ( SCIPisEQ(scip, secabsval, maxabsval) )
5019  return SCIP_OKAY;
5020 
5021  /* cannot upgrade if all activities are infinity */
5022  if ( SCIPisInfinity(scip, -minactivity) && SCIPisInfinity(scip, maxactivity) )
5023  return SCIP_OKAY;
5024 
5025  /* check each variable as indicator variable */
5026  for (j = 0; j < nvars; ++j)
5027  {
5028  SCIP_VAR** indconsvars;
5029  SCIP_Real* indconsvals;
5030  SCIP_Bool upgdlhs = FALSE;
5031  SCIP_Bool upgdrhs = FALSE;
5032  SCIP_Bool indneglhs = FALSE;
5033  SCIP_Bool indnegrhs = FALSE;
5034  SCIP_VAR* indvar;
5035  SCIP_Real indval;
5036  int l;
5037 
5038  indvar = vars[j];
5039  indval = vals[j];
5040  assert( ! SCIPisZero(scip, indval) );
5041 
5042  if ( ! SCIPvarIsBinary(indvar) )
5043  continue;
5044 
5045  /* check for upgrading of lhs */
5046  if ( ! SCIPisInfinity(scip, -minactivity) && ! SCIPisInfinity(scip, -lhs) )
5047  {
5048  /* upgrading is possible with binary variable */
5049  if ( SCIPisGE(scip, minactivity, lhs) )
5050  upgdlhs = TRUE;
5051 
5052  /* upgrading is possible with negated binary variable */
5053  if ( SCIPisGE(scip, minactivity + indval, lhs) )
5054  {
5055  upgdlhs = TRUE;
5056  indneglhs = TRUE;
5057  }
5058  }
5059 
5060  /* check for upgrading of rhs */
5061  if ( ! SCIPisInfinity(scip, maxactivity) && ! SCIPisInfinity(scip, rhs) )
5062  {
5063  /* upgrading is possible with binary variable */
5064  if ( SCIPisLE(scip, maxactivity, rhs) )
5065  upgdrhs = TRUE;
5066 
5067  /* upgrading is possible with negated binary variable */
5068  if ( SCIPisLE(scip, maxactivity + indval, rhs) )
5069  {
5070  upgdrhs = TRUE;
5071  indnegrhs = TRUE;
5072  }
5073  }
5074 
5075  /* upgrade constraint */
5076  if ( upgdlhs || upgdrhs )
5077  {
5078  SCIP_VAR* indvar2;
5079  SCIP_Real bnd;
5080  int cnt = 0;
5081 
5082  assert( ! upgdlhs || ! upgdrhs ); /* cannot treat ranged rows */
5083  SCIPdebugMsg(scip, "upgrading constraint <%s> to an indicator constraint.\n", SCIPconsGetName(cons));
5084 
5085  SCIP_CALL( SCIPallocBufferArray(scip, &indconsvars, nvars - 1) );
5086  SCIP_CALL( SCIPallocBufferArray(scip, &indconsvals, nvars - 1) );
5087 
5088  /* create constraint */
5089  for (l = 0; l < nvars; ++l)
5090  {
5091  if ( vars[l] == indvar )
5092  continue;
5093  indconsvars[cnt] = vars[l];
5094  if ( upgdlhs )
5095  indconsvals[cnt] = -vals[l];
5096  else
5097  indconsvals[cnt] = vals[l];
5098  ++cnt;
5099  }
5100 
5101  if ( indneglhs || indnegrhs )
5102  {
5103  SCIP_CALL( SCIPgetNegatedVar(scip, indvar, &indvar2) );
5104  }
5105  else
5106  indvar2 = indvar;
5107 
5108  if ( upgdlhs )
5109  {
5110  bnd = -lhs;
5111  if ( ! indneglhs )
5112  bnd -= indval;
5113  SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
5116  }
5117  else
5118  {
5119  bnd = rhs;
5120  if ( ! indnegrhs )
5121  bnd -= indval;
5122  SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
5125  }
5126 
5127 #ifdef SCIP_DEBUG
5128  SCIPinfoMessage(scip, NULL, "upgrade: \n");
5129  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
5130  SCIPinfoMessage(scip, NULL, "\n");
5131  SCIP_CALL( SCIPprintCons(scip, *upgdcons, NULL) );
5132  SCIPinfoMessage(scip, NULL, "\n");
5134  SCIPinfoMessage(scip, NULL, " (minact: %f, maxact: %f)\n", minactivity, maxactivity);
5135 #endif
5136 
5137  SCIPfreeBufferArray(scip, &indconsvars);
5138  SCIPfreeBufferArray(scip, &indconsvals);
5139 
5140  return SCIP_OKAY;
5141  }
5142  }
5143 
5144  return SCIP_OKAY;
5145 }
5146 
5147 
5148 /* ---------------------------- constraint handler callback methods ----------------------*/
5149 
5150 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
5151 static
5152 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyIndicator)
5153 { /*lint --e{715}*/
5154  assert( scip != NULL );
5155  assert( conshdlr != NULL );
5156  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5157  assert( valid != NULL );
5158 
5159  /* call inclusion method of constraint handler */
5161 
5162  *valid = TRUE;
5163 
5164  return SCIP_OKAY;
5165 }
5166 
5167 
5168 /** initialization method of constraint handler (called after problem was transformed) */
5169 static
5170 SCIP_DECL_CONSINIT(consInitIndicator)
5171 { /*lint --e{715}*/
5172  SCIP_CONSHDLRDATA* conshdlrdata;
5173 
5174  assert( scip != NULL );
5175  assert( conshdlr != NULL );
5176  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5177 
5178  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5179  assert( conshdlrdata != NULL );
5180 
5181  initConshdlrData(scip, conshdlrdata);
5182 
5183  /* find trysol heuristic */
5184  if ( conshdlrdata->trysolutions && conshdlrdata->heurtrysol == NULL )
5185  {
5186  conshdlrdata->heurtrysol = SCIPfindHeur(scip, "trysol");
5187  }
5188 
5189  return SCIP_OKAY;
5190 }
5191 
5192 
5193 /** deinitialization method of constraint handler (called before transformed problem is freed) */
5194 static
5195 SCIP_DECL_CONSEXIT(consExitIndicator)
5196 { /*lint --e{715}*/
5197  SCIP_CONSHDLRDATA* conshdlrdata;
5198 
5199  assert( scip != NULL );
5200  assert( conshdlr != NULL );
5201  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5202 
5203  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5204 
5205  if ( conshdlrdata->binvarhash != NULL )
5206  SCIPhashmapFree(&conshdlrdata->binvarhash);
5207 
5208  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
5209  conshdlrdata->maxaddlincons = 0;
5210  conshdlrdata->naddlincons = 0;
5211  conshdlrdata->nrows = 0;
5212 
5213  return SCIP_OKAY;
5214 }
5215 
5216 
5217 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
5218 static
5219 SCIP_DECL_CONSFREE(consFreeIndicator)
5221  SCIP_CONSHDLRDATA* conshdlrdata;
5222 
5223  assert( scip != NULL );
5224  assert( conshdlr != NULL );
5225  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5226 
5227  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5228  assert( conshdlrdata != NULL );
5229  assert( conshdlrdata->altlp == NULL );
5230  assert( conshdlrdata->varhash == NULL );
5231  assert( conshdlrdata->lbhash == NULL );
5232  assert( conshdlrdata->ubhash == NULL );
5233  assert( conshdlrdata->slackhash == NULL );
5234 
5235  if ( conshdlrdata->maxaddlincons > 0 )
5236  {
5237  /* if problem was not yet transformed the array may need to be freed, because we did not call the EXIT callback */
5238  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
5239  }
5240  assert( conshdlrdata->addlincons == NULL );
5241  conshdlrdata->naddlincons = 0;
5242  conshdlrdata->maxaddlincons = 0;
5243 
5244  SCIPfreeBlockMemory(scip, &conshdlrdata);
5245 
5246  return SCIP_OKAY;
5247 }
5248 
5249 
5250 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
5251 static
5252 SCIP_DECL_CONSINITSOL(consInitsolIndicator)
5254  SCIP_CONSHDLRDATA* conshdlrdata;
5255  int c;
5256 
5257  assert( scip != NULL );
5258  assert( conshdlr != NULL );
5259  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5260 
5263  return SCIP_OKAY;
5264 
5265  SCIPdebugMsg(scip, "Initsol for indicator constraints.\n");
5266 
5267  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5268  assert( conshdlrdata != NULL );
5269  assert( conshdlrdata->slackhash == NULL );
5270 
5271  SCIP_CALL( SCIPgetCharParam(scip, "separating/efficacynorm", &conshdlrdata->normtype) );
5272 
5273  if ( conshdlrdata->sepaalternativelp )
5274  {
5275  /* generate hash for storing all slack variables (size is just a guess) */
5276  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->slackhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
5277  assert( conshdlrdata->slackhash != NULL );
5278 
5279  /* first initialize slack hash */
5280  for (c = 0; c < nconss; ++c)
5281  {
5282  SCIP_CONSDATA* consdata;
5283 
5284  assert( conss != NULL );
5285  assert( conss[c] != NULL );
5286  assert( SCIPconsIsTransformed(conss[c]) );
5287 
5288  consdata = SCIPconsGetData(conss[c]);
5289  assert( consdata != NULL );
5290 
5291  assert( consdata->slackvar != NULL );
5292 
5293  /* insert slack variable into hash */
5294  SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->slackhash, consdata->slackvar, INT_MAX) );
5295  assert( SCIPhashmapExists(conshdlrdata->slackhash, consdata->slackvar) );
5296  ++conshdlrdata->nslackvars;
5297  }
5298 
5299  if ( conshdlrdata->genlogicor )
5300  {
5301  SCIP_CONSHDLR* logicorconshdlr;
5302  int logicorsepafreq;
5303  int sepafreq;
5304 
5305  /* If we generate logicor constraints, but the separation frequency is not 1, output warning */
5306  logicorconshdlr = SCIPfindConshdlr(scip, "logicor");
5307  if ( logicorconshdlr == NULL )
5308  {
5309  SCIPerrorMessage("Logicor constraint handler not included, cannot generate constraints.\n");
5310  return SCIP_ERROR;
5311  }
5312  logicorsepafreq = SCIPconshdlrGetSepaFreq(logicorconshdlr);
5313  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
5314  if ( (sepafreq != -1 || conshdlrdata->enforcecuts) && logicorsepafreq != 1 )
5315  {
5316  SCIPwarningMessage(scip, "For better performance set parameter 'constraints/logicor/sepafreq' to 1 if 'constraints/included/genlogicor' is true.\n");
5317  }
5318  }
5319  }
5320 
5321  /* check each constraint */
5322  conshdlrdata->objothervarsonly = TRUE;
5323  for (c = 0; c < nconss; ++c)
5324  {
5325  SCIP_CONSDATA* consdata;
5326 
5327  assert( conss != NULL );
5328  assert( conss[c] != NULL );
5329  assert( SCIPconsIsTransformed(conss[c]) );
5330 
5331  consdata = SCIPconsGetData(conss[c]);
5332  assert( consdata != NULL );
5333  assert( consdata->binvar != NULL );
5334  assert( consdata->slackvar != NULL );
5335 
5336  /* Presolving might replace a slack variable by an active variable. Thus, the objective of a slack variables might
5337  * be nonzero. However, we do not need to check slack variables here. */
5338  if ( ! SCIPisZero(scip, varGetObjDelta(consdata->binvar)) )
5339  conshdlrdata->objothervarsonly = FALSE;
5340 
5341  /* deactivate */
5342  if ( ! consdata->linconsactive )
5343  {
5344  SCIP_CALL( SCIPdisableCons(scip, consdata->lincons) );
5345  }
5346  else
5347  {
5348  /* add constraint to alternative LP if not already done */
5349  if ( conshdlrdata->sepaalternativelp && consdata->colindex < 0 )
5350  {
5351  SCIP_CALL( addAltLPConstraint(scip, conshdlr, consdata->lincons, consdata->slackvar, 1.0, &consdata->colindex) );
5352  SCIPdebugMsg(scip, "Added column for <%s> to alternative LP with column index %d.\n", SCIPconsGetName(conss[c]),consdata->colindex);
5353 #ifdef SCIP_OUTPUT
5354  SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
5355  SCIPinfoMessage(scip, NULL, ";\n");
5356 #endif
5357  }
5358  }
5359 
5360  /* add nlrow representation to NLP, if NLP had been constructed
5361  *
5362  * Note, that we did not tell SCIP in exitpre that we have something to add to the NLP, thus
5363  * indicators are only available in the NLP for MINLPs, but not for MIPs with indicators.
5364  */
5365  if ( SCIPisNLPConstructed(scip) && SCIPconsIsChecked(conss[c]) )
5366  {
5367  /* create nonlinear row binary variable * slack variable = 0 */
5368  SCIP_NLROW* nlrow;
5369  SCIP_EXPR* quadexpr;
5370  SCIP_EXPR* varexprs[2];
5371 
5372  SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[0], consdata->binvar, NULL, NULL) );
5373  SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[1], consdata->slackvar, NULL, NULL) );
5374  SCIP_CALL( SCIPcreateExprProduct(scip, &quadexpr, 2, varexprs, 1.0, NULL, NULL) );
5375 
5376  SCIP_CALL( SCIPcreateNlRow(scip, &nlrow, SCIPconsGetName(conss[c]), 0.0, 0, NULL, NULL, quadexpr, 0.0, 0.0, SCIP_EXPRCURV_UNKNOWN) );
5377 
5378  SCIP_CALL( SCIPreleaseExpr(scip, &quadexpr) );
5379  SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[1]) );
5380  SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[0]) );
5381 
5382  /* add row to NLP and forget about it */
5383  SCIP_CALL( SCIPaddNlRow(scip, nlrow) );
5384  SCIP_CALL( SCIPreleaseNlRow(scip, &nlrow) );
5385  }
5386  }
5387 
5388  SCIPdebugMsg(scip, "Initialized %d indicator constraints.\n", nconss);
5389 
5390  /* check additional constraints */
5391  if ( conshdlrdata->sepaalternativelp )
5392  {
5393  SCIP_CONS* cons;
5394  int colindex;
5395  int cnt = 0;
5396 
5397  /* add stored linear constraints if they exist */
5398  if ( conshdlrdata->naddlincons > 0 )
5399  {
5400  for (c = 0; c < conshdlrdata->naddlincons; ++c)
5401  {
5402  cons = conshdlrdata->addlincons[c];
5403 
5404  /* get transformed constraint - since it is needed only here, we do not store the information */
5405  if ( ! SCIPconsIsTransformed(cons) )
5406  {
5407  SCIP_CALL( SCIPgetTransformedCons(scip, conshdlrdata->addlincons[c], &cons) );
5408 
5409  /* @todo check when exactly the transformed constraint does not exist - SCIPisActive() does not suffice */
5410  if ( cons == NULL )
5411  continue;
5412  }
5413  SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
5414  ++cnt;
5415 
5416 #ifdef SCIP_OUTPUT
5417  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
5418  SCIPinfoMessage(scip, NULL, ";\n");
5419 #endif
5420  }
5421  SCIPdebugMsg(scip, "Added %d additional columns to alternative LP.\n", cnt);
5422  }
5423  else
5424  {
5425  /* if no stored linear constraints are available, possibly collect other linear constraints; we only use linear
5426  * constraints, since most other constraints involve integral variables, and in this context we will likely
5427  * benefit much more from continuous variables. */
5428  if ( conshdlrdata->useotherconss )
5429  {
5430  const char* conshdlrname;
5431  SCIP_CONS** allconss;
5432  int nallconss;
5433 
5434  nallconss = SCIPgetNConss(scip);
5435  allconss = SCIPgetConss(scip);
5436 
5437  /* loop through all constraints */
5438  for (c = 0; c < nallconss; ++c)
5439  {
5440  /* get constraint */
5441  cons = allconss[c];
5442  assert( cons != NULL );
5443  assert( SCIPconsIsTransformed(cons) );
5444 
5445  /* get constraint handler name */
5446  conshdlrname = SCIPconshdlrGetName(SCIPconsGetHdlr(cons));
5447 
5448  /* check type of constraint (only take modifiable linear constraints) */
5449  if ( strcmp(conshdlrname, "linear") == 0 && ! SCIPconsIsModifiable(cons) )
5450  {
5451  /* avoid adding linear constraints that correspond to indicator constraints */
5452  if ( strncmp(SCIPconsGetName(cons), "indlin", 6) != 0 )
5453  {
5454  SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
5455  SCIPdebugMsg(scip, "Added column for linear constraint <%s> to alternative LP with column index %d.\n", SCIPconsGetName(cons), colindex);
5456  ++cnt;
5457  }
5458  }
5459  }
5460  SCIPdebugMsg(scip, "Added %d additional columns from linear constraints to alternative LP.\n", cnt);
5461  }
5462  }
5463  }
5464 
5465  /* initialize event handler if restart should be forced */
5466  if ( conshdlrdata->forcerestart )
5467  {
5468  SCIP_Bool* covered;
5469  SCIP_VAR** vars;
5470  int nvars;
5471  int j;
5472 
5473  assert( conshdlrdata->eventhdlrrestart != NULL );
5474 
5475  /* store number of initial constraints */
5476  conshdlrdata->ninitconss = SCIPconshdlrGetNActiveConss(conshdlr);
5477 
5478  /* reset number of fixed binary variables */
5479  conshdlrdata->nbinvarszero = 0;
5480 
5481  /* loop through variables */
5482  nvars = SCIPgetNVars(scip);
5483  vars = SCIPgetVars(scip);
5484 
5485  conshdlrdata->objindicatoronly = FALSE;
5486  conshdlrdata->minabsobj = SCIP_REAL_MAX;
5487 
5488  /* unmark all variables */
5489  SCIP_CALL( SCIPallocBufferArray(scip, &covered, nvars) );
5490  for (j = 0; j < nvars; ++j)
5491  covered[j] = FALSE;
5492 
5493  /* mark indicator variables */
5494  for (c = 0; c < nconss; ++c)
5495  {
5496  SCIP_CONSDATA* consdata;
5497  int probindex;
5498 
5499  assert( conss != NULL );
5500  assert( conss[c] != NULL );
5501 
5502  /* avoid non-active indicator constraints */
5503  if ( ! SCIPconsIsActive(conss[c]) )
5504  continue;
5505 
5506  consdata = SCIPconsGetData(conss[c]);
5507  assert( consdata != NULL );
5508  assert( consdata->binvar != NULL );
5509 
5510  if ( SCIPvarIsNegated(consdata->binvar) )
5511  {
5512  assert( SCIPvarGetNegatedVar(consdata->binvar) != NULL );
5513  probindex = SCIPvarGetProbindex(SCIPvarGetNegatedVar(consdata->binvar));
5514  }
5515  else
5516  probindex = SCIPvarGetProbindex(consdata->binvar);
5517 
5518  /* if presolving detected infeasibility it might be that the binary variables are not active */
5519  if ( probindex < 0 )
5520  continue;
5521 
5522  assert( 0 <= probindex && probindex < nvars );
5523  covered[probindex] = TRUE;
5524  }
5525 
5526  /* check all variables */
5527  for (j = 0; j < nvars; ++j)
5528  {
5529  SCIP_Real obj;
5530 
5531  obj = SCIPvarGetObj(vars[j]);
5532  if ( ! SCIPisZero(scip, obj) )
5533  {
5534  if ( ! covered[j] )
5535  break;
5536  if ( ! SCIPisIntegral(scip, obj) )
5537  break;
5538  if ( REALABS(obj) < conshdlrdata->minabsobj )
5539  conshdlrdata->minabsobj = REALABS(obj);
5540  }
5541  }
5542 
5543  /* if all variables have integral objective and only indicator variables have nonzero objective */
5544  if ( j >= nvars )
5545  {
5546  /* if there are variables with nonzero objective */
5547  if ( conshdlrdata->minabsobj < SCIP_REAL_MAX )
5548  {
5549  assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
5550  assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0) );
5551 
5552  conshdlrdata->objindicatoronly = TRUE;
5553 
5554  assert( conshdlrdata->eventhdlrrestart != NULL );
5555  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
5556  }
5557  }
5558 
5559  SCIPfreeBufferArray(scip, &covered);
5560  }
5561 
5562  return SCIP_OKAY;
5563 }
5564 
5565 
5566 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
5567 static
5568 SCIP_DECL_CONSEXITSOL(consExitsolIndicator)
5569 { /*lint --e{715}*/
5570  SCIP_CONSHDLRDATA* conshdlrdata;
5571  int c;
5572 
5573  assert( scip != NULL );
5574  assert( conshdlr != NULL );
5575  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5576 
5577  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5578  assert( conshdlrdata != NULL );
5579 
5580  if ( conshdlrdata->sepaalternativelp )
5581  {
5582  if ( conshdlrdata->slackhash != NULL )
5583  {
5584 #ifdef SCIP_DEBUG
5585  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator slack hash:\n");
5586  SCIPhashmapPrintStatistics(conshdlrdata->slackhash, SCIPgetMessagehdlr(scip));
5587 #endif
5588  SCIPhashmapFree(&conshdlrdata->slackhash);
5589  }
5590 
5591  if ( conshdlrdata->altlp != NULL )
5592  {
5593  assert( conshdlrdata->varhash != NULL );
5594  assert( conshdlrdata->lbhash != NULL );
5595  assert( conshdlrdata->ubhash != NULL );
5596 
5597 #ifdef SCIP_DEBUG
5598  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator var hash:\n");
5599  SCIPhashmapPrintStatistics(conshdlrdata->varhash, SCIPgetMessagehdlr(scip));
5600  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator lower bound hash:\n");
5601  SCIPhashmapPrintStatistics(conshdlrdata->lbhash, SCIPgetMessagehdlr(scip));
5602  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator upper bound hash:\n");
5603  SCIPhashmapPrintStatistics(conshdlrdata->ubhash, SCIPgetMessagehdlr(scip));
5604 #endif
5605 
5606  SCIPhashmapFree(&conshdlrdata->varhash);
5607  SCIPhashmapFree(&conshdlrdata->lbhash);
5608  SCIPhashmapFree(&conshdlrdata->ubhash);
5609 
5610  SCIP_CALL( SCIPlpiFree(&conshdlrdata->altlp) );
5611 
5612  /* save the information that the columns have been deleted */
5613  for (c = 0; c < nconss; ++c)
5614  {
5615  SCIP_CONSDATA* consdata;
5616 
5617  assert( conss != NULL );
5618  assert( conss[c] != NULL );
5619 
5620  consdata = SCIPconsGetData(conss[c]);
5621  assert( consdata != NULL );
5622  consdata->colindex = -1;
5623  }
5624  }
5625  }
5626  else
5627  {
5628  assert( conshdlrdata->slackhash == NULL );
5629  assert( conshdlrdata->varhash == NULL );
5630  assert( conshdlrdata->lbhash == NULL );
5631  assert( conshdlrdata->ubhash == NULL );
5632  }
5633 
5634  return SCIP_OKAY;
5635 }
5636 
5637 
5638 /** frees specific constraint data */
5639 static
5640 SCIP_DECL_CONSDELETE(consDeleteIndicator)
5642  assert( scip != NULL );
5643  assert( conshdlr != NULL );
5644  assert( cons != NULL );
5645  assert( consdata != NULL );
5646  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5647 
5648 #ifdef SCIP_MORE_DEBUG
5649  SCIPdebugMsg(scip, "Deleting indicator constraint <%s>.\n", SCIPconsGetName(cons) );
5650 #endif
5651 
5652  /* drop events on transformed variables */
5653  if ( SCIPconsIsTransformed(cons) )
5654  {
5655  SCIP_CONSHDLRDATA* conshdlrdata;
5656 
5657  /* get constraint handler data */
5658  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5659  assert( conshdlrdata != NULL );
5660 
5661  if ( conshdlrdata->sepaalternativelp )
5662  {
5663  SCIP_CALL( deleteAltLPConstraint(scip, conshdlr, cons) );
5664  }
5665 
5666  assert( (*consdata)->slackvar != NULL );
5667  assert( (*consdata)->binvar != NULL );
5668 
5669  /* free events only in correct stages */
5671  {
5672  if ( (*consdata)->linconsactive )
5673  {
5674  assert( conshdlrdata->eventhdlrbound != NULL );
5675  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
5676  (SCIP_EVENTDATA*)*consdata, -1) );
5677  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
5678  (SCIP_EVENTDATA*)*consdata, -1) );
5679  }
5680  if ( conshdlrdata->forcerestart )
5681  {
5682  assert( conshdlrdata->eventhdlrrestart != NULL );
5683  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
5684  (SCIP_EVENTDATA*) conshdlrdata, -1) );
5685  }
5686  }
5687  }
5688 
5689  /* Can there be cases where lincons is NULL, e.g., if presolve found the problem infeasible? */
5690  assert( (*consdata)->lincons != NULL );
5691 
5692  /* release linear constraint and slack variable */
5693  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->slackvar) );
5694  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->lincons) );
5695 
5696  SCIPfreeBlockMemory(scip, consdata);
5697 
5698  return SCIP_OKAY;
5699 }
5700 
5701 
5702 /** transforms constraint data into data belonging to the transformed problem */
5703 static
5704 SCIP_DECL_CONSTRANS(consTransIndicator)
5706  SCIP_CONSDATA* consdata;
5707  SCIP_CONSHDLRDATA* conshdlrdata;
5708  SCIP_CONSDATA* sourcedata;
5709  char s[SCIP_MAXSTRLEN];
5710 
5711  assert( scip != NULL );
5712  assert( conshdlr != NULL );
5713  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5714  assert( sourcecons != NULL );
5715  assert( targetcons != NULL );
5716 
5717  /* get constraint handler data */
5718  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5719  assert( conshdlrdata != NULL );
5720  assert( conshdlrdata->eventhdlrbound != NULL );
5721 
5722 #ifdef SCIP_MORE_DEBUG
5723  SCIPdebugMsg(scip, "Transforming indicator constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
5724 #endif
5725 
5726  /* get data of original constraint */
5727  sourcedata = SCIPconsGetData(sourcecons);
5728  assert( sourcedata != NULL );
5729  assert( sourcedata->binvar != NULL );
5730 
5731  /* check for slackvar */
5732  if ( sourcedata->slackvar == NULL )
5733  {
5734  SCIPerrorMessage("The indicator constraint <%s> needs a slack variable.\n", SCIPconsGetName(sourcecons));
5735  return SCIP_INVALIDDATA;
5736  }
5737 
5738  /* check for linear constraint */
5739  if ( sourcedata->lincons == NULL )
5740  {
5741  SCIPerrorMessage("The indicator constraint <%s> needs a linear constraint variable.\n", SCIPconsGetName(sourcecons));
5742  return SCIP_INVALIDDATA;
5743  }
5744  assert( sourcedata->lincons != NULL );
5745  assert( sourcedata->slackvar != NULL );
5746 
5747  /* create constraint data */
5748  consdata = NULL;
5749  /* Note that the constraint has activeone = TRUE, since the binary variable has been negated already if needed. */
5750  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, SCIPconsGetName(sourcecons), &consdata, conshdlrdata->eventhdlrbound,
5751  conshdlrdata->eventhdlrrestart, sourcedata->binvar, TRUE, sourcedata->lessthanineq, sourcedata->slackvar, sourcedata->lincons, sourcedata->linconsactive) );
5752  consdata->activeone = sourcedata->activeone;
5753