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