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 
5773  /* reset number of fixed binary variables */
5774  conshdlrdata->nbinvarszero = 0;
5775 
5776  /* loop through variables */
5777  nvars = SCIPgetNVars(scip);
5778  vars = SCIPgetVars(scip);
5779 
5780  conshdlrdata->objindicatoronly = FALSE;
5781  conshdlrdata->minabsobj = SCIP_REAL_MAX;
5782 
5783  /* unmark all variables */
5784  SCIP_CALL( SCIPallocBufferArray(scip, &covered, nvars) );
5785  for (j = 0; j < nvars; ++j)
5786  covered[j] = FALSE;
5787 
5788  /* mark indicator variables */
5789  for (c = 0; c < nconss; ++c)
5790  {
5791  SCIP_CONSDATA* consdata;
5792  int probindex;
5793 
5794  assert( conss != NULL );
5795  assert( conss[c] != NULL );
5796 
5797  /* avoid non-active indicator constraints */
5798  if ( ! SCIPconsIsActive(conss[c]) )
5799  continue;
5800 
5801  consdata = SCIPconsGetData(conss[c]);
5802  assert( consdata != NULL );
5803  assert( consdata->binvar != NULL );
5804 
5805  if ( SCIPvarIsNegated(consdata->binvar) )
5806  {
5807  assert( SCIPvarGetNegatedVar(consdata->binvar) != NULL );
5808  probindex = SCIPvarGetProbindex(SCIPvarGetNegatedVar(consdata->binvar));
5809  }
5810  else
5811  probindex = SCIPvarGetProbindex(consdata->binvar);
5812 
5813  /* if presolving detected infeasibility it might be that the binary variables are not active */
5814  if ( probindex < 0 )
5815  continue;
5816 
5817  assert( 0 <= probindex && probindex < nvars );
5818  covered[probindex] = TRUE;
5819  }
5820 
5821  /* check all variables */
5822  for (j = 0; j < nvars; ++j)
5823  {
5824  SCIP_Real obj;
5825 
5826  obj = SCIPvarGetObj(vars[j]);
5827  if ( ! SCIPisZero(scip, obj) )
5828  {
5829  if ( ! covered[j] )
5830  break;
5831  if ( ! SCIPisIntegral(scip, obj) )
5832  break;
5833  if ( REALABS(obj) < conshdlrdata->minabsobj )
5834  conshdlrdata->minabsobj = REALABS(obj);
5835  }
5836  }
5837 
5838  /* if all variables have integral objective and only indicator variables have nonzero objective */
5839  if ( j >= nvars )
5840  {
5841  /* if there are variables with nonzero objective */
5842  if ( conshdlrdata->minabsobj < SCIP_REAL_MAX )
5843  {
5844  assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
5845  assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0) );
5846 
5847  conshdlrdata->objindicatoronly = TRUE;
5848 
5849  assert( conshdlrdata->eventhdlrrestart != NULL );
5850  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
5851  }
5852  }
5853 
5854  SCIPfreeBufferArray(scip, &covered);
5855  }
5856 
5857  return SCIP_OKAY;
5858 }
5859 
5860 
5861 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
5862 static
5863 SCIP_DECL_CONSEXITSOL(consExitsolIndicator)
5864 { /*lint --e{715}*/
5865  SCIP_CONSHDLRDATA* conshdlrdata;
5866  int c;
5867 
5868  assert( scip != NULL );
5869  assert( conshdlr != NULL );
5870  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5871 
5872  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5873  assert( conshdlrdata != NULL );
5874 
5875  if ( conshdlrdata->sepaalternativelp )
5876  {
5877  if ( conshdlrdata->slackhash != NULL )
5878  {
5879 #ifdef SCIP_DEBUG
5880  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator slack hash:\n");
5881  SCIPhashmapPrintStatistics(conshdlrdata->slackhash, SCIPgetMessagehdlr(scip));
5882 #endif
5883  SCIPhashmapFree(&conshdlrdata->slackhash);
5884  }
5885 
5886  if ( conshdlrdata->altlp != NULL )
5887  {
5888  assert( conshdlrdata->varhash != NULL );
5889  assert( conshdlrdata->lbhash != NULL );
5890  assert( conshdlrdata->ubhash != NULL );
5891 
5892 #ifdef SCIP_DEBUG
5893  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator var hash:\n");
5894  SCIPhashmapPrintStatistics(conshdlrdata->varhash, SCIPgetMessagehdlr(scip));
5895  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator lower bound hash:\n");
5896  SCIPhashmapPrintStatistics(conshdlrdata->lbhash, SCIPgetMessagehdlr(scip));
5897  SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator upper bound hash:\n");
5898  SCIPhashmapPrintStatistics(conshdlrdata->ubhash, SCIPgetMessagehdlr(scip));
5899 #endif
5900 
5901  SCIPhashmapFree(&conshdlrdata->varhash);
5902  SCIPhashmapFree(&conshdlrdata->lbhash);
5903  SCIPhashmapFree(&conshdlrdata->ubhash);
5904 
5905  SCIP_CALL( SCIPlpiFree(&conshdlrdata->altlp) );
5906 
5907  /* save the information that the columns have been deleted */
5908  for (c = 0; c < nconss; ++c)
5909  {
5910  SCIP_CONSDATA* consdata;
5911 
5912  assert( conss != NULL );
5913  assert( conss[c] != NULL );
5914 
5915  consdata = SCIPconsGetData(conss[c]);
5916  assert( consdata != NULL );
5917  consdata->colindex = -1;
5918  }
5919  }
5920  }
5921  else
5922  {
5923  assert( conshdlrdata->slackhash == NULL );
5924  assert( conshdlrdata->varhash == NULL );
5925  assert( conshdlrdata->lbhash == NULL );
5926  assert( conshdlrdata->ubhash == NULL );
5927  }
5928 
5929  return SCIP_OKAY;
5930 }
5931 
5932 
5933 /** frees specific constraint data */
5934 static
5935 SCIP_DECL_CONSDELETE(consDeleteIndicator)
5937  assert( scip != NULL );
5938  assert( conshdlr != NULL );
5939  assert( cons != NULL );
5940  assert( consdata != NULL );
5941  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5942 
5943 #ifdef SCIP_MORE_DEBUG
5944  SCIPdebugMsg(scip, "Deleting indicator constraint <%s>.\n", SCIPconsGetName(cons) );
5945 #endif
5946 
5947  /* Make sure that the hash for binary variables is freed. If we read a problem and then another problem without
5948  * solving (transforming) between, then no callback of constraint handlers are called. Thus, we cannot easily free the
5949  * hash map there. */
5950  if ( SCIPconshdlrGetNConss(conshdlr) == 0 )
5951  {
5952  SCIP_CONSHDLRDATA* conshdlrdata;
5953 
5954  /* get constraint handler data */
5955  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5956  assert( conshdlrdata != NULL );
5957 
5958  if ( conshdlrdata->binslackvarhash != NULL )
5959  SCIPhashmapFree(&conshdlrdata->binslackvarhash);
5960  }
5961 
5962  /* drop events on transformed variables */
5963  if ( SCIPconsIsTransformed(cons) )
5964  {
5965  SCIP_CONSHDLRDATA* conshdlrdata;
5966 
5967  /* get constraint handler data */
5968  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5969  assert( conshdlrdata != NULL );
5970 
5971  if ( conshdlrdata->sepaalternativelp )
5972  {
5973  SCIP_CALL( deleteAltLPConstraint(scip, conshdlr, cons) );
5974  }
5975 
5976  assert( (*consdata)->slackvar != NULL );
5977  assert( (*consdata)->binvar != NULL );
5978 
5979  /* free events only in correct stages */
5981  {
5982  if ( (*consdata)->linconsactive )
5983  {
5984  assert( conshdlrdata->eventhdlrbound != NULL );
5985  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
5986  (SCIP_EVENTDATA*) cons, -1) );
5987  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
5988  (SCIP_EVENTDATA*) cons, -1) );
5989  }
5990  if ( conshdlrdata->forcerestart )
5991  {
5992  assert( conshdlrdata->eventhdlrrestart != NULL );
5993  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
5994  (SCIP_EVENTDATA*) conshdlrdata, -1) );
5995  }
5996 
5997  /* drop bound change events on variables of linear constraints */
5998  if ( conshdlrdata->linconsevents && (*consdata)->linconsactive && (*consdata)->varswithevents != NULL )
5999  {
6000  int j;
6001  assert( cons != NULL );
6002  assert( (*consdata)->eventtypes != NULL );
6003  assert( (*consdata)->lincons != NULL );
6004 
6005  for (j = 0; j < (*consdata)->nevents; ++j)
6006  {
6007  assert( !SCIPvarIsDeleted((*consdata)->varswithevents[j]) );
6008  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->varswithevents[j], (*consdata)->eventtypes[j], conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, -1) );
6009  }
6010  SCIPfreeBlockMemoryArray(scip, &(*consdata)->varswithevents, (*consdata)->nevents);
6011  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventtypes, (*consdata)->nevents);
6012 
6013  (*consdata)->nevents = 0;
6014  assert( (*consdata)->varswithevents == NULL );
6015  assert( (*consdata)->eventtypes == NULL );
6016  }
6017  }
6018  }
6019 
6020  /* Can there be cases where lincons is NULL, e.g., if presolve found the problem infeasible? */
6021  assert( (*consdata)->lincons != NULL );
6022 
6023  /* mark linear constraint to be upgrade-able */
6024  if ( SCIPconsIsActive((*consdata)->lincons) )
6025  {
6026  SCIPconsAddUpgradeLocks((*consdata)->lincons, -1);
6027  assert( SCIPconsGetNUpgradeLocks((*consdata)->lincons) == 0 );
6028  }
6029 
6030  /* release linear constraint and slack variable */
6031  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->slackvar) );
6032  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->lincons) );
6033 
6034  SCIPfreeBlockMemory(scip, consdata);
6035 
6036  return SCIP_OKAY;
6037 }
6038 
6039 
6040 /** transforms constraint data into data belonging to the transformed problem */
6041 static
6042 SCIP_DECL_CONSTRANS(consTransIndicator)
6044  SCIP_CONSDATA* consdata;
6045  SCIP_CONSHDLRDATA* conshdlrdata;
6046  SCIP_CONSDATA* sourcedata;
6047  char s[SCIP_MAXSTRLEN];
6048 
6049  assert( scip != NULL );
6050  assert( conshdlr != NULL );
6051  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6052  assert( sourcecons != NULL );
6053  assert( targetcons != NULL );
6054 
6055  /* get constraint handler data */
6056  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6057  assert( conshdlrdata != NULL );
6058  assert( conshdlrdata->eventhdlrbound != NULL );
6059 
6060 #ifdef SCIP_MORE_DEBUG
6061  SCIPdebugMsg(scip, "Transforming indicator constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
6062 #endif
6063 
6064  /* get data of original constraint */
6065  sourcedata = SCIPconsGetData(sourcecons);
6066  assert( sourcedata != NULL );
6067  assert( sourcedata->binvar != NULL );
6068 
6069  /* check for slackvar */
6070  if ( sourcedata->slackvar == NULL )
6071  {
6072  SCIPerrorMessage("The indicator constraint <%s> needs a slack variable.\n", SCIPconsGetName(sourcecons));
6073  return SCIP_INVALIDDATA;
6074  }
6075 
6076  /* check for linear constraint */
6077  if ( sourcedata->lincons == NULL )
6078  {
6079  SCIPerrorMessage("The indicator constraint <%s> needs a linear constraint.\n", SCIPconsGetName(sourcecons));
6080  return SCIP_INVALIDDATA;
6081  }
6082  assert( sourcedata->lincons != NULL );
6083  assert( sourcedata->slackvar != NULL );
6084 
6085  /* create constraint data */
6086  consdata = NULL;
6087  /* Note that the constraint has activeone = TRUE, since the binary variable has been negated already if needed. */
6088  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, SCIPconsGetName(sourcecons), &consdata, conshdlrdata->eventhdlrrestart,
6089  sourcedata->binvar, TRUE, sourcedata->lessthanineq, sourcedata->slackvar, sourcedata->lincons, sourcedata->linconsactive) );
6090  consdata->activeone = sourcedata->activeone;
6091  assert( consdata != NULL );
6092 
6093  /* capture slack variable and linear constraint */
6094  SCIP_CALL( SCIPcaptureVar(scip, consdata->slackvar) );
6095  SCIP_CALL( SCIPcaptureCons(scip, consdata->lincons) );
6096 
6097  /* create transformed constraint with the same flags */
6098  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
6099  SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
6100  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
6101  SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
6102  SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
6103  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
6104  SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
6105 
6106  /* catch local bound change events on binary variable */
6107  if ( sourcedata->linconsactive )
6108  {
6109  assert( SCIPisTransformed(scip) );
6110  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *targetcons, NULL) );
6111  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *targetcons, NULL) );
6112  }
6113 
6114  /* make sure that binary variable hash exists */
6115  if ( conshdlrdata->sepaalternativelp )
6116  {
6117  if ( conshdlrdata->binvarhash == NULL )
6118  {
6119  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
6120  }
6121 
6122  /* check whether binary variable is present: note that a binary variable might appear several times, but this seldomly happens. */
6123  assert( conshdlrdata->binvarhash != NULL );
6124  if ( ! SCIPhashmapExists(conshdlrdata->binvarhash, (void*) consdata->binvar) )
6125  {
6126  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binvarhash, (void*) consdata->binvar, (void*) (*targetcons)) );
6127  }
6128  }
6129 
6130  return SCIP_OKAY;
6131 }
6132 
6133 
6134 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
6135 static
6136 SCIP_DECL_CONSINITPRE(consInitpreIndicator)
6137 { /*lint --e{715}*/
6138  SCIP_CONSHDLRDATA* conshdlrdata;
6139  int c;
6140 
6141  assert( scip != NULL );
6142  assert( conshdlr != NULL );
6143  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6144 
6145  if ( SCIPgetStatus(scip) != SCIP_STATUS_UNKNOWN )
6146  return SCIP_OKAY;
6147 
6148  SCIPdebugMsg(scip, "Initpre method for indicator constraints.\n");
6149 
6150  /* check each constraint and get transformed linear constraint */
6151  for (c = 0; c < nconss; ++c)
6152  {
6153  SCIP_CONSDATA* consdata;
6154 
6155  assert( conss != NULL );
6156  assert( conss[c] != NULL );
6157  assert( SCIPconsIsTransformed(conss[c]) );
6158 
6159  consdata = SCIPconsGetData(conss[c]);
6160  assert( consdata != NULL );
6161 
6162  /* if not happened already, get transformed linear constraint */
6163  assert( consdata->lincons != NULL );
6164  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear") == 0 );
6165 
6166  /* in a restart the linear constraint might already be transformed */
6167  if ( ! SCIPconsIsTransformed(consdata->lincons) )
6168  {
6169  SCIP_CONS* translincons;
6170 
6171  SCIP_CALL( SCIPgetTransformedCons(scip, consdata->lincons, &translincons) );
6172  assert( translincons != NULL );
6173 
6174  SCIP_CALL( SCIPreleaseCons(scip, &consdata->lincons) );
6175  SCIP_CALL( SCIPcaptureCons(scip, translincons) );
6176  consdata->lincons = translincons;
6177  }
6178  }
6179 
6180  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6181  assert( conshdlrdata != NULL );
6182 
6183  /* reset flag, in case presolve was called for some problem before */
6184  conshdlrdata->addedcouplingcons = FALSE;
6185 
6186  return SCIP_OKAY;
6187 }
6188 
6189 
6190 /** presolving method of constraint handler
6191  *
6192  * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
6193  * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
6194  * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not
6195  * inserted. Depending on the parameter @a addcouplingcons we add a variable upper bound or a row
6196  * (in consInitlpIndicator()).
6197  *
6198  * @warning We can never delete linear constraints, because we need them to get the right values
6199  * for the slack variables!
6200  */
6201 static
6202 SCIP_DECL_CONSPRESOL(consPresolIndicator)
6203 { /*lint --e{715}*/
6204  SCIP_CONSHDLRDATA* conshdlrdata;
6205  SCIP_Bool noReductions;
6206  SCIPdebug( int oldnfixedvars = *nfixedvars; )
6207  SCIPdebug( int oldndelconss = *ndelconss; )
6208  int c;
6209 
6210  assert( scip != NULL );
6211  assert( conshdlr != NULL );
6212  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6213  assert( result != NULL );
6214 
6215  *result = SCIP_DIDNOTRUN;
6216 
6217  /* get constraint handler data */
6218  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6219  assert( conshdlrdata != NULL );
6220 
6221  SCIPdebugMsg(scip, "Presolving indicator constraints.\n");
6222 
6223  /* only run if success is possible */
6224  if ( nrounds == 0 || nnewfixedvars > 0 || nnewchgbds > 0 || nnewaggrvars > 0 )
6225  {
6226  *result = SCIP_DIDNOTFIND;
6227 
6228  /* check each constraint */
6229  for (c = 0; c < nconss; ++c)
6230  {
6231  SCIP_CONSDATA* consdata;
6232  SCIP_CONS* cons;
6233  SCIP_Bool success;
6234  SCIP_Bool cutoff;
6235 
6236  assert( conss != NULL );
6237  assert( conss[c] != NULL );
6238  cons = conss[c];
6239  consdata = SCIPconsGetData(cons);
6240  assert( consdata != NULL );
6241  assert( consdata->binvar != NULL );
6242  assert( ! SCIPconsIsModifiable(cons) );
6243 
6244 #ifdef SCIP_MORE_DEBUG
6245  SCIPdebugMsg(scip, "Presolving indicator constraint <%s>.\n", SCIPconsGetName(cons) );
6246 #endif
6247 
6248  /* do nothing if the linear constraint is not active */
6249  if ( ! consdata->linconsactive )
6250  continue;
6251 
6252  assert( consdata->lincons != NULL );
6253  assert( consdata->slackvar != NULL );
6254  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear") == 0 );
6255  assert( SCIPconsIsTransformed(consdata->lincons) );
6256 
6257  /* add implications if not yet done */
6258  if ( ! consdata->implicationadded )
6259  {
6260  int nbnds = 0;
6261  SCIP_CALL( SCIPaddVarImplication(scip, consdata->binvar, TRUE, consdata->slackvar, SCIP_BOUNDTYPE_UPPER, 0.0,
6262  &cutoff, &nbnds) );
6263  *nchgbds += nbnds;
6264 
6265  /* cutoff/infeasible might be true if preprocessing was truncated */
6266  /* note: nbdchgs == 0 is not necessarily true, because preprocessing might be truncated. */
6267  consdata->implicationadded = TRUE;
6268  if ( cutoff )
6269  {
6270  *result = SCIP_CUTOFF;
6271  return SCIP_OKAY;
6272  }
6273  }
6274 
6275  /* check type of slack variable if not yet done */
6276  if ( ! consdata->slacktypechecked )
6277  {
6278  consdata->slacktypechecked = TRUE;
6279  /* check if slack variable can be made implicit integer. */
6280  if ( SCIPvarGetType(consdata->slackvar) == SCIP_VARTYPE_CONTINUOUS )
6281  {
6282  SCIP_Real* vals;
6283  SCIP_VAR** vars;
6284  SCIP_VAR* slackvar;
6285  SCIP_Bool foundslackvar = FALSE;
6286  int nvars;
6287  int j;
6288 
6289  assert( consdata->lincons != NULL );
6290  vars = SCIPgetVarsLinear(scip, consdata->lincons);
6291  vals = SCIPgetValsLinear(scip, consdata->lincons);
6292  nvars = SCIPgetNVarsLinear(scip, consdata->lincons);
6293  slackvar = consdata->slackvar;
6294  assert( slackvar != NULL );
6295 
6296  for (j = 0; j < nvars; ++j)
6297  {
6298  if ( vars[j] == slackvar )
6299  foundslackvar = TRUE;
6300  else
6301  {
6302  if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, vals[j]))
6303  break;
6304  }
6305  }
6306  /* something is strange if the slack variable does not appear in the linear constraint (possibly because it is an artificial constraint) */
6307  if ( j == nvars && foundslackvar )
6308  {
6309  SCIP_Bool infeasible;
6310  SCIP_Real lb;
6311  SCIP_Real ub;
6312 
6313  lb = SCIPvarGetLbGlobal(consdata->slackvar);
6314  ub = SCIPvarGetUbGlobal(consdata->slackvar);
6315  if ( (SCIPisInfinity(scip, -lb) || SCIPisIntegral(scip, lb)) && (SCIPisInfinity(scip, ub) || SCIPisIntegral(scip, ub)) )
6316  {
6317  SCIP_CALL( SCIPchgVarType(scip, consdata->slackvar, SCIP_VARTYPE_IMPLINT, &infeasible) );
6318  /* don't assert feasibility here because the presolver should detect infeasibility */
6319  }
6320  else
6321  {
6322  /* It can happen that the bounds of the slack variable have been changed to be non-integral in
6323  * previous presolving steps. We then might get a problem with tightening the bounds. In this case,
6324  * we just leave the slack variable to be continuous. */
6325  SCIPdebugMsg(scip, "Cannot change type of slack variable (<%s>) to IMPLINT, since global bound is non-integral: (%g, %g).\n",
6326  SCIPvarGetName(consdata->slackvar), SCIPvarGetLbGlobal(consdata->slackvar), SCIPvarGetUbGlobal(consdata->slackvar));
6327  }
6328  }
6329  }
6330  }
6331 
6332  /* perform one presolving round */
6333  SCIP_CALL( presolRoundIndicator(scip, conshdlrdata, cons, consdata,
6334  conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip), &cutoff, &success, ndelconss, nfixedvars) );
6335 
6336  if ( cutoff )
6337  {
6338  *result = SCIP_CUTOFF;
6339  return SCIP_OKAY;
6340  }
6341  if ( success )
6342  *result = SCIP_SUCCESS;
6343  }
6344  }
6345 
6346  /* determine whether other methods have found reductions */
6347  noReductions = nnewfixedvars == 0 && nnewaggrvars == 0 && nnewchgvartypes == 0 && nnewchgbds == 0
6348  && nnewdelconss == 0 && nnewchgcoefs == 0 && nnewchgsides == 0;
6349 
6350  /* add variable upper bounds after bounds are likely to be strengthened */
6351  if ( noReductions && *result != SCIP_SUCCESS && conshdlrdata->addcouplingcons && ! conshdlrdata->addedcouplingcons )
6352  {
6353  int ngen;
6354 
6355  /* create variable upper bounds, possibly removing indicator constraints */
6356  SCIP_CALL( createVarUbs(scip, conshdlrdata, conss, nconss, &ngen) );
6357 
6358  if ( ngen > 0 )
6359  {
6360  *result = SCIP_SUCCESS;
6361  *nupgdconss += ngen;
6362  if ( conshdlrdata->removeindicators )
6363  *ndelconss += ngen;
6364  }
6365  conshdlrdata->addedcouplingcons = TRUE;
6366  }
6367 
6368  SCIPdebug( SCIPdebugMsg(scip, "Presolved %d constraints (fixed %d variables, removed 0 variables, and deleted %d constraints).\n",
6369  nconss, *nfixedvars - oldnfixedvars, *ndelconss - oldndelconss); )
6370 
6371  return SCIP_OKAY; /*lint !e438*/
6372 }
6373 
6374 
6375 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved)
6376  *
6377  * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
6378  * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
6379  * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not inserted.
6380  */
6381 static
6382 SCIP_DECL_CONSINITLP(consInitlpIndicator)
6384  int c;
6385  SCIP_CONSHDLRDATA* conshdlrdata;
6386 
6387  assert( scip != NULL );
6388  assert( conshdlr != NULL );
6389  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6390 
6391  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6392  assert( conshdlrdata != NULL );
6393 
6394  *infeasible = FALSE;
6395 
6396  /* check whether coupling constraints should be added */
6397  if ( ! conshdlrdata->addcoupling )
6398  return SCIP_OKAY;
6399 
6400  /* check whether coupling constraints have been added already */
6401  if ( conshdlrdata->addcouplingcons && conshdlrdata->addedcouplingcons )
6402  return SCIP_OKAY;
6403 
6404  SCIPdebugMsg(scip, "Handle initial rows for %d indicator constraints.\n", nconss);
6405 
6406  /* check each constraint */
6407  for (c = 0; c < nconss && !(*infeasible); ++c)
6408  {
6409  SCIP_CONSDATA* consdata;
6410  SCIP_Real ub;
6411 
6412  assert( conss != NULL );
6413  assert( conss[c] != NULL );
6414  consdata = SCIPconsGetData(conss[c]);
6415  assert( consdata != NULL );
6416 
6417  /* do not add inequalities if there are no linear constraints (no slack variable available) */
6418  if ( ! consdata->linconsactive )
6419  continue;
6420 
6421  /* get upper bound for slack variable in linear constraint */
6422  ub = SCIPvarGetUbGlobal(consdata->slackvar);
6423  assert( ! SCIPisNegative(scip, ub) );
6424 
6425  /* insert corresponding row if helpful and coefficient is not too large */
6426  if ( ub <= conshdlrdata->maxcouplingvalue )
6427  {
6428  char name[50];
6429 
6430 #ifndef NDEBUG
6431  (void) SCIPsnprintf(name, 50, "couple%d", c);
6432 #else
6433  name[0] = '\0';
6434 #endif
6435 
6436  /* add variable upper bound if required */
6437  if ( conshdlrdata->addcouplingcons )
6438  {
6439  SCIP_CONS* cons;
6440 
6441  assert( ! conshdlrdata->addedcouplingcons );
6442 
6443  SCIPdebugMsg(scip, "Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
6444 
6445  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
6446  TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
6447 
6448  SCIP_CALL( SCIPaddCons(scip, cons) );
6449  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
6450  }
6451  else
6452  {
6453  SCIP_ROW* row;
6454 
6455  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, FALSE, FALSE, FALSE) );
6456  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
6457 
6458  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
6459  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
6460  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
6461 
6462  SCIPdebugMsg(scip, "Insert coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
6463 #ifdef SCIP_OUTPUT
6464  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
6465 #endif
6466  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
6467  SCIP_CALL( SCIPreleaseRow(scip, &row));
6468  }
6469  }
6470  }
6471 
6472  return SCIP_OKAY;
6473 }
6474 
6475 
6476 /** separation method of constraint handler for LP solutions */
6477 static
6478 SCIP_DECL_CONSSEPALP(consSepalpIndicator)
6479 { /*lint --e{715}*/
6480  assert( scip != NULL );
6481  assert( conshdlr != NULL );
6482  assert( conss != NULL );
6483  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6484  assert( result != NULL );
6485 
6486  /* perform separation */
6487  SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, NULL, SCIP_TYPE_SEPALP, result) );
6488 
6489  return SCIP_OKAY;
6490 }
6491 
6492 
6493 /** separation method of constraint handler for arbitrary primal solutions */
6494 static
6495 SCIP_DECL_CONSSEPASOL(consSepasolIndicator)
6496 { /*lint --e{715}*/
6497  assert( scip != NULL );
6498  assert( conshdlr != NULL );
6499  assert( conss != NULL );
6500  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6501  assert( result != NULL );
6502 
6503  /* perform separation */
6504  SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, sol, SCIP_TYPE_SEPASOL, result) );
6505 
6506  return SCIP_OKAY;
6507 }
6508 
6509 
6510 /** constraint enforcing method of constraint handler for LP solutions */
6511 static
6512 SCIP_DECL_CONSENFOLP(consEnfolpIndicator)
6513 { /*lint --e{715}*/
6514  SCIP_CONSHDLRDATA* conshdlrdata;
6515 
6516  assert( scip != NULL );
6517  assert( conshdlr != NULL );
6518  assert( conss != NULL );
6519  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6520  assert( result != NULL );
6521 
6522  if ( solinfeasible )
6523  {
6524  *result = SCIP_FEASIBLE;
6525  return SCIP_OKAY;
6526  }
6527 
6528  /* get constraint handler data */
6529  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6530  assert( conshdlrdata != NULL );
6531 
6532  SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, NULL, SCIP_TYPE_ENFOLP, conshdlrdata->genlogicor, result) );
6533 
6534  return SCIP_OKAY;
6535 }
6536 
6537 
6538 /** constraint enforcing method of constraint handler for relaxation solutions */
6539 static
6540 SCIP_DECL_CONSENFORELAX(consEnforelaxIndicator)
6541 { /*lint --e{715}*/
6542  SCIP_CONSHDLRDATA* conshdlrdata;
6543 
6544  assert( scip != NULL );
6545  assert( conshdlr != NULL );
6546  assert( conss != NULL );
6547  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6548  assert( result != NULL );
6549 
6550  if ( solinfeasible )
6551  {
6552  *result = SCIP_FEASIBLE;
6553  return SCIP_OKAY;
6554  }
6555 
6556  /* get constraint handler data */
6557  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6558  assert( conshdlrdata != NULL );
6559 
6560  SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, sol, SCIP_TYPE_ENFORELAX, conshdlrdata->genlogicor, result) );
6561 
6562  return SCIP_OKAY;
6563 }
6564 
6565 
6566 /** constraint enforcing method of constraint handler for pseudo solutions */
6567 static
6568 SCIP_DECL_CONSENFOPS(consEnfopsIndicator)
6569 { /*lint --e{715}*/
6570  assert( scip != NULL );
6571  assert( conshdlr != NULL );
6572  assert( conss != NULL );
6573  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6574  assert( result != NULL );
6575 
6576  if ( solinfeasible )
6577  {
6578  *result = SCIP_FEASIBLE;
6579  return SCIP_OKAY;
6580  }
6581 
6582  if ( objinfeasible )
6583  {
6584  *result = SCIP_DIDNOTRUN;
6585  return SCIP_OKAY;
6586  }
6587 
6588  SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, NULL, SCIP_TYPE_ENFOPS, TRUE, result) );
6589 
6590  return SCIP_OKAY;
6591 }
6592 
6593 
6594 /** feasibility check method of constraint handler for integral solutions */
6595 static
6596 SCIP_DECL_CONSCHECK(consCheckIndicator)
6597 { /*lint --e{715}*/
6598  SCIP_SOL* trysol = NULL;
6599  SCIP_CONSHDLRDATA* conshdlrdata;
6600  SCIP_Bool someLinconsNotActive;
6601  SCIP_Bool changedSol;
6602  int c;
6603 
6604  assert( scip != NULL );
6605  assert( conshdlr != NULL );
6606  assert( conss != NULL );
6607  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6608  assert( result != NULL );
6609 
6610  SCIPdebugMsg(scip, "Checking %d indicator constraints <%s>.\n", nconss, SCIPconshdlrGetName(conshdlr) );
6611 
6612  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6613  assert( conshdlrdata != NULL );
6614 
6615  /* try to repair solution below, if it makes sense (will send solution to trysol heuristic in any case (see below) */
6616  if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM && SCIPgetStage(scip) < SCIP_STAGE_SOLVED && conshdlrdata->trysolutions && conshdlrdata->heurtrysol != NULL )
6617  {
6618  SCIP_CALL( SCIPcreateSolCopy(scip, &trysol, sol) );
6619  assert( trysol != NULL );
6620  }
6621 
6622  /* check each constraint */
6623  *result = SCIP_FEASIBLE;
6624  changedSol = FALSE;
6625  someLinconsNotActive = FALSE;
6626  for (c = 0; c < nconss; ++c)
6627  {
6628  SCIP_CONSDATA* consdata;
6629 
6630  assert( conss[c] != NULL );
6631  consdata = SCIPconsGetData(conss[c]);
6632  assert( consdata != NULL );
6633  assert( consdata->binvar != NULL );
6634 
6635  /* if the linear constraint has not been generated, we do nothing */
6636  if ( ! consdata->linconsactive )
6637  {
6638  someLinconsNotActive = TRUE;
6639  continue;
6640  }
6641 
6642  assert( consdata->slackvar != NULL );
6643  /* if printreason is true it can happen that non-integral solutions are checked */
6644  assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
6645 
6646  /* if constraint is infeasible */
6647  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) &&
6648  ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) )
6649  {
6650  SCIP_Real absviol = REALABS(SCIPgetSolVal(scip, sol, consdata->slackvar));
6651  SCIP_Real relviol = SCIPrelDiff(absviol, 0.0);
6652 
6653  if( sol != NULL )
6654  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
6655 
6656  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
6657  *result = SCIP_INFEASIBLE;
6658 
6659  if ( printreason )
6660  {
6661  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
6662  SCIPinfoMessage(scip, NULL, ";\nviolation: <%s> = %g and <%s> = %.15g\n",
6663  SCIPvarGetName(consdata->binvar), SCIPgetSolVal(scip, sol, consdata->binvar),
6664  SCIPvarGetName(consdata->slackvar), SCIPgetSolVal(scip, sol, consdata->slackvar));
6665  }
6666 
6667  /* try to make solution feasible if it makes sense - otherwise exit */
6668  if ( trysol != NULL )
6669  {
6670  SCIP_Bool changed;
6671  SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
6672  changedSol = changedSol || changed;
6673  }
6674  else
6675  {
6676  SCIPdebugMsg(scip, "Indicator constraint %s is not feasible.\n", SCIPconsGetName(conss[c]));
6677 
6678  if ( ! completely )
6679  return SCIP_OKAY;
6680  }
6681  }
6682  else
6683  {
6684  if ( trysol != NULL )
6685  {
6686  SCIP_Bool changed;
6687  SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
6688  changedSol = changedSol || changed;
6689  }
6690  }
6691  }
6692 
6693  /* if some linear constraints are not active, we need to check feasibility via the alternative polyhedron */
6694  if ( someLinconsNotActive )
6695  {
6696  SCIP_LPI* lp;
6697  SCIP_Bool infeasible;
6698  SCIP_Bool error;
6699  SCIP_Bool* S;
6700 
6701  lp = conshdlrdata->altlp;
6702  assert( conshdlrdata->sepaalternativelp );
6703 
6704  /* the check maybe called before we have build the alternative polyhedron -> return SCIP_INFEASIBLE */
6705  if ( lp != NULL )
6706  {
6707 #ifndef NDEBUG
6708  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
6709 #endif
6710 
6711  /* change coefficients of bounds in alternative LP */
6712  if ( conshdlrdata->updatebounds )
6713  {
6714  SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
6715  }
6716 
6717  /* scale first row if necessary */
6718  SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
6719 
6720  /* set objective function to current solution */
6721  SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
6722 
6723  SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
6724 
6725  /* set up variables fixed to 1 */
6726  for (c = 0; c < nconss; ++c)
6727  {
6728  SCIP_CONSDATA* consdata;
6729 
6730  assert( conss[c] != NULL );
6731  consdata = SCIPconsGetData(conss[c]);
6732  assert( consdata != NULL );
6733 
6734  /* if printreason is true it can happen that non-integral solutions are checked */
6735  assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
6736  if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
6737  S[c] = TRUE;
6738  else
6739  S[c] = FALSE;
6740  }
6741 
6742  /* fix the variables in S */
6743  SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
6744 
6745  /* check feasibility */
6747  SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, TRUE, &infeasible, &error) );
6749 
6750  if ( error )
6751  return SCIP_LPERROR;
6752 
6753  if ( ! infeasible )
6754  *result = SCIP_INFEASIBLE;
6755 
6756  /* reset bounds */
6757  SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
6758 
6759 #ifndef NDEBUG
6760  SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
6761 #endif
6762 
6763  SCIPfreeBufferArray(scip, &S);
6764  }
6765  else
6766  *result = SCIP_INFEASIBLE;
6767  }
6768  else
6769  {
6770  /* tell heur_trysol about solution - it will pass it to SCIP */
6771  if ( trysol != NULL && changedSol )
6772  {
6773  assert( conshdlrdata->heurtrysol != NULL );
6774  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->heurtrysol, trysol) );
6775  }
6776  }
6777 
6778  if ( trysol != NULL )
6779  SCIP_CALL( SCIPfreeSol(scip, &trysol) );
6780 
6781  if ( *result == SCIP_INFEASIBLE )
6782  {
6783  SCIPdebugMsg(scip, "Indicator constraints are not feasible.\n");
6784  return SCIP_OKAY;
6785  }
6786 
6787  /* at this point we are feasible */
6788  SCIPdebugMsg(scip, "Indicator constraints are feasible.\n");
6789 
6790  return SCIP_OKAY;
6791 }
6792 
6793 
6794 /** domain propagation method of constraint handler */
6795 static
6796 SCIP_DECL_CONSPROP(consPropIndicator)
6797 { /*lint --e{715}*/
6798  SCIP_CONSHDLRDATA* conshdlrdata;
6799  SCIP_Bool dualreductions;
6800  int ngen = 0;
6801  int c;
6802 
6803  assert( scip != NULL );
6804  assert( conshdlr != NULL );
6805  assert( conss != NULL );
6806  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6807  assert( result != NULL );
6808 
6809  *result = SCIP_DIDNOTRUN;
6810 
6811  assert( SCIPisTransformed(scip) );
6812 
6813  SCIPdebugMsg(scip, "Start propagation of constraint handler <%s>.\n", SCIPconshdlrGetName(conshdlr));
6814 
6815  /* get constraint handler data */
6816  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6817  assert( conshdlrdata != NULL );
6818 
6819  /* avoid propagation if no bound has changed */
6820  if ( ! conshdlrdata->boundhaschanged && ! SCIPinRepropagation(scip) && ! conshdlrdata->linconsboundschanged )
6821  {
6822  *result = SCIP_DIDNOTFIND;
6823  return SCIP_OKAY;
6824  }
6825 
6826  /* if first time called, add events on variables of linear constraint */
6827  if ( !conshdlrdata->linconsevents )
6828  {
6829  for (c = 0; c < nconss; ++c)
6830  {
6831  SCIP_CONSDATA* consdata;
6832  SCIP_VAR** vars;
6833  SCIP_Real* vals;
6834  int nvars;
6835  int j;
6836  assert( conss[c] != NULL );
6837 
6838  consdata = SCIPconsGetData(conss[c]);
6839  assert( consdata != NULL );
6840 
6841  /* if the linear constraint is not present, we continue */
6842  if ( ! consdata->linconsactive )
6843  continue;
6844 
6845  /* do not add events if upper bound of slackvar is already small */
6846  if ( SCIPvarGetUbLocal(consdata->slackvar) <= conshdlrdata->maxcouplingvalue )
6847  continue;
6848 
6849  /* do not add events if it is not a <= inequality; we do not propagate in this case */
6850  if ( SCIPisInfinity(scip, SCIPgetRhsLinear(scip, consdata->lincons) ) )
6851  continue;
6852 
6853  assert( consdata->lincons != NULL );
6854  vars = SCIPgetVarsLinear(scip, consdata->lincons);
6855  vals = SCIPgetValsLinear(scip, consdata->lincons);
6856  nvars = SCIPgetNVarsLinear(scip, consdata->lincons);
6857  assert( consdata->slackvar != NULL );
6858  assert( nvars != 0 );
6859 
6860  /* alloc memory to store events on variables of linear constraint; otherwise we can not drop the events when the cons is deleted */
6861  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varswithevents, nvars - 1) );
6862  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventtypes, nvars - 1) );
6863 
6864  for (j = 0; j < nvars; ++j)
6865  {
6866  if ( vars[j] == consdata->slackvar )
6867  continue;
6868 
6869  /* catch only bound changes which are important for propagation of max activity to upper bound of slackvar */
6870  if ( vals[j] > 0.0 )
6871  {
6872  SCIP_CALL( SCIPcatchVarEvent(scip, vars[j], SCIP_EVENTTYPE_UBTIGHTENED, conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
6873  consdata->varswithevents[consdata->nevents] = vars[j];
6874  consdata->eventtypes[consdata->nevents] = SCIP_EVENTTYPE_UBTIGHTENED;
6875  consdata->nevents++;
6876  }
6877  else
6878  {
6879  SCIP_CALL( SCIPcatchVarEvent(scip, vars[j], SCIP_EVENTTYPE_LBTIGHTENED, conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
6880  consdata->varswithevents[consdata->nevents] = vars[j];
6881  consdata->eventtypes[consdata->nevents] = SCIP_EVENTTYPE_LBTIGHTENED;
6882  consdata->nevents++;
6883  }
6884  }
6885  assert( consdata->nevents == nvars - 1 );
6886  }
6887  conshdlrdata->linconsevents = TRUE;
6888  }
6889 
6890  /* already mark that no bound has changed */
6891  conshdlrdata->boundhaschanged = FALSE;
6892  conshdlrdata->linconsboundschanged = FALSE;
6893 
6894  dualreductions = conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip);
6895 
6896  /* check each constraint */
6897  for (c = 0; c < nconss; ++c)
6898  {
6899  SCIP_CONS* cons;
6900  SCIP_CONSDATA* consdata;
6901  SCIP_Bool cutoff;
6902  int cnt;
6903 
6904  *result = SCIP_DIDNOTFIND;
6905 
6906  assert( conss[c] != NULL );
6907  cons = conss[c];
6908  consdata = SCIPconsGetData(cons);
6909  assert( consdata != NULL );
6910 
6911 #ifdef SCIP_MORE_DEBUG
6912  SCIPdebugMsg(scip, "Propagating indicator constraint <%s>.\n", SCIPconsGetName(cons) );
6913 #endif
6914 
6915  SCIP_CALL( propIndicator(scip, cons, consdata, conshdlrdata, dualreductions, conshdlrdata->addopposite, &cutoff, &cnt) );
6916 
6917  if ( cutoff )
6918  {
6919  *result = SCIP_CUTOFF;
6920  return SCIP_OKAY;
6921  }
6922  ngen += cnt;
6923  }
6924 
6925  SCIPdebugMsg(scip, "Propagated %d domains in constraint handler <%s>.\n", ngen, SCIPconshdlrGetName(conshdlr));
6926  if ( ngen > 0 )
6927  *result = SCIP_REDUCEDDOM;
6928 
6929  return SCIP_OKAY;
6930 }
6931 
6932 
6933 /** propagation conflict resolving method of constraint handler
6934  *
6935  * We check which bound changes were the reason for infeasibility. We use that @a inferinfo is 0 if
6936  * the binary variable has bounds that fix it to be nonzero (these bounds are the reason). Likewise
6937  * @a inferinfo is 1 if the slack variable has bounds that fix it to be nonzero.
6938  */
6939 static
6940 SCIP_DECL_CONSRESPROP(consRespropIndicator)
6941 { /*lint --e{715}*/
6942  SCIP_CONSDATA* consdata;
6943 
6944  assert( scip != NULL );
6945  assert( cons != NULL );
6946  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6947  assert( infervar != NULL );
6948  assert( bdchgidx != NULL );
6949  assert( result != NULL );
6950 
6951  *result = SCIP_DIDNOTFIND;
6952  SCIPdebugMsg(scip, "Propagation resolution method of indicator constraint <%s>.\n", SCIPconsGetName(cons));
6953 
6954  consdata = SCIPconsGetData(cons);
6955  assert( consdata != NULL );
6956  assert( inferinfo == 0 || inferinfo == 1 || inferinfo == 2 || inferinfo == 3 );
6957  assert( consdata->linconsactive );
6958 
6959  /* if the binary variable was the reason */
6960  if ( inferinfo == 0 )
6961  {
6962  assert( SCIPgetVarLbAtIndex(scip, consdata->binvar, bdchgidx, FALSE) > 0.5 );
6963  assert( infervar != consdata->binvar );
6964 
6965  SCIP_CALL( SCIPaddConflictLb(scip, consdata->binvar, bdchgidx) );
6966  }
6967  else if ( inferinfo == 1 )
6968  {
6969  /* if the slack variable fixed to a positive value was the reason */
6970  assert( infervar != consdata->slackvar );
6971  /* Use a weaker comparison to SCIPvarGetLbAtIndex here (i.e., SCIPisPositive instead of SCIPisFeasPositive),
6972  * because SCIPvarGetLbAtIndex might differ from the local bound at time bdchgidx by epsilon. */
6973  assert( SCIPisPositive(scip, SCIPgetVarLbAtIndex(scip, consdata->slackvar, bdchgidx, FALSE)) );
6974  SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, bdchgidx) );
6975  }
6976  else if ( inferinfo == 2 )
6977  {
6978  assert( SCIPisFeasZero(scip, SCIPgetVarUbAtIndex(scip, consdata->slackvar, bdchgidx, FALSE)) );
6979  assert( SCIPconshdlrGetData(conshdlr)->dualreductions && SCIPallowStrongDualReds(scip) && SCIPallowWeakDualReds(scip) );
6980  SCIP_CALL( SCIPaddConflictUb(scip, consdata->slackvar, bdchgidx) );
6981  }
6982  else
6983  {
6984  assert( inferinfo == 3 );
6985  SCIP_CALL( SCIPaddConflictUb(scip, consdata->slackvar, bdchgidx) );
6986  }
6987 
6988  *result = SCIP_SUCCESS;
6989 
6990  return SCIP_OKAY;
6991 }
6992 
6993 
6994 /** variable rounding lock method of constraint handler
6995  *
6996  * The up-rounding of the binary and slack variable may violate the constraint. If the linear
6997  * constraint is not active, we lock all variables in the depending constraint - otherwise they
6998  * will be fixed by dual presolving methods.
6999  */
7000 static
7001 SCIP_DECL_CONSLOCK(consLockIndicator)
7003  SCIP_CONSDATA* consdata;
7004 
7005  assert( scip != NULL );
7006  assert( conshdlr != NULL );
7007  assert( cons != NULL );
7008  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7009  consdata = SCIPconsGetData(cons);
7010  assert( consdata != NULL );
7011  assert( consdata->binvar != NULL );
7012 
7013 #ifdef SCIP_MORE_DEBUG
7014  SCIPdebugMsg(scip, "%socking constraint <%s>.\n", (nlocksneg < 0) || (nlockspos < 0) ? "Unl" : "L", SCIPconsGetName(cons));
7015 #endif
7016 
7017  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->binvar, locktype, nlocksneg, nlockspos) );
7018 
7019  if ( consdata->linconsactive )
7020  {
7021  assert( consdata->slackvar != NULL );
7022 
7023  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->slackvar, locktype, nlocksneg, nlockspos) );
7024  }
7025  else
7026  {
7027  SCIP_VAR** linvars;
7028  SCIP_Real* linvals;
7029  SCIP_Bool haslhs;
7030  SCIP_Bool hasrhs;
7031  int nlinvars;
7032  int j;
7033 
7034  assert( consdata->lincons != NULL );
7035  assert( consdata->slackvar == NULL );
7036 
7037  nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
7038  linvars = SCIPgetVarsLinear(scip, consdata->lincons);
7039  linvals = SCIPgetValsLinear(scip, consdata->lincons);
7040  haslhs = ! SCIPisInfinity(scip, REALABS(SCIPgetLhsLinear(scip, consdata->lincons)));
7041  hasrhs = ! SCIPisInfinity(scip, REALABS(SCIPgetRhsLinear(scip, consdata->lincons)));
7042 
7043  for (j = 0; j < nlinvars; ++j)
7044  {
7045  assert( ! SCIPisZero(scip, linvals[j]) );
7046  if ( SCIPisPositive(scip, linvals[j]) )
7047  {
7048  if ( haslhs )
7049  {
7050  SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlockspos, nlocksneg) );
7051  }
7052  if ( hasrhs )
7053  {
7054  SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlocksneg, nlockspos) );
7055  }
7056  }
7057  else
7058  {
7059  if ( haslhs )
7060  {
7061  SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlocksneg, nlockspos) );
7062  }
7063  if ( hasrhs )
7064  {
7065  SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlockspos, nlocksneg) );
7066  }
7067  }
7068  }
7069  }
7070 
7071  return SCIP_OKAY;
7072 }
7073 
7074 
7075 /** constraint display method of constraint handler */
7076 static
7077 SCIP_DECL_CONSPRINT(consPrintIndicator)
7079  SCIP_CONSDATA* consdata;
7080  SCIP_VAR* binvar;
7081  int rhs;
7082 
7083  assert( scip != NULL );
7084  assert( conshdlr != NULL );
7085  assert( cons != NULL );
7086  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7087 
7088  consdata = SCIPconsGetData(cons);
7089  assert( consdata != NULL );
7090  assert( consdata->binvar != NULL );
7091 
7092  binvar = consdata->binvar;
7093  rhs = 1;
7094  if ( SCIPvarGetStatus(binvar) == SCIP_VARSTATUS_NEGATED )
7095  {
7096  rhs = 0;
7097  binvar = SCIPvarGetNegatedVar(binvar);
7098  }
7099  SCIPinfoMessage(scip, file, "<%s> = %d", SCIPvarGetName(binvar), rhs);
7100 
7101  assert( consdata->slackvar != NULL );
7102  assert( consdata->lincons != NULL );
7103  SCIPinfoMessage(scip, file, " -> <%s> = 0", SCIPvarGetName(consdata->slackvar));
7104  SCIPinfoMessage(scip, file, " (<%s>)", SCIPconsGetName(consdata->lincons));
7105 
7106  return SCIP_OKAY;
7107 }
7108 
7109 
7110 /** constraint copying method of constraint handler */
7111 static
7112 SCIP_DECL_CONSCOPY(consCopyIndicator)
7113 { /*lint --e{715}*/
7114  SCIP_CONSDATA* sourceconsdata;
7115  SCIP_CONS* targetlincons = NULL;
7116  SCIP_VAR* targetbinvar = NULL;
7117  SCIP_VAR* targetslackvar = NULL;
7118  SCIP_CONS* sourcelincons;
7119  SCIP_CONSHDLR* conshdlrlinear;
7120  const char* consname;
7121 
7122  assert( scip != NULL );
7123  assert( sourcescip != NULL );
7124  assert( sourcecons != NULL );
7125  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 );
7126 
7127  *valid = TRUE;
7128 
7129  if ( name != NULL )
7130  consname = name;
7131  else
7132  consname = SCIPconsGetName(sourcecons);
7133 
7134 #ifdef SCIP_MORE_DEBUG
7135  SCIPdebugMsg(scip, "Copying indicator constraint <%s> ...\n", consname);
7136 #endif
7137 
7138  if ( modifiable )
7139  {
7140  SCIPwarningMessage(scip, "cannot create modifiable indicator constraint when trying to copy constraint <%s>,\n", SCIPconsGetName(sourcecons));
7141  *valid = FALSE;
7142  return SCIP_OKAY;
7143  }
7144 
7145  sourceconsdata = SCIPconsGetData(sourcecons);
7146  assert( sourceconsdata != NULL );
7147 
7148  /* get linear constraint */
7149  sourcelincons = sourceconsdata->lincons;
7150 
7151  /* if the constraint has been deleted -> create empty constraint (multi-aggregation might still contain slack variable, so indicator is valid) */
7152  if ( SCIPconsIsDeleted(sourcelincons) )
7153  {
7154  SCIPdebugMsg(scip, "Linear constraint <%s> deleted! Create empty linear constraint.\n", SCIPconsGetName(sourceconsdata->lincons));
7155 
7156  SCIP_CALL( SCIPcreateConsLinear(scip, &targetlincons, "dummy", 0, NULL, NULL, 0.0, SCIPinfinity(scip),
7158  SCIP_CALL( SCIPaddCons(scip, targetlincons) );
7159  }
7160  else
7161  {
7162  /* get copied version of linear constraint */
7163  assert( sourcelincons != NULL );
7164  conshdlrlinear = SCIPfindConshdlr(sourcescip, "linear");
7165  assert( conshdlrlinear != NULL );
7166 
7167  /* if copying scip after transforming the original instance before presolving, we need to correct the linear
7168  * constraint pointer */
7169  if ( SCIPisTransformed(sourcescip) && ! SCIPconsIsTransformed(sourcelincons) )
7170  {
7171  SCIP_CONS* translincons;
7172 
7173  /* adjust the linear constraint in the original constraint (no need to release translincons) */
7174  SCIP_CALL( SCIPgetTransformedCons(sourcescip, sourcelincons, &translincons) );
7175  assert( translincons != NULL );
7176  SCIP_CALL( SCIPreleaseCons(sourcescip, &sourceconsdata->lincons) );
7177  SCIP_CALL( SCIPcaptureCons(sourcescip, translincons) );
7178  sourceconsdata->lincons = translincons;
7179  sourcelincons = translincons;
7180  }
7181 
7182  SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, sourcelincons, &targetlincons, conshdlrlinear, varmap, consmap, SCIPconsGetName(sourcelincons),
7183  SCIPconsIsInitial(sourcelincons), SCIPconsIsSeparated(sourcelincons), SCIPconsIsEnforced(sourcelincons), SCIPconsIsChecked(sourcelincons),
7184  SCIPconsIsPropagated(sourcelincons), SCIPconsIsLocal(sourcelincons), SCIPconsIsModifiable(sourcelincons), SCIPconsIsDynamic(sourcelincons),
7185  SCIPconsIsRemovable(sourcelincons), SCIPconsIsStickingAtNode(sourcelincons), global, valid) );
7186  }
7187 
7188  /* find copied variable corresponding to binvar */
7189  if ( *valid )
7190  {
7191  SCIP_VAR* sourcebinvar;
7192 
7193  sourcebinvar = sourceconsdata->binvar;
7194  assert( sourcebinvar != NULL );
7195 
7196  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcebinvar, &targetbinvar, varmap, consmap, global, valid) );
7197  }
7198 
7199  /* find copied variable corresponding to slackvar */
7200  if ( *valid )
7201  {
7202  SCIP_VAR* sourceslackvar;
7203 
7204  sourceslackvar = sourceconsdata->slackvar;
7205  assert( sourceslackvar != NULL );
7206 
7207  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourceslackvar, &targetslackvar, varmap, consmap, global, valid) );
7208  }
7209 
7210  /* create indicator constraint */
7211  if ( *valid )
7212  {
7213  assert( targetlincons != NULL );
7214  assert( targetbinvar != NULL );
7215  assert( targetslackvar != NULL );
7216 
7217  /* creates indicator constraint (and captures the linear constraint) */
7218  /* Note that the copied constraint has activeone = TRUE, since the target binary variable already was negated if needed. */
7219  SCIP_CALL( SCIPcreateConsIndicatorGenericLinCons(scip, cons, consname, targetbinvar, targetlincons, targetslackvar, TRUE,
7220  initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
7221  }
7222  else
7223  {
7224  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "could not copy linear constraint <%s>\n", SCIPconsGetName(sourcelincons));
7225  }
7226 
7227  /* release copied linear constraint */
7228  if ( targetlincons != NULL )
7229  {
7230  SCIP_CALL( SCIPreleaseCons(scip, &targetlincons) );
7231  }
7232 
7233  return SCIP_OKAY;
7234 }
7235 
7236 
7237 /** constraint parsing method of constraint handler */
7238 static
7239 SCIP_DECL_CONSPARSE(consParseIndicator)
7240 { /*lint --e{715}*/
7241  char binvarname[1024];
7242  char slackvarname[1024];
7243  char linconsname[1024];
7244  SCIP_VAR* binvar;
7245  SCIP_VAR* slackvar;
7246  SCIP_CONS* lincons;
7247  int zeroone;
7248  int nargs;
7249 
7250  *success = TRUE;
7251 
7252  /* read indicator constraint */
7253  /* coverity[secure_coding] */
7254  nargs = sscanf(str, " <%1023[^>]> = %d -> <%1023[^>]> = 0 (<%1023[^>]>)", binvarname, &zeroone, slackvarname, linconsname);
7255 
7256  /* downward compatible: accept missing linear constraint at end */
7257  if ( nargs != 3 && nargs != 4 )
7258  {
7259  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0 (<lincons>).\n%s\n", str);
7260  *success = FALSE;
7261  return SCIP_OKAY;
7262  }
7263 
7264  if ( zeroone != 0 && zeroone != 1 )
7265  {
7266  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0.\n%s\n", str);
7267  *success = FALSE;
7268  return SCIP_OKAY;
7269  }
7270 
7271  /* get binary variable */
7272  binvar = SCIPfindVar(scip, binvarname);
7273  if ( binvar == NULL )
7274  {
7275  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", binvarname);
7276  *success = FALSE;
7277  return SCIP_OKAY;
7278  }
7279  /* check whether we need the complemented variable */
7280  if ( zeroone == 0 )
7281  SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
7282 
7283  /* get slack variable */
7284  slackvar = SCIPfindVar(scip, slackvarname);
7285  if ( slackvar == NULL )
7286  {
7287  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", slackvarname);
7288  *success = FALSE;
7289  return SCIP_OKAY;
7290  }
7291 
7292  /* determine linear constraint */
7293  if ( nargs == 4 )
7294  {
7295  lincons = SCIPfindCons(scip, linconsname);
7296  if ( lincons == NULL )
7297  {
7298  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown constraint <%s>\n", linconsname);
7299  *success = FALSE;
7300  return SCIP_OKAY;
7301  }
7302  if ( strncmp(SCIPconshdlrGetName(SCIPconsGetHdlr(lincons)), "linear", 6) != 0 )
7303  {
7304  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "constraint <%s> is not linear\n", linconsname);
7305  *success = FALSE;
7306  return SCIP_OKAY;
7307  }
7308  }
7309  else
7310  {
7311  const char* posstr;
7312 
7313  /* for backward compability try to determine name of linear constraint from variables names */
7314  assert( nargs == 3 );
7315 
7316  /* find matching linear constraint */
7317  posstr = strstr(slackvarname, "indslack");
7318  if ( posstr == NULL )
7319  {
7320  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "strange slack variable name: <%s>\n", slackvarname);
7321  *success = FALSE;
7322  return SCIP_OKAY;
7323  }
7324 
7325  /* overwrite binvarname: set up name for linear constraint */
7326  (void) SCIPsnprintf(binvarname, 1023, "indlin%s", posstr+8);
7327 
7328  lincons = SCIPfindCons(scip, binvarname);
7329  if ( lincons == NULL )
7330  {
7331  /* if not found - check without indlin */
7332  (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+9);
7333  lincons = SCIPfindCons(scip, binvarname);
7334 
7335  if ( lincons == NULL )
7336  {
7337  /* if not found - check without indrhs or indlhs */
7338  (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+16);
7339  lincons = SCIPfindCons(scip, binvarname);
7340 
7341  if( lincons == NULL )
7342  {
7343  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: unknown linear constraint <indlin%s>, <%s> or <%s>.\n",
7344  name, posstr+8, posstr+9, posstr+16);
7345  *success = FALSE;
7346  return SCIP_OKAY;
7347  }
7348  }
7349  }
7350  }
7351  assert( lincons != NULL );
7352 
7353  /* check correct linear constraint */
7354  if ( ! SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, lincons)) && ! SCIPisInfinity(scip, SCIPgetRhsLinear(scip, lincons)) )
7355  {
7356  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: linear constraint is ranged or equation.\n", name);
7357  *success = FALSE;
7358  return SCIP_OKAY;
7359  }
7360 
7361  /* create indicator constraint */
7362  SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
7363  initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
7364 
7365  return SCIP_OKAY;
7366 }
7367 
7368 
7369 /** constraint enabling notification method of constraint handler */
7370 static
7371 SCIP_DECL_CONSENABLE(consEnableIndicator)
7373  SCIP_CONSHDLRDATA* conshdlrdata;
7374  SCIP_CONSDATA* consdata;
7375 
7376  assert( scip != NULL );
7377  assert( conshdlr != NULL );
7378  assert( cons != NULL );
7379  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7380 
7381 #ifdef SCIP_MORE_DEBUG
7382  SCIPdebugMsg(scip, "Enabling constraint <%s>.\n", SCIPconsGetName(cons));
7383 #endif
7384 
7385  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7386  assert( conshdlrdata != NULL );
7387 
7388  consdata = SCIPconsGetData(cons);
7389  assert( consdata != NULL );
7390 
7391  if ( conshdlrdata->altlp != NULL )
7392  {
7393  assert( conshdlrdata->sepaalternativelp );
7394 
7395  if ( consdata->colindex >= 0 )
7396  {
7397  SCIP_CALL( unfixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
7398  }
7399  }
7400 
7401  return SCIP_OKAY;
7402 }
7403 
7404 
7405 /** constraint disabling notification method of constraint handler */
7406 static
7407 SCIP_DECL_CONSDISABLE(consDisableIndicator)
7409  SCIP_CONSHDLRDATA* conshdlrdata;
7410 
7411  assert( scip != NULL );
7412  assert( conshdlr != NULL );
7413  assert( cons != NULL );
7414  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7415 
7416 #ifdef SCIP_MORE_DEBUG
7417  SCIPdebugMsg(scip, "Disabling constraint <%s>.\n", SCIPconsGetName(cons));
7418 #endif
7419 
7420  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7421  assert( conshdlrdata != NULL );
7422 
7423  if ( conshdlrdata->altlp != NULL )
7424  {
7425  SCIP_CONSDATA* consdata;
7426 
7427  consdata = SCIPconsGetData(cons);
7428  assert( consdata != NULL );
7429  assert( conshdlrdata->sepaalternativelp );
7430 
7431  if ( consdata->colindex >= 0 )
7432  {
7433  SCIP_CALL( fixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
7434  }
7435  }
7436 
7437  return SCIP_OKAY;
7438 }
7439 
7440 
7441 /** constraint method of constraint handler which returns the variables (if possible) */
7442 static
7443 SCIP_DECL_CONSGETVARS(consGetVarsIndicator)
7444 { /*lint --e{715}*/
7445  SCIP_CONSDATA* consdata;
7446  int nvars = 0;
7447 
7448  assert( scip != NULL );
7449  assert( cons != NULL );
7450  assert( vars != NULL );
7451  assert( success != NULL );
7452 
7453  if ( varssize < 0 )
7454  return SCIP_INVALIDDATA;
7455  assert( varssize >= 0 );
7456 
7457  (*success) = TRUE;
7458 
7459  /* if indicator constraint is already deleted */
7460  if ( SCIPconsIsDeleted(cons) )
7461  return SCIP_OKAY;
7462 
7463  consdata = SCIPconsGetData(cons);
7464  assert( consdata != NULL );
7465  assert( consdata->lincons != NULL );
7466 
7467  if ( consdata->binvar != NULL )
7468  {
7469  assert( varssize > 0 );
7470  vars[nvars++] = consdata->binvar;
7471  }
7472  if ( consdata->slackvar != NULL )
7473  {
7474  assert( varssize > nvars );
7475  vars[nvars++] = consdata->slackvar;
7476  }
7477 
7478  /* if linear constraint of indicator is already deleted */
7479  if ( SCIPconsIsDeleted(consdata->lincons) )
7480  return SCIP_OKAY;
7481 
7482  SCIP_CALL( SCIPgetConsVars(scip, consdata->lincons, &(vars[nvars]), varssize - nvars, success) );
7483 
7484  return SCIP_OKAY;
7485 }
7486 
7487 
7488 /** constraint method of constraint handler which returns the number of variables (if possible) */
7489 static
7490 SCIP_DECL_CONSGETNVARS(consGetNVarsIndicator)
7491 { /*lint --e{715}*/
7492  SCIP_CONSDATA* consdata;
7493  int nlinvars;
7494 
7495  assert( scip != NULL );
7496  assert( cons != NULL );
7497  assert( nvars != NULL );
7498  assert( success != NULL );
7499 
7500  *success = TRUE;
7501  *nvars = 0;
7502 
7503  /* if indicator constraint is already deleted */
7504  if ( SCIPconsIsDeleted(cons) )
7505  return SCIP_OKAY;
7506 
7507  consdata = SCIPconsGetData(cons);
7508  assert( consdata != NULL );
7509  assert( consdata->lincons != NULL );
7510 
7511  if ( consdata->binvar != NULL )
7512  ++(*nvars);
7513  if ( consdata->slackvar != NULL )
7514  ++(*nvars);
7515 
7516  /* if linear constraint of indicator is already deleted */
7517  if ( SCIPconsIsDeleted(consdata->lincons) )
7518  return SCIP_OKAY;
7519 
7520  SCIP_CALL( SCIPgetConsNVars(scip, consdata->lincons, &nlinvars, success) );
7521 
7522  if ( *success )
7523  {
7524  assert( nlinvars >= 0 );
7525  *nvars += nlinvars;
7526  }
7527 
7528  return SCIP_OKAY;
7529 }
7530 
7531 
7532 /** constraint handler method to suggest dive bound changes during the generic diving algorithm */
7533 static
7534 SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsIndicator)
7536  SCIP_CONS** indconss;
7537  int nindconss;
7538  int c;
7539  SCIP_VAR* bestvar = NULL;
7540  SCIP_Bool bestvarroundup = FALSE;
7541  SCIP_Real bestscore = SCIP_REAL_MIN;
7542 
7543  assert(scip != NULL);
7544  assert(conshdlr != NULL);
7545  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7546  assert(diveset != NULL);
7547  assert(success != NULL);
7548  assert(infeasible != NULL);
7549 
7550  *success = FALSE;
7551  *infeasible = FALSE;
7552 
7553  indconss = SCIPconshdlrGetConss(conshdlr);
7554  nindconss = SCIPconshdlrGetNConss(conshdlr);
7555 
7556  /* loop over indicator constraints and score indicator variables with already integral solution value */
7557  for (c = 0; c < nindconss; ++c)
7558  {
7559  /* check whether constraint is violated */
7560  if ( SCIPisViolatedIndicator(scip, indconss[c], sol) )
7561  {
7562  SCIP_VAR* binvar;
7563  SCIP_Real solval;
7564 
7565  binvar = SCIPgetBinaryVarIndicator(indconss[c]);
7566  solval = SCIPgetSolVal(scip, sol, binvar);
7567 
7568  /* we only treat indicator variables with integral solution values that are not yet fixed */
7569  if ( SCIPisFeasIntegral(scip, solval) && SCIPvarGetLbLocal(binvar) < SCIPvarGetUbLocal(binvar) - 0.5 )
7570  {
7571  SCIP_Real score;
7572  SCIP_Bool roundup;
7573 
7574  SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_INTEGRALITY, binvar, solval, 0.0,
7575  &score, &roundup) );
7576 
7577  /* best candidate maximizes the score */
7578  if ( score > bestscore )
7579  {
7580  bestscore = score;
7581  *success = TRUE;
7582  bestvar = binvar;
7583  bestvarroundup = roundup;
7584  }
7585  }
7586  }
7587  }
7588 
7589  assert(! *success || bestvar != NULL);
7590 
7591  if ( *success )
7592  {
7593  /* if the diving score voted for fixing the best variable to 1.0, we add this as the preferred bound change */
7594  SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_UPWARDS, 1.0, bestvarroundup) );
7595  SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_DOWNWARDS, 0.0, ! bestvarroundup) );
7596  }
7597 
7598  return SCIP_OKAY;
7599 }
7600 
7601 /** constraint handler method which returns the permutation symmetry detection graph of a constraint */
7602 static
7603 SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphIndicator)
7604 { /*lint --e{715}*/
7605  SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
7606 
7607  return SCIP_OKAY;
7608 }
7609 
7610 /** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
7611 static
7612 SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphIndicator)
7613 { /*lint --e{715}*/
7614  SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
7615 
7616  return SCIP_OKAY;
7617 }
7618 
7619 /* ---------------- Constraint specific interface methods ---------------- */
7620 
7621 /** creates the handler for indicator constraints and includes it in SCIP */
7623  SCIP* scip /**< SCIP data structure */
7624  )
7625 {
7626  SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
7627  SCIP_CONFLICTHDLR* conflicthdlr;
7628  SCIP_CONSHDLRDATA* conshdlrdata;
7629  SCIP_CONSHDLR* conshdlr;
7630 
7631  /* create constraint handler data (used in conflicthdlrdata) */
7632  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
7633 
7634  /* create event handler for bound change events */
7635  conshdlrdata->eventhdlrbound = NULL;
7636  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlrbound), EVENTHDLR_BOUND_NAME, EVENTHDLR_BOUND_DESC,
7637  eventExecIndicatorBound, NULL) );
7638  assert(conshdlrdata->eventhdlrbound != NULL);
7639 
7640  /* create event handler for bound change events on linear constraint */
7641  conshdlrdata->eventhdlrlinconsbound = NULL;
7642  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlrlinconsbound), EVENTHDLR_LINCONSBOUND_NAME, EVENTHDLR_LINCONSBOUND_DESC,
7643  eventExecIndicatorLinconsBound, NULL) );
7644  assert(conshdlrdata->eventhdlrlinconsbound != NULL);
7645 
7646  /* create event handler for restart events */
7647  conshdlrdata->eventhdlrrestart = NULL;
7648  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlrrestart), EVENTHDLR_RESTART_NAME, EVENTHDLR_RESTART_DESC,
7649  eventExecIndicatorRestart, NULL) );
7650  assert( conshdlrdata->eventhdlrrestart != NULL );
7651 
7652  conshdlrdata->heurtrysol = NULL;
7653  conshdlrdata->sepaalternativelp = DEFAULT_SEPAALTERNATIVELP;
7654  conshdlrdata->nolinconscont = DEFAULT_NOLINCONSCONT;
7655  conshdlrdata->forcerestart = DEFAULT_FORCERESTART;
7656  conshdlrdata->binvarhash = NULL;
7657  conshdlrdata->binslackvarhash = NULL;
7658 
7659  /* initialize constraint handler data */
7660  initConshdlrData(scip, conshdlrdata);
7661 
7662  /* the following three variables cannot be initialized in the above method, because initConshdlrData() is also called
7663  * in the CONSINIT callback, but these variables might be used even before the is ccallback is called, so we would
7664  * lose the data added before calling this callback */
7665  conshdlrdata->addlincons = NULL;
7666  conshdlrdata->naddlincons = 0;
7667  conshdlrdata->maxaddlincons = 0;
7668 
7669  /* include constraint handler */
7672  consEnfolpIndicator, consEnfopsIndicator, consCheckIndicator, consLockIndicator,
7673  conshdlrdata) );
7674 
7675  assert( conshdlr != NULL );
7676 
7677  /* set non-fundamental callbacks via specific setter functions */
7678  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyIndicator, consCopyIndicator) );
7679  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteIndicator) );
7680  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableIndicator) );
7681  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableIndicator) );
7682  SCIP_CALL( SCIPsetConshdlrGetDiveBdChgs(scip, conshdlr, consGetDiveBdChgsIndicator) );
7683  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitIndicator) );
7684  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolIndicator) );
7685  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeIndicator) );
7686  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsIndicator) );
7687  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsIndicator) );
7688  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitIndicator) );
7689  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreIndicator) );
7690  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolIndicator) );
7691  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpIndicator) );
7692  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseIndicator) );
7693  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolIndicator, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
7694  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintIndicator) );
7695  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropIndicator, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
7697  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropIndicator) );
7698  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpIndicator, consSepasolIndicator, CONSHDLR_SEPAFREQ,
7700  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransIndicator) );
7701  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxIndicator) );
7702  SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphIndicator) );
7703  SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphIndicator) );
7704 
7705  /* add upgrading method */
7706  if ( SCIPfindConshdlr(scip, "linear") != NULL )
7707  {
7708  /* include the linear constraint upgrade in the linear constraint handler */
7709  SCIP_CALL( SCIPincludeLinconsUpgrade(scip, linconsUpgdIndicator, LINCONSUPGD_PRIORITY, CONSHDLR_NAME) );
7710  }
7711 
7712  /* create conflict handler data */
7713  SCIP_CALL( SCIPallocBlockMemory(scip, &conflicthdlrdata) );
7714  conflicthdlrdata->conshdlrdata = conshdlrdata;
7715  conflicthdlrdata->conshdlr = conshdlr;
7716  assert( conflicthdlrdata->conshdlr != NULL );
7717 
7718  /* create conflict handler for indicator constraints */
7720  conflictExecIndicator, conflicthdlrdata) );
7721 
7722  SCIP_CALL( SCIPsetConflicthdlrFree(scip, conflicthdlr, conflictFreeIndicator) );
7723 
7724  /* add indicator constraint handler parameters */
7726  "constraints/indicator/branchindicators",
7727  "Branch on indicator constraints in enforcing?",
7728  &conshdlrdata->branchindicators, TRUE, DEFAULT_BRANCHINDICATORS, NULL, NULL) );
7729 
7731  "constraints/indicator/genlogicor",
7732  "Generate logicor constraints instead of cuts?",
7733  &conshdlrdata->genlogicor, TRUE, DEFAULT_GENLOGICOR, NULL, NULL) );
7734 
7736  "constraints/indicator/addcoupling",
7737  "Add coupling constraints or rows if big-M is small enough?",
7738  &conshdlrdata->addcoupling, TRUE, DEFAULT_ADDCOUPLING, NULL, NULL) );
7739 
7741  "constraints/indicator/maxcouplingvalue",
7742  "maximum coefficient for binary variable in coupling constraint",
7743  &conshdlrdata->maxcouplingvalue, TRUE, DEFAULT_MAXCOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
7744 
7746  "constraints/indicator/addcouplingcons",
7747  "Add initial variable upper bound constraints, if 'addcoupling' is true?",
7748  &conshdlrdata->addcouplingcons, TRUE, DEFAULT_ADDCOUPLINGCONS, NULL, NULL) );
7749 
7751  "constraints/indicator/sepacouplingcuts",
7752  "Should the coupling inequalities be separated dynamically?",
7753  &conshdlrdata->sepacouplingcuts, TRUE, DEFAULT_SEPACOUPLINGCUTS, NULL, NULL) );
7754 
7756  "constraints/indicator/sepacouplinglocal",
7757  "Allow to use local bounds in order to separate coupling inequalities?",
7758  &conshdlrdata->sepacouplinglocal, TRUE, DEFAULT_SEPACOUPLINGLOCAL, NULL, NULL) );
7759 
7761  "constraints/indicator/sepacouplingvalue",
7762  "maximum coefficient for binary variable in separated coupling constraint",
7763  &conshdlrdata->sepacouplingvalue, TRUE, DEFAULT_SEPACOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
7764 
7766  "constraints/indicator/sepaperspective",
7767  "Separate cuts based on perspective formulation?",
7768  &conshdlrdata->sepaperspective, TRUE, DEFAULT_SEPAPERSPECTIVE, NULL, NULL) );
7769 
7771  "constraints/indicator/sepapersplocal",
7772  "Allow to use local bounds in order to separate perspective cuts?",
7773  &conshdlrdata->sepapersplocal, TRUE, DEFAULT_SEPAPERSPLOCAL, NULL, NULL) );
7774 
7775  SCIP_CALL( SCIPaddIntParam(scip,
7776  "constraints/indicator/maxsepanonviolated",
7777  "maximal number of separated non violated IISs, before separation is stopped",
7778  &conshdlrdata->maxsepanonviolated, FALSE, DEFAULT_MAXSEPANONVIOLATED, 0, INT_MAX, NULL, NULL) );
7779 
7781  "constraints/indicator/updatebounds",
7782  "Update bounds of original variables for separation?",
7783  &conshdlrdata->updatebounds, TRUE, DEFAULT_UPDATEBOUNDS, NULL, NULL) );
7784 
7786  "constraints/indicator/maxconditionaltlp",
7787  "maximum estimated condition of the solution basis matrix of the alternative LP to be trustworthy (0.0 to disable check)",
7788  &conshdlrdata->maxconditionaltlp, TRUE, DEFAULT_MAXCONDITIONALTLP, 0.0, SCIP_REAL_MAX, NULL, NULL) );
7789 
7790  SCIP_CALL( SCIPaddIntParam(scip,
7791  "constraints/indicator/maxsepacuts",
7792  "maximal number of cuts separated per separation round",
7793  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
7794 
7795  SCIP_CALL( SCIPaddIntParam(scip,
7796  "constraints/indicator/maxsepacutsroot",
7797  "maximal number of cuts separated per separation round in the root node",
7798  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
7799 
7801  "constraints/indicator/removeindicators",
7802  "Remove indicator constraint if corresponding variable bound constraint has been added?",
7803  &conshdlrdata->removeindicators, TRUE, DEFAULT_REMOVEINDICATORS, NULL, NULL) );
7804 
7806  "constraints/indicator/generatebilinear",
7807  "Do not generate indicator constraint, but a bilinear constraint instead?",
7808  &conshdlrdata->generatebilinear, TRUE, DEFAULT_GENERATEBILINEAR, NULL, NULL) );
7809 
7811  "constraints/indicator/scaleslackvar",
7812  "Scale slack variable coefficient at construction time?",
7813  &conshdlrdata->scaleslackvar, TRUE, DEFAULT_SCALESLACKVAR, NULL, NULL) );
7814 
7816  "constraints/indicator/trysolutions",
7817  "Try to make solutions feasible by setting indicator variables?",
7818  &conshdlrdata->trysolutions, TRUE, DEFAULT_TRYSOLUTIONS, NULL, NULL) );
7819 
7821  "constraints/indicator/enforcecuts",
7822  "In enforcing try to generate cuts (only if sepaalternativelp is true)?",
7823  &conshdlrdata->enforcecuts, TRUE, DEFAULT_ENFORCECUTS, NULL, NULL) );
7824 
7826  "constraints/indicator/dualreductions",
7827  "Should dual reduction steps be performed?",
7828  &conshdlrdata->dualreductions, TRUE, DEFAULT_DUALREDUCTIONS, NULL, NULL) );
7829 
7831  "constraints/indicator/addopposite",
7832  "Add opposite inequality in nodes in which the binary variable has been fixed to 0?",
7833  &conshdlrdata->addopposite, TRUE, DEFAULT_ADDOPPOSITE, NULL, NULL) );
7834 
7836  "constraints/indicator/conflictsupgrade",
7837  "Try to upgrade bounddisjunction conflicts by replacing slack variables?",
7838  &conshdlrdata->conflictsupgrade, TRUE, DEFAULT_CONFLICTSUPGRADE, NULL, NULL) );
7839 
7841  "constraints/indicator/restartfrac",
7842  "fraction of binary variables that need to be fixed before restart occurs (in forcerestart)",
7843  &conshdlrdata->restartfrac, TRUE, DEFAULT_RESTARTFRAC, 0.0, 1.0, NULL, NULL) );
7844 
7846  "constraints/indicator/useotherconss",
7847  "Collect other constraints to alternative LP?",
7848  &conshdlrdata->useotherconss, TRUE, DEFAULT_USEOTHERCONSS, NULL, NULL) );
7849 
7851  "constraints/indicator/useobjectivecut",
7852  "Use objective cut with current best solution to alternative LP?",
7853  &conshdlrdata->useobjectivecut, TRUE, DEFAULT_USEOBJECTIVECUT, NULL, NULL) );
7854 
7856  "constraints/indicator/trysolfromcover",
7857  "Try to construct a feasible solution from a cover?",
7858  &conshdlrdata->trysolfromcover, TRUE, DEFAULT_TRYSOLFROMCOVER, NULL, NULL) );
7859 
7861  "constraints/indicator/upgradelinear",
7862  "Try to upgrade linear constraints to indicator constraints?",
7863  &conshdlrdata->upgradelinear, TRUE, DEFAULT_UPGRADELINEAR, NULL, NULL) );
7864 
7865  /* parameters that should not be changed after problem stage: */
7867  "constraints/indicator/sepaalternativelp",
7868  "Separate using the alternative LP?",
7869  &conshdlrdata->sepaalternativelp_, TRUE, DEFAULT_SEPAALTERNATIVELP, paramChangedIndicator, NULL) );
7870 
7872  "constraints/indicator/forcerestart",
7873  "Force restart if absolute gap is 1 or enough binary variables have been fixed?",
7874  &conshdlrdata->forcerestart_, TRUE, DEFAULT_FORCERESTART, paramChangedIndicator, NULL) );
7875 
7877  "constraints/indicator/nolinconscont",
7878  "Decompose problem (do not generate linear constraint if all variables are continuous)?",
7879  &conshdlrdata->nolinconscont_, TRUE, DEFAULT_NOLINCONSCONT, paramChangedIndicator, NULL) );
7880 
7881  return SCIP_OKAY;
7882 }
7883 
7884 /** creates and captures an indicator constraint
7885  *
7886  * @note @a binvar is checked to be binary only later. This enables a change of the type in
7887  * procedures reading an instance.
7888  *
7889  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7890  */
7892  SCIP* scip, /**< SCIP data structure */
7893  SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
7894  const char* name, /**< name of constraint */
7895  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
7896  int nvars, /**< number of variables in the inequality */
7897  SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
7898  SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
7899  SCIP_Real rhs, /**< rhs of the inequality */
7900  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
7901  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
7902  * Usually set to TRUE. */
7903  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
7904  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7905  SCIP_Bool check, /**< should the constraint be checked for feasibility?
7906  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7907  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
7908  * Usually set to TRUE. */
7909  SCIP_Bool local, /**< is constraint only valid locally?
7910  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7911  SCIP_Bool dynamic, /**< is constraint subject to aging?
7912  * Usually set to FALSE. Set to TRUE for own cuts which
7913  * are separated as constraints. */
7914  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
7915  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
7916  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
7917  * if it may be moved to a more global node?
7918  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
7919  )
7920 {
7921  return SCIPcreateConsIndicatorGeneric(scip, cons, name, binvar, nvars, vars, vals, rhs, TRUE, TRUE, initial,
7922  separate, enforce, check, propagate, local, dynamic, removable, stickingatnode);
7923 }
7924 
7925 /** creates and captures a indicator constraint in a more generic version.
7926  *
7927  * The key difference from SCIPcreateConsIndicator() is the activeone and lessthanineq Booleans.
7928  * If \f$z = o\f$, with \f$o\f$ the activeone flag, then:
7929  * if lessthanineq then \f$a^T x \leq b\f$ holds, else the passed vectors are assumed to be of the form \f$a^T x \geq b\f$.
7930  * The underlying linear constraint is always created as a less-than inequality.
7931  */
7933  SCIP* scip, /**< SCIP data structure */
7934  SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
7935  const char* name, /**< name of constraint */
7936  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
7937  int nvars, /**< number of variables in the inequality */
7938  SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
7939  SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
7940  SCIP_Real rhs, /**< rhs of the inequality */
7941  SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
7942  SCIP_Bool lessthanineq, /**< is the linear constraint a less than RHS (TRUE) or greater than RHS (FALSE)? */
7943  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
7944  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
7945  * Usually set to TRUE. */
7946  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
7947  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7948  SCIP_Bool check, /**< should the constraint be checked for feasibility?
7949  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7950  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
7951  * Usually set to TRUE. */
7952  SCIP_Bool local, /**< is constraint only valid locally?
7953  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7954  SCIP_Bool dynamic, /**< is constraint subject to aging?
7955  * Usually set to FALSE. Set to TRUE for own cuts which
7956  * are separated as constraints. */
7957  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
7958  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
7959  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
7960  * if it may be moved to a more global node?
7961  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
7962  )
7963 {
7964  SCIP_CONSHDLR* conshdlr;
7965  SCIP_CONSHDLRDATA* conshdlrdata;
7966  SCIP_CONSDATA* consdata = NULL;
7967  SCIP_CONS* lincons;
7968  SCIP_VAR* slackvar = NULL;
7969  SCIP_Bool modifiable = FALSE;
7970  SCIP_Bool linconsactive = TRUE;
7971  SCIP_VARTYPE slackvartype;
7972  SCIP_Real absvalsum = 0.0;
7973  char s[SCIP_MAXSTRLEN];
7974  SCIP_Real* valscopy;
7975  int j;
7976 
7977  if ( nvars < 0 )
7978  {
7979  SCIPerrorMessage("Indicator constraint <%s> needs nonnegative number of variables in linear constraint.\n", name);
7980  return SCIP_INVALIDDATA;
7981  }
7982 
7983  /* find the indicator constraint handler */
7984  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
7985  if ( conshdlr == NULL )
7986  {
7987  SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
7988  return SCIP_PLUGINNOTFOUND;
7989  }
7990 
7991  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7992  assert( conshdlrdata != NULL );
7993 
7994  if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
7995  {
7996  SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
7997  return SCIP_INVALIDDATA;
7998  }
7999 
8000  if ( conshdlrdata->nolinconscont && conshdlrdata->generatebilinear )
8001  {
8002  SCIPerrorMessage("constraint handler <%s>: parameters <nolinconscont> and <generatebilinear> cannot both be true.\n", CONSHDLR_NAME);
8003  return SCIP_INVALIDDATA;
8004  }
8005 
8006  valscopy = NULL;
8007  if ( lessthanineq )
8008  valscopy = vals;
8009  else
8010  {
8011  /* flip coefficients and RHS of indicator */
8012  SCIP_CALL( SCIPallocBufferArray(scip, &valscopy, nvars) );
8013  for (j = 0; j < nvars; ++j)
8014  valscopy[j] = -vals[j];
8015  rhs = -rhs;
8016  }
8017  assert( nvars == 0 || valscopy != NULL );
8018 
8019  /* check if slack variable can be made implicit integer */
8020  slackvartype = SCIP_VARTYPE_IMPLINT;
8021  for (j = 0; j < nvars; ++j)
8022  {
8023  if ( conshdlrdata->scaleslackvar )
8024  absvalsum += REALABS(valscopy[j]);
8025  if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, valscopy[j]) )
8026  {
8027  slackvartype = SCIP_VARTYPE_CONTINUOUS;
8028  if ( ! conshdlrdata->scaleslackvar )
8029  break;
8030  }
8031  }
8032 
8033  /* Check whether binary variable has been used for a different constraint; then use the same slack variable. */
8034  if ( binvar != NULL )
8035  {
8036  SCIP_VAR* binvarinternal;
8037 
8038  /* if active on 0, the binary variable is reversed */
8039  if ( activeone )
8040  binvarinternal = binvar;
8041  else
8042  {
8043  SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
8044  }
8045 
8046  /* make sure that the hashmap exists */
8047  if ( conshdlrdata->binslackvarhash == NULL )
8048  {
8049  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binslackvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
8050  }
8051 
8052  assert( conshdlrdata->binslackvarhash != NULL );
8053  if ( SCIPhashmapExists(conshdlrdata->binslackvarhash, (void*) binvarinternal) )
8054  {
8055  SCIP_Bool infeasible;
8056 
8057  slackvar = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->binslackvarhash, (void*) binvarinternal);
8058  assert( slackvar != NULL );
8059 
8060  /* make sure that the type of the slackvariable is as general as possible */
8061  if ( SCIPvarGetType(slackvar) == SCIP_VARTYPE_IMPLINT && slackvartype != SCIP_VARTYPE_IMPLINT )
8062  {
8063  SCIP_CALL( SCIPchgVarType(scip, slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
8064  assert( ! infeasible );
8065  }
8066 
8067  SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
8068  }
8069  else
8070  {
8071  /* create slack variable */
8072  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
8073  SCIP_CALL( SCIPcreateVar(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0, slackvartype, TRUE, FALSE,
8074  NULL, NULL, NULL, NULL, NULL) );
8075 
8076  SCIP_CALL( SCIPaddVar(scip, slackvar) );
8077 
8078  /* mark slack variable not to be multi-aggregated */
8079  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );
8080 
8081  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binslackvarhash, (void*) binvarinternal, (void*) slackvar) );
8082  }
8083  }
8084  else
8085  {
8086  /* create slack variable */
8087  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
8088  SCIP_CALL( SCIPcreateVar(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0, slackvartype, TRUE, FALSE,
8089  NULL, NULL, NULL, NULL, NULL) );
8090 
8091  SCIP_CALL( SCIPaddVar(scip, slackvar) );
8092 
8093  /* mark slack variable not to be multi-aggregated */
8094  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );
8095  }
8096 
8097  /* if the problem should be decomposed if only non-integer variables are present */
8098  if ( conshdlrdata->nolinconscont )
8099  {
8100  SCIP_Bool onlyCont = TRUE;
8101 
8102  assert( ! conshdlrdata->generatebilinear );
8103 
8104  /* check whether call variables are non-integer */
8105  for (j = 0; j < nvars; ++j)
8106  {
8107  SCIP_VARTYPE vartype;
8108 
8109  vartype = SCIPvarGetType(vars[j]);
8110  if ( vartype != SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_IMPLINT )
8111  {
8112  onlyCont = FALSE;
8113  break;
8114  }
8115  }
8116 
8117  if ( onlyCont )
8118  linconsactive = FALSE;
8119  }
8120 
8121  /* create linear constraint */
8122  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indlin_%s", name);
8123 
8124  /* if the linear constraint should be activated (lincons is captured) */
8125  if ( linconsactive )
8126  {
8127  /* the constraint is initial if initial is true, enforced, separated, and checked */
8128  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, s, nvars, vars, valscopy, -SCIPinfinity(scip), rhs,
8129  initial, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
8130  }
8131  else
8132  {
8133  /* create non-active linear constraint, which is neither initial, nor enforced, nor separated, nor checked */
8134  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, s, nvars, vars, valscopy, -SCIPinfinity(scip), rhs,
8136  }
8137 
8138  if ( ! lessthanineq )
8139  SCIPfreeBufferArray(scip, &valscopy);
8140 
8141  /* mark linear constraint not to be upgraded - otherwise we loose control over it */
8142  SCIPconsAddUpgradeLocks(lincons, 1);
8143  assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
8144 
8145  /* add slack variable */
8146  if ( conshdlrdata->scaleslackvar && nvars > 0 )
8147  {
8148  absvalsum = absvalsum/((SCIP_Real) nvars);
8149  if ( slackvartype == SCIP_VARTYPE_IMPLINT )
8150  absvalsum = SCIPceil(scip, absvalsum);
8151  if ( SCIPisZero(scip, absvalsum) )
8152  absvalsum = 1.0;
8153  SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, -absvalsum) );
8154  }
8155  else
8156  {
8157  SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, -1.0) );
8158  }
8159  SCIP_CALL( SCIPaddCons(scip, lincons) );
8160 
8161  /* check whether we should generate a bilinear constraint instead of an indicator constraint */
8162  if ( conshdlrdata->generatebilinear )
8163  {
8164  SCIP_Real val = 1.0;
8165  SCIP_VAR* binvarinternal;
8166 
8167  /* if active on 0, the binary variable is reversed */
8168  if ( activeone )
8169  binvarinternal = binvar;
8170  else
8171  {
8172  SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
8173  }
8174 
8175  /* create a quadratic constraint with a single bilinear term - note that cons is used */
8176  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
8177  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
8178  }
8179  else
8180  {
8181  /* create constraint data */
8182  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrrestart,
8183  binvar, activeone, lessthanineq, slackvar, lincons, linconsactive) );
8184  assert( consdata != NULL );
8185  /* do not need to capture slack variable and linear constraint here */
8186 
8187  /* create constraint */
8188  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
8189  local, modifiable, dynamic, removable, stickingatnode) );
8190 
8191  if ( SCIPisTransformed(scip) )
8192  {
8193  /* catch local bound change events on binary variable */
8194  if ( linconsactive )
8195  {
8196  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
8197  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
8198  }
8199 
8200  /* make sure that binary variable hash exists */
8201  if ( conshdlrdata->sepaalternativelp )
8202  {
8203  SCIP_VAR* binvarinternal;
8204 
8205  if ( conshdlrdata->binvarhash == NULL )
8206  {
8207  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
8208  }
8209 
8210  /* if active on 0, the binary variable is reversed */
8211  if ( activeone )
8212  binvarinternal = binvar;
8213  else
8214  {
8215  SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
8216  }
8217 
8218  /* check whether binary variable is present: note that a binary variable might appear several times, but this seldomly happens. */
8219  assert( conshdlrdata->binvarhash != NULL );
8220  if ( ! SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarinternal) )
8221  {
8222  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binvarhash, (void*) binvarinternal, (void*) (*cons)) );
8223  }
8224  }
8225  }
8226  }
8227 
8228  return SCIP_OKAY;
8229 }
8230 
8231 /** creates and captures an indicator constraint in its most basic version, i. e., all constraint flags are set to their
8232  * basic value as explained for the method SCIPcreateConsIndicator(); all flags can be set via
8233  * SCIPsetConsFLAGNAME-methods in scip.h
8234  *
8235  * @see SCIPcreateConsIndicator() for information about the basic constraint flag configuration
8236  *
8237  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8238  */
8240  SCIP* scip, /**< SCIP data structure */
8241  SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
8242  const char* name, /**< name of constraint */
8243  SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
8244  int nvars, /**< number of variables in the inequality */
8245  SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
8246  SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
8247  SCIP_Real rhs /**< rhs of the inequality */
8248  )
8249 {
8250  assert( scip != NULL );
8251 
8252  SCIP_CALL( SCIPcreateConsIndicator(scip, cons, name, binvar, nvars, vars, vals, rhs,
8253  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
8254 
8255  return SCIP_OKAY;
8256 }
8257 
8258 /** creates and captures an indicator constraint with given linear constraint and slack variable
8259  * in a generic version, i. e., with a flag activeone indicating whether the constraint is active on
8260  * value 1 or 0 of the binary variable.
8261 
8262  * @note @a binvar is checked to be binary only later. This enables a change of the type in
8263  * procedures reading an instance.
8264  *
8265  * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
8266  * the role of a slack variable!
8267  *
8268  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8269  *
8270  * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
8271  */
8273  SCIP* scip, /**< SCIP data structure */
8274  SCIP_CONS** cons, /**< pointer to hold the created constraint */
8275  const char* name, /**< name of constraint */
8276  SCIP_VAR* binvar, /**< binary indicator variable */
8277  SCIP_CONS* lincons, /**< linear constraint */
8278  SCIP_VAR* slackvar, /**< slack variable */
8279  SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
8280  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
8281  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
8282  * Usually set to TRUE. */
8283  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
8284  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8285  SCIP_Bool check, /**< should the constraint be checked for feasibility?
8286  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8287  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
8288  * Usually set to TRUE. */
8289  SCIP_Bool local, /**< is constraint only valid locally?
8290  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
8291  SCIP_Bool dynamic, /**< is constraint subject to aging?
8292  * Usually set to FALSE. Set to TRUE for own cuts which
8293  * are separated as constraints. */
8294  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
8295  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
8296  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
8297  * if it may be moved to a more global node?
8298  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
8299  )
8300 {
8301  SCIP_CONSHDLR* conshdlr;
8302  SCIP_CONSHDLRDATA* conshdlrdata;
8303  SCIP_CONSDATA* consdata = NULL;
8304  SCIP_Bool modifiable = FALSE;
8305  SCIP_Bool linconsactive = TRUE;
8306 
8307  assert( scip != NULL );
8308  assert( lincons != NULL );
8309  assert( binvar != NULL );
8310  assert( slackvar != NULL );
8311 
8312  /* check whether lincons is really a linear constraint */
8313  conshdlr = SCIPconsGetHdlr(lincons);
8314  if ( strcmp(SCIPconshdlrGetName(conshdlr), "linear") != 0 )
8315  {
8316  SCIPerrorMessage("Lincons constraint is not linear.\n");
8317  return SCIP_INVALIDDATA;
8318  }
8319 
8320  /* find the indicator constraint handler */
8321  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
8322  if ( conshdlr == NULL )
8323  {
8324  SCIPerrorMessage("<%s> constraint handler not found.\n", CONSHDLR_NAME);
8325  return SCIP_PLUGINNOTFOUND;
8326  }
8327 
8328  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8329  assert( conshdlrdata != NULL );
8330 
8331  if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
8332  {
8333  SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
8334  return SCIP_INVALIDDATA;
8335  }
8336 
8337  /* mark slack variable not to be multi-aggregated */
8338  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );
8339 
8340  /* if the problem should be decomposed (only if all variables are continuous) */
8341  if ( conshdlrdata->nolinconscont )
8342  {
8343  SCIP_Bool onlyCont = TRUE;
8344  int v;
8345  int nvars;
8346  SCIP_VAR** vars;
8347 
8348  nvars = SCIPgetNVarsLinear(scip, lincons);
8349  vars = SCIPgetVarsLinear(scip, lincons);
8350 
8351  /* check whether call variables are non-integer */
8352  for (v = 0; v < nvars; ++v)
8353  {
8354  SCIP_VARTYPE vartype;
8355 
8356  vartype = SCIPvarGetType(vars[v]);
8357  if ( vartype != SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_IMPLINT )
8358  {
8359  onlyCont = FALSE;
8360  break;
8361  }
8362  }
8363 
8364  if ( onlyCont )
8365  linconsactive = FALSE;
8366  }
8367 
8368  /* mark linear constraint not to be upgraded - otherwise we loose control over it */
8369  SCIPconsAddUpgradeLocks(lincons, 1);
8370  assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
8371 
8372  /* check whether we should generate a bilinear constraint instead of an indicator constraint */
8373  if ( conshdlrdata->generatebilinear )
8374  {
8375  SCIP_Real val = 1.0;
8376 
8377  /* if active on 0, the binary variable is reversed */
8378  SCIP_VAR* binvarinternal;
8379  if ( activeone )
8380  {
8381  binvarinternal = binvar;
8382  }
8383  else
8384  {
8385  SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
8386  }
8387 
8388  /* create a quadratic constraint with a single bilinear term - note that cons is used */
8389  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
8390  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
8391  }
8392  else
8393  {
8394  /* create constraint data */
8395  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrrestart,
8396  binvar, activeone, TRUE, slackvar, lincons, linconsactive) );
8397  assert( consdata != NULL );
8398 
8399  /* create constraint */
8400  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
8401  local, modifiable, dynamic, removable, stickingatnode) );
8402 
8403  /* catch local bound change events on binary variable */
8404  if ( consdata->linconsactive && SCIPisTransformed(scip) )
8405  {
8406  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
8407  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
8408  }
8409  }
8410 
8411  /* capture slack variable and linear constraint */
8412  SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
8413  SCIP_CALL( SCIPcaptureCons(scip, lincons) );
8414 
8415  return SCIP_OKAY;
8416 }
8417 
8418 /** creates and captures an indicator constraint with given linear constraint and slack variable
8419  *
8420  * @note @a binvar is checked to be binary only later. This enables a change of the type in
8421  * procedures reading an instance.
8422  *
8423  * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
8424  * the role of a slack variable!
8425  *
8426  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8427  */
8429  SCIP* scip, /**< SCIP data structure */
8430  SCIP_CONS** cons, /**< pointer to hold the created constraint */
8431  const char* name, /**< name of constraint */
8432  SCIP_VAR* binvar, /**< binary indicator variable */
8433  SCIP_CONS* lincons, /**< linear constraint */
8434  SCIP_VAR* slackvar, /**< slack variable */
8435  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
8436  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
8437  * Usually set to TRUE. */
8438  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
8439  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8440  SCIP_Bool check, /**< should the constraint be checked for feasibility?
8441  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8442  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
8443  * Usually set to TRUE. */
8444  SCIP_Bool local, /**< is constraint only valid locally?
8445  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
8446  SCIP_Bool dynamic, /**< is constraint subject to aging?
8447  * Usually set to FALSE. Set to TRUE for own cuts which
8448  * are separated as constraints. */
8449  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
8450  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
8451  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
8452  * if it may be moved to a more global node?
8453  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
8454  )
8455 {
8456  return SCIPcreateConsIndicatorGenericLinCons(scip, cons, name, binvar, lincons, slackvar, TRUE, initial, separate,
8457  enforce, check, propagate, local, dynamic, removable, stickingatnode);
8458 }
8459 
8460 
8461 /** creates and captures an indicator constraint with given linear constraint and slack variable
8462  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
8463  * method SCIPcreateConsIndicator(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
8464  *
8465  * @note @a binvar is checked to be binary only later. This enables a change of the type in
8466  * procedures reading an instance.
8467  *
8468  * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
8469  * the role of a slack variable!
8470  *
8471  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8472  *
8473  * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
8474  *
8475  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8476  */
8478  SCIP* scip, /**< SCIP data structure */
8479  SCIP_CONS** cons, /**< pointer to hold the created constraint */
8480  const char* name, /**< name of constraint */
8481  SCIP_VAR* binvar, /**< binary indicator variable */
8482  SCIP_CONS* lincons, /**< linear constraint */
8483  SCIP_VAR* slackvar /**< slack variable */
8484  )
8485 {
8486  assert( scip != NULL );
8487 
8488  SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
8489  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
8490 
8491  return SCIP_OKAY;
8492 }
8493 
8494 
8495 /** creates and captures an indicator constraint with given linear constraint in a generic version, i. e., with a flag
8496  * activeone indicating whether the constraint is active on value 1 or 0 of the binary variable; no slack variable is
8497  * given
8498 
8499  * @note @a binvar is checked to be binary only later. This enables a change of the type in
8500  * procedures reading an instance.
8501  *
8502  * @note The linear constraint must be single-sided, i.e., either rhs or lhs have to be infinite.
8503  *
8504  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8505  *
8506  * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
8507  */
8509  SCIP* scip, /**< SCIP data structure */
8510  SCIP_CONS** cons, /**< pointer to hold the created constraint */
8511  const char* name, /**< name of constraint */
8512  SCIP_VAR* binvar, /**< binary indicator variable */
8513  SCIP_CONS* lincons, /**< linear constraint */
8514  SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
8515  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
8516  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
8517  * Usually set to TRUE. */
8518  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
8519  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8520  SCIP_Bool check, /**< should the constraint be checked for feasibility?
8521  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8522  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
8523  * Usually set to TRUE. */
8524  SCIP_Bool local, /**< is constraint only valid locally?
8525  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
8526  SCIP_Bool dynamic, /**< is constraint subject to aging?
8527  * Usually set to FALSE. Set to TRUE for own cuts which
8528  * are separated as constraints. */
8529  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
8530  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
8531  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
8532  * if it may be moved to a more global node?
8533  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
8534  )
8535 {
8536  char s[SCIP_MAXSTRLEN];
8537  SCIP_CONSHDLR* conshdlr;
8538  SCIP_CONSHDLRDATA* conshdlrdata;
8539  SCIP_CONSDATA* consdata = NULL;
8540  SCIP_Bool modifiable = FALSE;
8541  SCIP_Bool linconsactive = TRUE;
8542  SCIP_VAR* binvarinternal;
8543  SCIP_VAR* slackvar = NULL;
8544  SCIP_VARTYPE slackvartype;
8545  SCIP_VAR** vars;
8546  SCIP_Real* vals;
8547  SCIP_Real sign;
8548  SCIP_Real lhs;
8549  SCIP_Real rhs;
8550  int nvars;
8551  int j;
8552 
8553  assert( scip != NULL );
8554  assert( lincons != NULL );
8555  assert( binvar != NULL );
8556 
8557  /* check whether lincons is really a linear constraint */
8558  conshdlr = SCIPconsGetHdlr(lincons);
8559  if ( strcmp(SCIPconshdlrGetName(conshdlr), "linear") != 0 )
8560  {
8561  SCIPerrorMessage("Lincons constraint is not linear.\n");
8562  return SCIP_INVALIDDATA;
8563  }
8564 
8565  /* find the indicator constraint handler */
8566  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
8567  if ( conshdlr == NULL )
8568  {
8569  SCIPerrorMessage("<%s> constraint handler not found.\n", CONSHDLR_NAME);
8570  return SCIP_PLUGINNOTFOUND;
8571  }
8572 
8573  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8574  assert( conshdlrdata != NULL );
8575 
8576  if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
8577  {
8578  SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
8579  return SCIP_INVALIDDATA;
8580  }
8581 
8582  lhs = SCIPgetLhsLinear(scip, lincons);
8583  rhs = SCIPgetRhsLinear(scip, lincons);
8584  if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
8585  {
8586  SCIPerrorMessage("Lincons constraint has finite lhs and rhs.\n");
8587  return SCIP_INVALIDDATA;
8588  }
8589 
8590  /* determine type of slack variable */
8591  slackvartype = SCIP_VARTYPE_IMPLINT;
8592  nvars = SCIPgetNVarsLinear(scip, lincons);
8593  vars = SCIPgetVarsLinear(scip, lincons);
8594  vals = SCIPgetValsLinear(scip, lincons);
8595  for (j = 0; j < nvars; ++j)
8596  {
8597  if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, vals[j]) )
8598  {
8599  slackvartype = SCIP_VARTYPE_CONTINUOUS;
8600  break;
8601  }
8602  }
8603 
8604  /* if active on 0, the binary variable is reversed */
8605  if ( activeone )
8606  binvarinternal = binvar;
8607  else
8608  {
8609  SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
8610  }
8611 
8612  /* Check awhether binary variable has been used for a different constraint; then use the same slack variable. */
8613  if ( conshdlrdata->binslackvarhash == NULL )
8614  {
8615  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binslackvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
8616  }
8617 
8618  assert( conshdlrdata->binslackvarhash != NULL );
8619  if ( SCIPhashmapExists(conshdlrdata->binslackvarhash, (void*) binvarinternal) )
8620  {
8621  /* determine slack variable */
8622  slackvar = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->binslackvarhash, (void*) binvarinternal);
8623  assert( slackvar != NULL );
8624 
8625  /* make sure that the type of the slackvariable is as general as possible */
8626  if ( SCIPvarGetType(slackvar) == SCIP_VARTYPE_IMPLINT && slackvartype != SCIP_VARTYPE_IMPLINT )
8627  {
8628  SCIP_Bool infeasible;
8629 
8630  SCIP_CALL( SCIPchgVarType(scip, slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
8631  assert( ! infeasible );
8632  }
8633  SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
8634  }
8635  else
8636  {
8637  /* create slack variable */
8638  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "indslack_%s", name);
8639  SCIP_CALL( SCIPcreateVar(scip, &slackvar, s, 0.0, SCIPinfinity(scip), 0.0, slackvartype, TRUE, FALSE,
8640  NULL, NULL, NULL, NULL, NULL) );
8641 
8642  SCIP_CALL( SCIPaddVar(scip, slackvar) );
8643 
8644  /* mark slack variable not to be multi-aggregated */
8645  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );
8646 
8647  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binslackvarhash, (void*) binvarinternal, (void*) slackvar) );
8648  }
8649  assert( slackvar != NULL );
8650 
8651  /* if the problem should be decomposed (only if all variables are continuous) */
8652  if ( conshdlrdata->nolinconscont )
8653  {
8654  SCIP_Bool onlyCont = TRUE;
8655 
8656  nvars = SCIPgetNVarsLinear(scip, lincons);
8657  vars = SCIPgetVarsLinear(scip, lincons);
8658 
8659  /* check whether call variables are non-integer */
8660  for (j = 0; j < nvars; ++j)
8661  {
8662  SCIP_VARTYPE vartype;
8663 
8664  vartype = SCIPvarGetType(vars[j]);
8665  if ( vartype != SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_IMPLINT )
8666  {
8667  onlyCont = FALSE;
8668  break;
8669  }
8670  }
8671 
8672  if ( onlyCont )
8673  linconsactive = FALSE;
8674  }
8675 
8676  /* determine sign of slack variable */
8677  sign = -1.0;
8678  if ( SCIPisInfinity(scip, rhs) )
8679  sign = 1.0;
8680 
8681  /* add slack variable */
8682  SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, sign) );
8683 
8684  /* mark linear constraint not to be upgraded - otherwise we loose control over it */
8685  SCIPconsAddUpgradeLocks(lincons, 1);
8686  assert( SCIPconsGetNUpgradeLocks(lincons) > 0 );
8687 
8688  /* check whether we should generate a bilinear constraint instead of an indicator constraint */
8689  if ( conshdlrdata->generatebilinear )
8690  {
8691  SCIP_Real val = 1.0;
8692 
8693  /* create a quadratic constraint with a single bilinear term - note that cons is used */
8694  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
8695  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
8696  }
8697  else
8698  {
8699  /* create constraint data */
8700  SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrrestart,
8701  binvar, activeone, TRUE, slackvar, lincons, linconsactive) );
8702  assert( consdata != NULL );
8703 
8704  /* create constraint */
8705  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
8706  local, modifiable, dynamic, removable, stickingatnode) );
8707 
8708  /* catch local bound change events on binary variable */
8709  if ( consdata->linconsactive && SCIPisTransformed(scip) )
8710  {
8711  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
8712  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
8713  }
8714  }
8715 
8716  /* capture slack variable and linear constraint */
8717  SCIP_CALL( SCIPcaptureCons(scip, lincons) );
8718 
8719  return SCIP_OKAY;
8720 }
8721 
8722 
8723 /** creates and captures an indicator constraint with given linear constraint; no slack variable is specified
8724  *
8725  * @note @a binvar is checked to be binary only later. This enables a change of the type in
8726  * procedures reading an instance.
8727  *
8728  * @note The linear constraint has to be single sided only, i.e., either rhs or lhs have to be infinite.
8729  *
8730  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8731  */
8733  SCIP* scip, /**< SCIP data structure */
8734  SCIP_CONS** cons, /**< pointer to hold the created constraint */
8735  const char* name, /**< name of constraint */
8736  SCIP_VAR* binvar, /**< binary indicator variable */
8737  SCIP_CONS* lincons, /**< linear constraint */
8738  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
8739  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
8740  * Usually set to TRUE. */
8741  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
8742  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8743  SCIP_Bool check, /**< should the constraint be checked for feasibility?
8744  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8745  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
8746  * Usually set to TRUE. */
8747  SCIP_Bool local, /**< is constraint only valid locally?
8748  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
8749  SCIP_Bool dynamic, /**< is constraint subject to aging?
8750  * Usually set to FALSE. Set to TRUE for own cuts which
8751  * are separated as constraints. */
8752  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
8753  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
8754  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
8755  * if it may be moved to a more global node?
8756  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
8757  )
8758 {
8759  return SCIPcreateConsIndicatorGenericLinConsPure(scip, cons, name, binvar, lincons, TRUE, initial, separate,
8760  enforce, check, propagate, local, dynamic, removable, stickingatnode);
8761 }
8762 
8763 
8764 /** adds variable to the inequality of the indicator constraint */
8766  SCIP* scip, /**< SCIP data structure */
8767  SCIP_CONS* cons, /**< indicator constraint */
8768  SCIP_VAR* var, /**< variable to add to the inequality */
8769  SCIP_Real val /**< value of variable */
8770  )
8771 {
8772  SCIP_CONSDATA* consdata;
8773 
8774  assert( cons != NULL );
8775  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8776 
8777  consdata = SCIPconsGetData(cons);
8778  assert( consdata != NULL );
8779 
8780  /* if linear inequality is flipped, variable is added with negative coefficient */
8781  if ( !consdata->lessthanineq )
8782  val = -val;
8783 
8784  SCIP_CALL( SCIPaddCoefLinear(scip, consdata->lincons, var, val) );
8785 
8786  /* possibly adapt variable type */
8787  if ( SCIPvarGetType(consdata->slackvar) != SCIP_VARTYPE_CONTINUOUS && (! SCIPvarIsIntegral(var) || ! SCIPisIntegral(scip, val) ) )
8788  {
8789  SCIP_Bool infeasible;
8790 
8791  SCIP_CALL( SCIPchgVarType(scip, consdata->slackvar, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
8792  assert( ! infeasible );
8793  }
8794 
8795  return SCIP_OKAY;
8796 }
8797 
8798 
8799 /** gets the linear constraint corresponding to the indicator constraint (may be NULL) */
8801  SCIP_CONS* cons /**< indicator constraint */
8802  )
8803 {
8804  SCIP_CONSDATA* consdata;
8805 
8806  assert( cons != NULL );
8807  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8808 
8809  consdata = SCIPconsGetData(cons);
8810  assert( consdata != NULL );
8811 
8812  return consdata->lincons;
8813 }
8814 
8815 
8816 /** sets the linear constraint corresponding to the indicator constraint (may be NULL) */
8818  SCIP* scip, /**< SCIP data structure */
8819  SCIP_CONS* cons, /**< indicator constraint */
8820  SCIP_CONS* lincons /**< linear constraint */
8821  )
8822 {
8823  SCIP_CONSHDLR* conshdlr;
8824  SCIP_CONSHDLRDATA* conshdlrdata;
8825  SCIP_CONSDATA* consdata;
8826 
8827  if ( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
8828  {
8829  SCIPerrorMessage("Cannot set linear constraint in SCIP stage <%d>\n", SCIPgetStage(scip) );
8830  return SCIP_INVALIDCALL;
8831  }
8832 
8833  assert( cons != NULL );
8834  conshdlr = SCIPconsGetHdlr(cons);
8835 
8836  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8837  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8838  assert( conshdlrdata != NULL );
8839 
8840  consdata = SCIPconsGetData(cons);
8841  assert( consdata != NULL );
8842 
8843  /* free old linear constraint */
8844  assert( consdata->lincons != NULL );
8845  SCIP_CALL( SCIPdelCons(scip, consdata->lincons) );
8846  SCIP_CALL( SCIPreleaseCons(scip, &(consdata->lincons) ) );
8847 
8848  assert( lincons != NULL );
8849  consdata->lincons = lincons;
8850  consdata->linconsactive = TRUE;
8851  SCIP_CALL( SCIPcaptureCons(scip, lincons) );
8852 
8853  /* if the problem should be decomposed if only non-integer variables are present */
8854  if ( conshdlrdata->nolinconscont )
8855  {
8856  SCIP_Bool onlyCont;
8857  int v;
8858  int nvars;
8859  SCIP_VAR** vars;
8860 
8861  onlyCont = TRUE;
8862  nvars = SCIPgetNVarsLinear(scip, lincons);
8863  vars = SCIPgetVarsLinear(scip, lincons);
8864  assert( vars != NULL );
8865 
8866  /* check whether call variables are non-integer */
8867  for (v = 0; v < nvars; ++v)
8868  {
8869  SCIP_VARTYPE vartype;
8870 
8871  vartype = SCIPvarGetType(vars[v]);
8872  if ( vartype != SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_IMPLINT )
8873  {
8874  onlyCont = FALSE;
8875  break;
8876  }
8877  }
8878 
8879  if ( onlyCont )
8880  consdata->linconsactive = FALSE;
8881  }
8882 
8883  return SCIP_OKAY;
8884 }
8885 
8886 /** gets activation value of an indicator constraint, TRUE for active on 1, FALSE for active on 0 */
8888  SCIP_CONS* cons /**< indicator constraint */
8889  )
8890 {
8891  SCIP_CONSDATA* consdata;
8892 
8893  assert( cons != NULL );
8894  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8895 
8896  consdata = SCIPconsGetData(cons);
8897  assert( consdata != NULL );
8898 
8899  return consdata->activeone;
8900 }
8901 
8902 
8903 /** gets binary variable corresponding to indicator constraint */
8905  SCIP_CONS* cons /**< indicator constraint */
8906  )
8907 {
8908  SCIP_CONSDATA* consdata;
8909 
8910  assert( cons != NULL );
8911  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8912 
8913  consdata = SCIPconsGetData(cons);
8914  assert( consdata != NULL );
8915 
8916  return consdata->binvar;
8917 }
8918 
8919 /** similar to SCIPgetBinaryVarIndicator but returns the original binary variable passed by the user. */
8921  SCIP_CONS* cons /**< indicator constraint */
8922  )
8923 {
8924  SCIP_CONSDATA* consdata;
8925  SCIP_VAR* binvar;
8926 
8927  assert(cons != NULL);
8928  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
8929 
8930  consdata = SCIPconsGetData(cons);
8931  assert(consdata != NULL);
8932  binvar = consdata->binvar;
8933 
8934  if ( ! consdata->activeone )
8935  binvar = SCIPvarGetNegationVar(binvar);
8936  assert(binvar != NULL);
8937 
8938  return binvar;
8939 }
8940 
8941 /** sets binary indicator variable for indicator constraint */
8943  SCIP* scip, /**< SCIP data structure */
8944  SCIP_CONS* cons, /**< indicator constraint */
8945  SCIP_VAR* binvar /**< binary variable to add to the inequality */
8946  )
8947 {
8948  SCIP_CONSDATA* consdata;
8949 
8950  assert( cons != NULL );
8951  assert( binvar != NULL );
8952  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
8953 
8954  consdata = SCIPconsGetData(cons);
8955  assert( consdata != NULL );
8956 
8957  /* check type */
8958  if ( SCIPvarGetType(binvar) != SCIP_VARTYPE_BINARY )
8959  {
8960  SCIPerrorMessage("Indicator variable <%s> is not binary %d.\n", SCIPvarGetName(binvar), SCIPvarGetType(binvar));
8961  return SCIP_ERROR;
8962  }
8963 
8964  /* check previous binary variable */
8965  if ( consdata->binvar != NULL )
8966  {
8967  /* to allow replacement of binary variables, we would need to drop events etc. */
8968  SCIPerrorMessage("Cannot replace binary variable <%s> for indicator constraint <%s>.\n", SCIPvarGetName(binvar), SCIPconsGetName(cons));
8969  return SCIP_INVALIDCALL;
8970  }
8971 
8972  /* if we are transformed, obtain transformed variables and catch events */
8973  if ( SCIPconsIsTransformed(cons) )
8974  {
8975  SCIP_VAR* var;
8976  SCIP_CONSHDLR* conshdlr;
8977  SCIP_CONSHDLRDATA* conshdlrdata;
8978 
8979  /* make sure we have a transformed binary variable */
8980  /* coverity[copy_paste_error] */
8981  SCIP_CALL( SCIPgetTransformedVar(scip, binvar, &var) );
8982  assert( var != NULL );
8983  if ( ! consdata->activeone )
8984  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
8985 
8986  consdata->binvar = var;
8987 
8988  conshdlr = SCIPconsGetHdlr(cons);
8989  assert( conshdlr != NULL );
8990  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8991  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8992  assert( conshdlrdata != NULL );
8993  assert( conshdlrdata->eventhdlrbound != NULL );
8994  assert( conshdlrdata->eventhdlrrestart != NULL );
8995 
8996  /* catch local bound change events on binary variable */
8997  if ( consdata->linconsactive )
8998  {
8999  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, NULL) );
9000  }
9001 
9002  /* catch global bound change events on binary variable */
9003  if ( conshdlrdata->forcerestart )
9004  {
9005  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
9006  }
9007 
9008  /* if binary variable is fixed to be nonzero */
9009  if ( SCIPvarGetLbLocal(var) > 0.5 )
9010  ++(consdata->nfixednonzero);
9011  }
9012  else
9013  {
9014  if ( ! consdata->activeone )
9015  SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
9016  consdata->binvar = binvar;
9017  }
9018 
9019  return SCIP_OKAY;
9020 }
9021 
9022 /** gets slack variable corresponding to indicator constraint */
9024  SCIP_CONS* cons /**< indicator constraint */
9025  )
9026 {
9027  SCIP_CONSDATA* consdata;
9028 
9029  assert( cons != NULL );
9030  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
9031 
9032  consdata = SCIPconsGetData(cons);
9033  assert( consdata != NULL );
9034 
9035  return consdata->slackvar;
9036 }
9037 
9038 
9039 /** sets upper bound for slack variable corresponding to indicator constraint
9040  *
9041  * Use with care if you know that the maximal violation of the corresponding constraint is at most @p ub. This bound
9042  * might be improved automatically during the solution process.
9043  *
9044  * @pre This method should only be called if SCIP is in one of the following stages:
9045  * - \ref SCIP_STAGE_INIT
9046  * - \ref SCIP_STAGE_PROBLEM
9047  */
9049  SCIP* scip, /**< SCIP data structure */
9050  SCIP_CONS* cons, /**< indicator constraint */
9051  SCIP_Real ub /**< upper bound for slack variable */
9052  )
9053 {
9054  SCIP_CONSDATA* consdata;
9055 
9056  assert( scip != NULL );
9057  assert( cons != NULL );
9058  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
9059 
9060  consdata = SCIPconsGetData(cons);
9061  assert( consdata != NULL );
9062 
9063  if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM )
9064  return SCIP_OKAY;
9065 
9066  assert( consdata->slackvar != NULL );
9067  SCIP_CALL( SCIPchgVarUb(scip, consdata->slackvar, ub) );
9068 
9069  return SCIP_OKAY;
9070 }
9071 
9072 
9073 /** checks whether indicator constraint is violated w.r.t. sol */
9075  SCIP* scip, /**< SCIP data structure */
9076  SCIP_CONS* cons, /**< indicator constraint */
9077  SCIP_SOL* sol /**< solution, or NULL to use current node's solution */
9078  )
9079 {
9080  SCIP_CONSDATA* consdata;
9081 
9082  assert( cons != NULL );
9083 
9084  /* deleted constraints should always be satisfied */
9085  if ( SCIPconsIsDeleted(cons) )
9086  return FALSE;
9087 
9088  consdata = SCIPconsGetData(cons);
9089  assert( consdata != NULL );
9090 
9091  if ( consdata->linconsactive )
9092  {
9093  assert( consdata->slackvar != NULL );
9094  assert( consdata->binvar != NULL );
9095  return(
9096  SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) &&
9097  SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
9098  }
9099 
9100  /* @todo: check how this can be decided for linconsactive == FALSE */
9101  return TRUE;
9102 }
9103 
9104 
9105 /** based on values of other variables, computes slack and binary variable to turn constraint feasible
9106  *
9107  * It will also clean up the solution, i.e., shift slack variable, as follows:
9108  *
9109  * If the inequality is \f$a^T x + \gamma\, s \leq \beta\f$, the value of the slack variable
9110  * \f$s\f$ to achieve equality is
9111  * \f[
9112  * s^* = \frac{\beta - a^T x^*}{\gamma},
9113  * \f]
9114  * where \f$x^*\f$ is the given solution. In case of \f$a^T x + \gamma\, s \geq \alpha\f$, we
9115  * arrive at
9116  * \f[
9117  * s^* = \frac{\alpha - a^T x^*}{\gamma}.
9118  * \f]
9119  * The typical values of \f$\gamma\f$ in the first case is -1 and +1 in the second case.
9120  *
9121  * Now, let \f$\sigma\f$ be the sign of \f$\gamma\f$ in the first case and \f$-\gamma\f$ in the
9122  * second case. Thus, if \f$\sigma > 0\f$ and \f$s^* < 0\f$, the inequality cannot be satisfied by
9123  * a nonnegative value for the slack variable; in this case, we have to leave the values as they
9124  * are. If \f$\sigma < 0\f$ and \f$s^* > 0\f$, the solution violates the indicator constraint (we
9125  * can set the slack variable to value \f$s^*\f$). If \f$\sigma < 0\f$ and \f$s^* \leq 0\f$ or
9126  * \f$\sigma > 0\f$ and \f$s^* \geq 0\f$, the constraint is satisfied, and we can set the slack
9127  * variable to 0.
9128  */
9130  SCIP* scip, /**< SCIP data structure */
9131  SCIP_CONS* cons, /**< indicator constraint */
9132  SCIP_SOL* sol, /**< solution */
9133  SCIP_Bool* changed /**< pointer to store whether the solution has been changed */
9134  )
9135 {
9136  SCIP_CONSDATA* consdata;
9137  SCIP_CONS* lincons;
9138  SCIP_VAR** linvars;
9139  SCIP_Real* linvals;
9140  SCIP_VAR* slackvar;
9141  SCIP_VAR* binvar;
9142  SCIP_Real slackcoef;
9143  SCIP_Real sum;
9144  SCIP_Real val;
9145  int nlinvars;
9146  int sigma;
9147  int v;
9148 
9149  assert( cons != NULL );
9150  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
9151  assert( sol != NULL );
9152  assert( changed != NULL );
9153 
9154  *changed = FALSE;
9155 
9156  /* avoid deleted indicator constraints, e.g., due to preprocessing */
9157  if ( ! SCIPconsIsActive(cons) && SCIPgetStage(scip) >= SCIP_STAGE_INITPRESOLVE )
9158  return SCIP_OKAY;
9159 
9160  assert( cons != NULL );
9161  consdata = SCIPconsGetData(cons);
9162  assert( consdata != NULL );
9163 
9164  /* if the linear constraint is not present, we cannot do anything */
9165  if ( ! consdata->linconsactive )
9166  return SCIP_OKAY;
9167 
9168  lincons = consdata->lincons;
9169  assert( lincons != NULL );
9170 
9171  /* avoid non-active linear constraints, e.g., due to preprocessing */
9172  if ( SCIPconsIsActive(lincons) || SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE )
9173  {
9174  slackvar = consdata->slackvar;
9175  binvar = consdata->binvar;
9176  assert( slackvar != NULL );
9177  assert( binvar != NULL );
9178 
9179  nlinvars = SCIPgetNVarsLinear(scip, lincons);
9180  linvars = SCIPgetVarsLinear(scip, lincons);
9181  linvals = SCIPgetValsLinear(scip, lincons);
9182 
9183  /* compute value of regular variables */
9184  sum = 0.0;
9185  slackcoef = 0.0;
9186  for (v = 0; v < nlinvars; ++v)
9187  {
9188  SCIP_VAR* var;
9189  var = linvars[v];
9190  if ( var != slackvar )
9191  sum += linvals[v] * SCIPgetSolVal(scip, sol, var);
9192  else
9193  slackcoef = linvals[v];
9194  }
9195 
9196  /* do nothing if slack variable does not appear */
9197  if ( SCIPisFeasZero(scip, slackcoef) )
9198  return SCIP_OKAY;
9199 
9200  assert( ! SCIPisZero(scip, slackcoef) );
9201  assert( slackcoef != 0.0 ); /* to satisfy lint */
9202  assert( SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, lincons)) || SCIPisInfinity(scip, SCIPgetRhsLinear(scip, lincons)) );
9203  assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(slackvar), 0.0) );
9204 
9205  val = SCIPgetRhsLinear(scip, lincons);
9206  sigma = 1;
9207  if ( SCIPisInfinity(scip, val) )
9208  {
9209  val = SCIPgetLhsLinear(scip, lincons);
9210  assert( ! SCIPisInfinity(scip, REALABS(val)) );
9211  sigma = -1;
9212  }
9213  /* compute value of slack that would achieve equality */
9214  val = (val - sum)/slackcoef;
9215 
9216  /* compute direction into which slack variable would be infeasible */
9217  if ( slackcoef < 0 )
9218  sigma *= -1;
9219 
9220  /* filter out cases in which no sensible change is possible */
9221  if ( sigma > 0 && SCIPisFeasNegative(scip, val) )
9222  return SCIP_OKAY;
9223 
9224  /* check if linear constraint w/o slack variable is violated */
9225  if ( sigma < 0 && SCIPisFeasPositive(scip, val) )
9226  {
9227  /* the original constraint is violated */
9228  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, slackvar), val) )
9229  {
9230  SCIP_CALL( SCIPsetSolVal(scip, sol, slackvar, val) );
9231  *changed = TRUE;
9232  }
9233  /* check whether binary variable is fixed or its negated variable is fixed */
9234  if ( SCIPvarGetStatus(binvar) != SCIP_VARSTATUS_FIXED &&
9236  {
9237  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 0.0) )
9238  {
9239  SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 0.0) );
9240  *changed = TRUE;
9241  }
9242  }
9243  }
9244  else
9245  {
9246  assert( SCIPisFeasGE(scip, val * ((SCIP_Real) sigma), 0.0) );
9247 
9248  /* the original constraint is satisfied - we can set the slack variable to 0 (slackvar
9249  * should only occur in this indicator constraint) */
9250  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, slackvar), 0.0) && SCIPisFeasPositive(scip, SCIPvarGetLbLocal(slackvar)) )
9251  {
9252  SCIP_CALL( SCIPsetSolVal(scip, sol, slackvar, 0.0) );
9253  *changed = TRUE;
9254  }
9255 
9256  /* check whether binary variable is fixed or its negated variable is fixed */
9257  if ( SCIPvarGetStatus(binvar) != SCIP_VARSTATUS_FIXED &&
9259  {
9260  SCIP_Real obj;
9261  obj = varGetObjDelta(binvar);
9262 
9263  /* check objective for possibly setting binary variable */
9264  if ( obj <= 0 )
9265  {
9266  /* setting variable to 1 does not increase objective - check whether we can set it to 1 */
9267  if ( ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 1.0) )
9268  {
9269  /* check whether variable only occurs in the current constraint */
9270  if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
9271  {
9272  SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 1.0) );
9273  *changed = TRUE;
9274  /* make sure that the other case does not occur if obj = 0: prefer variables set to 1 */
9275  obj = -1.0;
9276  }
9277  }
9278  else
9279  {
9280  /* make sure that the other case does not occur if obj = 0: prefer variables set to 1 */
9281  obj = -1.0;
9282  }
9283  }
9284  if ( obj >= 0 )
9285  {
9286  /* setting variable to 0 does not increase objective -> check whether variable only occurs in the current constraint
9287  * note: binary variables are only locked up */
9289  && ! SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, binvar), 0.0) )
9290  {
9291  SCIP_CALL( SCIPsetSolVal(scip, sol, binvar, 0.0) );
9292  *changed = TRUE;
9293  }
9294  }
9295  }
9296  }
9297  }
9298 
9299  return SCIP_OKAY;
9300 }
9301 
9302 
9303 /** based on values of other variables, computes slack and binary variable to turn all constraints feasible */
9305  SCIP* scip, /**< SCIP data structure */
9306  SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
9307  SCIP_SOL* sol, /**< solution */
9308  SCIP_Bool* changed /**< pointer to store whether the solution has been changed */
9309  )
9310 {
9311  SCIP_CONS** conss;
9312  int nconss;
9313  int c;
9314 
9315  assert( conshdlr != NULL );
9316  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9317  assert( sol != NULL );
9318  assert( changed != NULL );
9319 
9320  *changed = FALSE;
9321 
9322  /* only run after or in presolving */
9323  if ( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE )
9324  return SCIP_OKAY;
9325 
9326  conss = SCIPconshdlrGetConss(conshdlr);
9327  nconss = SCIPconshdlrGetNConss(conshdlr);
9328 
9329  for (c = 0; c < nconss; ++c)
9330  {
9331  SCIP_CONSDATA* consdata;
9332  SCIP_Bool chg = FALSE;
9333  assert( conss[c] != NULL );
9334 
9335  consdata = SCIPconsGetData(conss[c]);
9336  assert( consdata != NULL );
9337 
9338  /* if the linear constraint is not present, we stop */
9339  if ( ! consdata->linconsactive )
9340  break;
9341 
9342  SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], sol, &chg) );
9343  *changed = *changed || chg;
9344  }
9345 
9346  return SCIP_OKAY;
9347 }
9348 
9349 
9350 /** adds additional linear constraint that is not connected with an indicator constraint, but can be used for separation */
9352  SCIP* scip, /**< SCIP data structure */
9353  SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
9354  SCIP_CONS* lincons /**< linear constraint */
9355  )
9356 {
9357  assert( scip != NULL );
9358  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9359  assert( lincons != NULL );
9360 
9361  /* do not add locally valid constraints (this would require much more bookkeeping) */
9362  if ( ! SCIPconsIsLocal(lincons) && ! SCIPconsIsModifiable(lincons) )
9363  {
9364  SCIP_CONSHDLRDATA* conshdlrdata;
9365 
9366  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9367  assert( conshdlrdata != NULL );
9368 
9369  SCIP_CALL( consdataEnsureAddLinConsSize(scip, conshdlr, conshdlrdata->naddlincons+1) );
9370  assert( conshdlrdata->naddlincons+1 <= conshdlrdata->maxaddlincons );
9371 
9372  conshdlrdata->addlincons[conshdlrdata->naddlincons++] = lincons;
9373  }
9374 
9375  return SCIP_OKAY;
9376 }
9377 
9378 
9379 /** adds additional row that is not connected with an indicator constraint, but can be used for separation
9380  *
9381  * @note The row is directly added to the alternative polyhedron and is not stored.
9382  */
9384  SCIP* scip, /**< SCIP data structure */
9385  SCIP_CONSHDLR* conshdlr, /**< indicator constraint handler */
9386  SCIP_ROW* row /**< row to add */
9387  )
9388 {
9389  assert( scip != NULL );
9390  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9391  assert( row != NULL );
9392 
9393  /* skip local cuts (local cuts would require to dynamically add and remove columns from the alternative polyhedron */
9394  if ( ! SCIProwIsLocal(row) )
9395  {
9396  int colindex;
9397  SCIP_CONSHDLRDATA* conshdlrdata;
9398 
9399  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9400  assert( conshdlrdata != NULL );
9401 
9402  /* do not add rows if we do not separate */
9403  if ( ! conshdlrdata->sepaalternativelp )
9404  return SCIP_OKAY;
9405 
9406  SCIPdebugMsg(scip, "Adding row <%s> to alternative LP.\n", SCIProwGetName(row));
9407 
9408  /* add row directly to alternative polyhedron */
9409  SCIP_CALL( addAltLPRow(scip, conshdlr, row, 0.0, &colindex) );
9410  }
9411 
9412  return SCIP_OKAY;
9413 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
static SCIP_RETCODE checkLPBoundsClean(SCIP *scip, SCIP_LPI *lp, int nconss, SCIP_CONS **conss)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define EVENTHDLR_BOUND_DESC
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2082
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1785
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1422
SCIP_Bool SCIPisViolatedIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
Definition: lpi_clp.cpp:1417
SCIP_RETCODE SCIPgetCharParam(SCIP *scip, const char *name, char *value)
Definition: scip_param.c:326
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:146
#define DEFAULT_UPGRADELINEAR
#define NULL
Definition: def.h:267
static SCIP_DECL_CONSRESPROP(consRespropIndicator)
SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
Definition: lpi_clp.cpp:643
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8313
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
primal heuristic that tries a given solution
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:110
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
static SCIP_DECL_CONSINITLP(consInitlpIndicator)
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2130
#define DEFAULT_SEPACOUPLINGCUTS
#define CONFLICTHDLR_DESC
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for SCIP parameter handling
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3296
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
SCIP_Bool SCIPlpiIsInfinity(SCIP_LPI *lpi, SCIP_Real val)
Definition: lpi_clp.cpp:3931
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8475
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:601
SCIP_RETCODE SCIPcreateConsIndicatorLinConsPure(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, SCIP_CONS *lincons, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Constraint handler for variable bound constraints .
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3357
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1994
#define EVENTHDLR_LINCONSBOUND_NAME
static SCIP_DECL_CONSINIT(consInitIndicator)
public methods for memory management
static SCIP_RETCODE consdataEnsureAddLinConsSize(SCIP *scip, SCIP_CONSHDLR *conshdlr, int num)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:354
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:941
SCIP_RETCODE SCIPheurPassIndicator(SCIP *scip, SCIP_HEUR *heur, int nindconss, SCIP_CONS **indconss, SCIP_Bool *solcand, SCIP_Real obj)
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1658
SCIP_Real SCIPgetPrimalbound(SCIP *scip)
#define DEFAULT_TRYSOLUTIONS
SCIP_VAR * SCIPbdchginfoGetVar(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18681
SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
Definition: lpi_clp.cpp:2788
#define OBJEPSILON
static SCIP_DECL_CONSINITPRE(consInitpreIndicator)
#define DEFAULT_SEPAPERSPLOCAL
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18079
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:831
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:12311
SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
Definition: lpi_clp.cpp:3692
#define SCIP_MAXSTRLEN
Definition: def.h:288
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3354
public methods for conflict handler plugins and conflict analysis
#define CONSHDLR_CHECKPRIORITY
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1805
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:323
SCIP_RETCODE SCIPaddVarIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1813
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2843
static SCIP_RETCODE addAltLPRow(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_ROW *row, SCIP_Real objcoef, int *colindex)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
static long bound
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1701
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:17213
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
int SCIPgetNOrigVars(SCIP *scip)
Definition: scip_prob.c:2432
SCIP_RETCODE SCIPcreateConsIndicatorGeneric(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real rhs, SCIP_Bool activeone, SCIP_Bool lessthanineq, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18135
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
static SCIP_DECL_EVENTEXEC(eventExecIndicatorBound)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public solving methods
SCIP_RETCODE SCIPchgVarLbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4848
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:104
SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
Definition: lpi_clp.cpp:1167
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17351
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1441
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1250
interface methods for specific LP solvers
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17600
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:492
constraint handler for indicator constraints
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
#define CONSHDLR_DESC
static SCIP_RETCODE separateIISRounding(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_ENFOSEPATYPE enfosepatype, int nconss, SCIP_CONS **conss, int maxsepacuts, SCIP_Bool *cutoff, int *nGen)
SCIP_RETCODE SCIPsetSlackVarUb(SCIP *scip, SCIP_CONS *cons, SCIP_Real ub)
#define DEFAULT_MAXCONDITIONALTLP
static SCIP_RETCODE unfixAltLPVariable(SCIP_LPI *lp, int ind)
int SCIPgetSymgraphVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define CONSHDLR_PRESOLTIMING
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1866
static SCIP_RETCODE propIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_Bool dualreductions, SCIP_Bool addopposite, SCIP_Bool *cutoff, int *nGen)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4595
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17292
#define FALSE
Definition: def.h:94
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3074
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:324
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11184
static SCIP_RETCODE addObjcut(SCIP *scip, SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:181
#define MAXROUNDINGROUNDS
static SCIP_DECL_CONFLICTEXEC(conflictExecIndicator)
#define EVENTHDLR_RESTART_DESC
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10877
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:93
#define SCIPdebug(x)
Definition: pub_message.h:93
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8495
SCIP_enfosepatype
static SCIP_RETCODE checkAltLPInfeasible(SCIP *scip, SCIP_LPI *lp, SCIP_Real maxcondition, SCIP_Bool primal, SCIP_Bool *infeasible, SCIP_Bool *error)
SCIP_RETCODE SCIPsetLinearConsIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_CONS *lincons)
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3192
static SCIP_RETCODE updateFirstRow(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
SCIP_BRANCHRULE * SCIPfindBranchrule(SCIP *scip, const char *name)
Definition: scip_branch.c:297
SCIP_RETCODE SCIPmakeIndicatorFeasible(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *changed)
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17769
#define CONSHDLR_NEEDSCONS
const char * SCIPparamGetName(SCIP_PARAM *param)
Definition: paramset.c:659
#define SCIP_EVENTTYPE_GLBCHANGED
Definition: type_event.h:75
SCIP_Real SCIPvarGetAggrScalar(SCIP_VAR *var)
Definition: var.c:17823
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8525
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
Definition: lpi_clp.cpp:1435
public methods for problem variables
static SCIP_DECL_CONSEXITSOL(consExitsolIndicator)
SCIP_RETCODE SCIPaddDiveBoundChange(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir, SCIP_Real value, SCIP_Bool preferred)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define CONSHDLR_PROP_TIMING
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:235
SCIP_RETCODE SCIPlpiGetBounds(SCIP_LPI *lpi, int firstcol, int lastcol, SCIP_Real *lbs, SCIP_Real *ubs)
Definition: lpi_clp.cpp:1709
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
SCIP_RETCODE SCIPchgVarUbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4892
#define DEFAULT_ENFORCECUTS
static SCIP_DECL_CONSSEPASOL(consSepasolIndicator)
SCIP_RETCODE SCIPlpiGetRealSolQuality(SCIP_LPI *lpi, SCIP_LPSOLQUALITY qualityindicator, SCIP_Real *quality)
Definition: lpi_clp.cpp:2940
SCIP_CONS ** SCIPgetConss(SCIP *scip)
Definition: scip_prob.c:3088
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:5132
static SCIP_DECL_CONSGETNVARS(consGetNVarsIndicator)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3261
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE checkIISlocal(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_Real *vector, SCIP_Bool *isLocal)
SCIP_RETCODE SCIPcreateExprVar(SCIP *scip, SCIP_EXPR **expr, SCIP_VAR *var, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_var.c:390
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define DEFAULT_SEPAALTERNATIVELP
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
static SCIP_RETCODE setAltLPObjZero(SCIP *scip, SCIP_LPI *lp, int nconss, SCIP_CONS **conss)
SCIP_RETCODE SCIPaddSymgraphVarAggregation(SCIP *scip, SYM_GRAPH *graph, int rootidx, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Real constant)
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:102
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:590
variable expression handler
public methods for SCIP variables
#define DEFAULT_DUALREDUCTIONS
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition: var.c:17905
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8485
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:125
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:624
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, const char *consname, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlrrestart, SCIP_VAR *binvar, SCIP_Bool activeone, SCIP_Bool lessthanineq, SCIP_VAR *slackvar, SCIP_CONS *lincons, SCIP_Bool linconsactive)
SCIP_Real SCIPgetRhsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:808
SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
Definition: lpi_clp.cpp:531
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8277
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:998
static SCIP_DECL_CONSCHECK(consCheckIndicator)
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
#define DEFAULT_MAXSEPANONVIOLATED
#define DEFAULT_BRANCHINDICATORS
SCIP_RETCODE SCIPlpiAddCols(SCIP_LPI *lpi, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition: lpi_clp.cpp:758
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
public methods for numerical tolerances
SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPlpiIsPrimalUnbounded(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2488
#define CONSHDLR_SEPAFREQ
#define DEFAULT_ADDOPPOSITE
public methods for querying solving statistics
int SCIPlpiGetInternalStatus(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2752
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:17895
#define DEFAULT_CONFLICTSUPGRADE
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3423
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4261
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:78
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
public methods for the branch-and-bound tree
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:252
SCIP_VAR * SCIPgetSlackVarIndicator(SCIP_CONS *cons)
SCIP_VAR * SCIPfindVar(SCIP *scip, const char *name)
Definition: scip_prob.c:2685
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1880
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip_var.c:8178
static SCIP_DECL_CONSENABLE(consEnableIndicator)
SCIP_Bool SCIPlpiIsStable(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2647
static SCIP_DECL_CONSCOPY(consCopyIndicator)
static SCIP_DECL_CONSINITSOL(consInitsolIndicator)
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18089
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:444
static SCIP_DECL_CONSENFORELAX(consEnforelaxIndicator)
public methods for handling parameter settings
public methods for managing constraints
SCIP_RETCODE SCIPlpiAddRows(SCIP_LPI *lpi, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition: lpi_clp.cpp:914
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1242
SCIP_RETCODE SCIPsetConshdlrGetDiveBdChgs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETDIVEBDCHGS((*consgetdivebdchgs)))
Definition: scip_cons.c:877
static SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsIndicator)
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip_sol.c:474
methods for dealing with symmetry detection graphs
#define CONFLICTHDLR_NAME
SCIP_RETCODE SCIPlpiWriteLP(SCIP_LPI *lpi, const char *fname)
Definition: lpi_clp.cpp:4001
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:347
static SCIP_RETCODE extendToCover(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_LPI *lp, SCIP_SOL *sol, SCIP_ENFOSEPATYPE enfosepatype, SCIP_Bool removable, SCIP_Bool genlogicor, int nconss, SCIP_CONS **conss, SCIP_Bool *S, int *size, SCIP_Real *value, SCIP_Bool *error, SCIP_Bool *cutoff, int *nGen)
SCIP_RETCODE SCIPcreateConsBasicIndicator(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real rhs)
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:258
static SCIP_DECL_CONSPROP(consPropIndicator)
static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphIndicator)
SCIP_BOUNDTYPE SCIPboundtypeOpposite(SCIP_BOUNDTYPE boundtype)
Definition: lp.c:17203
static SCIP_RETCODE addAltLPColumn(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *slackvar, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real rhscoef, SCIP_Real objcoef, SCIP_Real sign, SCIP_Bool colfree, int *colindex)
#define SCIPerrorMessage
Definition: pub_message.h:64
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4199
void SCIPhashmapPrintStatistics(SCIP_HASHMAP *hashmap, SCIP_MESSAGEHDLR *messagehdlr)
Definition: misc.c:3485
SCIP_Bool SCIPisParamFixed(SCIP *scip, const char *name)
Definition: scip_param.c:219
SCIP_RETCODE SCIPgetConsNVars(SCIP *scip, SCIP_CONS *cons, int *nvars, SCIP_Bool *success)
Definition: scip_cons.c:2622
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:396
static SCIP_DECL_CONSPRESOL(consPresolIndicator)
#define EVENTHDLR_LINCONSBOUND_DESC
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3474
public methods for event handler plugins and event handlers
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)))
Definition: scip_cons.c:900
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1058
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17401
SCIP_Real SCIPgetDualbound(SCIP *scip)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1796
SCIP_RETCODE SCIPaddVarImplication(SCIP *scip, SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip_var.c:6782
static SCIP_DECL_CONSFREE(consFreeIndicator)
#define CONFLICTHDLR_PRIORITY
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:498
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
#define DEFAULT_NOLINCONSCONT
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4439
SCIP_RETCODE SCIPcreateConsQuadraticNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
SCIP_Bool SCIPlpiIsPrimalInfeasible(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2502
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8216
SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4768
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8717
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8435
static SCIP_DECL_CONSPARSE(consParseIndicator)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:173
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17420
#define DEFAULT_MAXCOUPLINGVALUE
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3108
type definitions for specific LP solvers interface
#define DEFAULT_FORCERESTART
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4219
SCIP_CONS * SCIPfindCons(SCIP *scip, const char *name)
Definition: scip_prob.c:2947
#define DEFAULT_SEPACOUPLINGLOCAL
SCIP_RETCODE SCIPenforelaxCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
Definition: scip_cons.c:2225
enum SCIP_enfosepatype SCIP_ENFOSEPATYPE
static SCIP_RETCODE setAltLPObj(SCIP *scip, SCIP_LPI *lp, SCIP_SOL *sol, int nconss, SCIP_CONS **conss)
SCIP_RETCODE SCIPcreateExprProduct(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real coefficient, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
structs for symmetry computations
#define REALABS(x)
Definition: def.h:197
#define SCIP_EVENTTYPE_UBRELAXED
Definition: type_event.h:80
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip_branch.c:1017
public methods for problem copies
handle partial solutions for linear problems with indicators and otherwise continuous variables ...
struct SCIP_ConflicthdlrData SCIP_CONFLICTHDLRDATA
Definition: type_conflict.h:50
SCIP_VAR * SCIPgetBinaryVarIndicatorGeneric(SCIP_CONS *cons)
#define SCIP_CALL(x)
Definition: def.h:380
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:77
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
#define DEFAULT_USEOBJECTIVECUT
static SCIP_RETCODE enforceCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_ENFOSEPATYPE enfosepatype, SCIP_Bool genlogicor, SCIP_Bool *cutoff, int *nGen)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17302
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8455
static SCIP_DECL_CONSDELETE(consDeleteIndicator)
static SCIP_DECL_CONSDISABLE(consDisableIndicator)
SCIP_RETCODE SCIPgetTransformedCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONS **transcons)
Definition: scip_cons.c:1675
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1139
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:250
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:647
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
SCIP_RETCODE SCIPdisableCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1872
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17238
SCIP_RETCODE SCIPgetConsVars(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **vars, int varssize, SCIP_Bool *success)
Definition: scip_cons.c:2578
int SCIPgetSymgraphNegatedVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
static SCIP_RETCODE fixAltLPVariable(SCIP_LPI *lp, int ind)
public methods for primal heuristic plugins and divesets
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4638
static SCIP_DECL_CONSENFOLP(consEnfolpIndicator)
public methods for constraint handler plugins and constraints
SCIP_RETCODE SCIPgetConsCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_CONS *sourcecons, SCIP_CONS **targetcons, SCIP_CONSHDLR *sourceconshdlr, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, const char *name, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
Definition: scip_copy.c:1591
SCIP_Bool SCIPlpiExistsPrimalRay(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2450
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1077
SCIP_PARAMTYPE SCIPparamGetType(SCIP_PARAM *param)
Definition: paramset.c:649
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17248
public data structures and miscellaneous methods
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1053
SCIP_RETCODE SCIPaddLinearConsIndicator(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *lincons)
#define SCIP_Bool
Definition: def.h:91
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:286
SCIP_RETCODE SCIPcreateConsIndicatorLinCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, SCIP_CONS *lincons, SCIP_VAR *slackvar, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define DEFAULT_ADDCOUPLING
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1030
SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:3919
SCIP_RETCODE SCIPlpiChgCoef(SCIP_LPI *lpi, int row, int col, SCIP_Real newval)
Definition: lpi_clp.cpp:1197
static const char * paramname[]
Definition: lpi_msk.c:5096
static SCIP_RETCODE deleteAltLPConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:670
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition: scip_expr.c:1417
static SCIP_DECL_CONSPRINT(consPrintIndicator)
constraint handler for nonlinear constraints specified by algebraic expressions
static SCIP_RETCODE unfixAltLPVariables(SCIP *scip, SCIP_LPI *lp, int nconss, SCIP_CONS **conss, SCIP_Bool *S)
#define DEFAULT_SEPACOUPLINGVALUE
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2537
#define DEFAULT_SEPAPERSPECTIVE
static SCIP_RETCODE createVarUbs(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *ngen)
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:361
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8236
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:487
public methods for LP management
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8345
static SCIP_DECL_CONFLICTFREE(conflictFreeIndicator)
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip_cons.c:739
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:320
public methods for cuts and aggregation rows
#define DEFAULT_MAXSEPACUTS
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:841
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8415
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8385
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17927
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:400
SCIP_Real SCIPbdchginfoGetNewbound(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18671
SCIP_VAR * SCIPvarGetAggrVar(SCIP_VAR *var)
Definition: var.c:17811
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip_var.c:114
#define SEPAALTTHRESHOLD
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip_nlp.c:954
static SCIP_DECL_LINCONSUPGD(linconsUpgdIndicator)
#define DEFAULT_REMOVEINDICATORS
SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
Definition: scip_var.c:8658
#define DEFAULT_TRYSOLFROMCOVER
SCIP_RETCODE SCIPsepasolCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_RESULT *result)
Definition: scip_cons.c:2311
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8278
static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphIndicator)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyIndicator)
int SCIPgetNRuns(SCIP *scip)
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4353
enum SYM_Symtype SYM_SYMTYPE
Definition: type_symmetry.h:60
SCIP_RETCODE SCIPenfolpCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool solinfeasible, SCIP_RESULT *result)
Definition: scip_cons.c:2195
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:785
SCIP_RETCODE SCIPaddSymgraphOpnode(SCIP *scip, SYM_GRAPH *graph, int op, int *nodeidx)
#define CONSHDLR_NAME
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:79
SCIP_RETCODE SCIPsetConflicthdlrFree(SCIP *scip, SCIP_CONFLICTHDLR *conflicthdlr, SCIP_DECL_CONFLICTFREE((*conflictfree)))
Constraint handler for linear constraints in their most general form, .
SCIP_Longint SCIPgetNConflictConssApplied(SCIP *scip)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
#define DEFAULT_RESTARTFRAC
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define SCIP_EVENTTYPE_GBDCHANGED
Definition: type_event.h:120
SCIP_VAR * SCIPgetBinaryVarIndicator(SCIP_CONS *cons)
SCIP_Bool SCIPlpiIsOptimal(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2623
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5503
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip_cons.c:716
SCIP_Real SCIPcalcChildEstimate(SCIP *scip, SCIP_VAR *var, SCIP_Real targetvalue)
Definition: scip_branch.c:947
#define DEFAULT_ADDCOUPLINGCONS
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2037
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4672
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)))
Definition: scip_cons.c:924
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:97
public methods for the LP relaxation, rows and columns
SCIP_RETCODE SCIPlpiChgBounds(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *lb, const SCIP_Real *ub)
Definition: lpi_clp.cpp:1084
SCIP_RETCODE SCIPvarGetProbvarBound(SCIP_VAR **var, SCIP_Real *bound, SCIP_BOUNDTYPE *boundtype)
Definition: var.c:12470
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
SCIP_Bool SCIPgetActiveOnIndicator(SCIP_CONS *cons)
int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
Definition: cons.c:8667
#define SCIP_REAL_MAX
Definition: def.h:174
public methods for nonlinear relaxation
product expression handler
SCIP_RETCODE SCIPincludeConshdlrIndicator(SCIP *scip)
SCIP_RETCODE SCIPsetBinaryVarIndicator(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *binvar)
#define SCIP_REAL_MIN
Definition: def.h:175
SCIP_RETCODE SCIPcreateConsIndicator(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_RETCODE scaleFirstRow(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
SCIP_RETCODE SCIPlpiGetRows(SCIP_LPI *lpi, int firstrow, int lastrow, SCIP_Real *lhs, SCIP_Real *rhs, int *nnonz, int *beg, int *ind, SCIP_Real *val)
Definition: lpi_clp.cpp:1538
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define SCIP_LONGINT_FORMAT
Definition: def.h:165
#define DEFAULT_UPDATEBOUNDS
static SCIP_RETCODE separateIndicators(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, int nusefulconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_ENFOSEPATYPE enfosepatype, SCIP_RESULT *result)
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition: lp.c:17258
public methods for branching rule plugins and branching
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
SCIP_Bool SCIPisObjIntegral(SCIP *scip)
Definition: scip_prob.c:1562
public methods for managing events
#define SCIP_EVENTTYPE_BESTSOLFOUND
Definition: type_event.h:105
general public methods
SCIP_RETCODE SCIPcreateConsIndicatorGenericLinConsPure(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, SCIP_CONS *lincons, SCIP_Bool activeone, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define CONSHDLR_ENFOPRIORITY
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPenfopsCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool solinfeasible, SCIP_Bool objinfeasible, SCIP_RESULT *result)
Definition: scip_cons.c:2164
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:17042
SCIP_RETCODE SCIPsepalpCons(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result)
Definition: scip_cons.c:2284
public methods for solutions
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip_copy.c:711
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1668
SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8246
static SCIP_RETCODE presolRoundIndicator(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_Bool dualreductions, SCIP_Bool *cutoff, SCIP_Bool *success, int *ndelconss, int *nfixedvars)
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5617
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:396
#define CONSHDLR_DELAYSEPA
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3472
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:420
public methods for conflict analysis handlers
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3042
public methods for the probing mode
static SCIP_DECL_CONSLOCK(consLockIndicator)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
#define LINCONSUPGD_PRIORITY
static SCIP_DECL_CONSENFOPS(consEnfopsIndicator)
SCIP_RETCODE SCIPcreateConsIndicatorGenericLinCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, SCIP_CONS *lincons, SCIP_VAR *slackvar, SCIP_Bool activeone, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define DEFAULT_SCALESLACKVAR
SCIP_RETCODE SCIPincludeConflicthdlrBasic(SCIP *scip, SCIP_CONFLICTHDLR **conflicthdlrptr, const char *name, const char *desc, int priority, SCIP_DECL_CONFLICTEXEC((*conflictexec)), SCIP_CONFLICTHDLRDATA *conflicthdlrdata)
static void initConshdlrData(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
const char * SCIPconflicthdlrGetName(SCIP_CONFLICTHDLR *conflicthdlr)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:540
public methods for message output
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:129
static SCIP_RETCODE branchCons(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result)
#define EVENTHDLR_BOUND_NAME
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1218
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
#define DEFAULT_GENLOGICOR
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17539
SCIP_RETCODE SCIPaddSymgraphConsnode(SCIP *scip, SYM_GRAPH *graph, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, int *nodeidx)
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1216
#define SCIP_Real
Definition: def.h:173
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8465
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_lp.c:1727
static SCIP_RETCODE initAlternativeLP(SCIP *scip, SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPaddRowIndicator(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_ROW *row)
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:854
public methods for message handling
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8405
SCIP_RETCODE SCIPcreateConsBasicIndicatorLinCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *binvar, SCIP_CONS *lincons, SCIP_VAR *slackvar)
SCIP_RETCODE SCIPmakeIndicatorsFeasible(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_Bool *changed)
#define SCIP_INVALID
Definition: def.h:193
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8395
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2212
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2167
SCIP_RETCODE SCIPaddSymgraphEdge(SCIP *scip, SYM_GRAPH *graph, int first, int second, SCIP_Bool hasval, SCIP_Real val)
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17585
SCIP_RETCODE SCIPlpiChgObj(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *obj)
Definition: lpi_clp.cpp:1240
static SCIP_RETCODE addAltLPConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *lincons, SCIP_VAR *slackvar, SCIP_Real objcoef, int *colindex)
static SCIP_DECL_PARAMCHGD(paramChangedIndicator)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
static SCIP_DECL_CONSSEPALP(consSepalpIndicator)
SCIP_Real * SCIPgetValsLinear(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_SEPAPRIORITY
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
enum SCIP_Vartype SCIP_VARTYPE
Definition: type_var.h:73
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
SCIP_Real SCIPgetVarSol(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:2309
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18145
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
#define CONSHDLR_EAGERFREQ
SCIP_RETCODE SCIPgetDivesetScore(SCIP *scip, SCIP_DIVESET *diveset, SCIP_DIVETYPE divetype, SCIP_VAR *divecand, SCIP_Real divecandsol, SCIP_Real divecandfrac, SCIP_Real *candscore, SCIP_Bool *roundup)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
#define DEFAULT_GENERATEBILINEAR
#define EVENTHDLR_RESTART_NAME
void SCIPconsAddUpgradeLocks(SCIP_CONS *cons, int nlocks)
Definition: cons.c:8655
SCIP_RETCODE SCIPlpiGetCoef(SCIP_LPI *lpi, int row, int col, SCIP_Real *val)
Definition: lpi_clp.cpp:1771
#define CONSHDLR_PROPFREQ
SCIP_BOUNDTYPE SCIPbdchginfoGetBoundtype(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18701
SCIP_Real SCIPgetUpperbound(SCIP *scip)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:3156
static SCIP_DECL_CONSTRANS(consTransIndicator)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE updateObjUpperbound(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
#define SCIP_EVENTTYPE_GUBCHANGED
Definition: type_event.h:76
SCIP_RETCODE SCIPaddConflict(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
Definition: scip_prob.c:3228
#define DEFAULT_USEOTHERCONSS
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3281
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1391
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
#define SCIP_DIVETYPE_INTEGRALITY
Definition: type_heur.h:60
SCIP_CONFLICTHDLRDATA * SCIPconflicthdlrGetData(SCIP_CONFLICTHDLR *conflicthdlr)
static SCIP_DECL_CONSGETVARS(consGetVarsIndicator)
SCIP_CONS * SCIPgetLinearConsIndicator(SCIP_CONS *cons)
static SCIP_RETCODE enforceIndicators(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_ENFOSEPATYPE enfosepatype, SCIP_Bool genlogicor, SCIP_RESULT *result)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:468
static SCIP_DECL_CONSEXIT(consExitIndicator)
#define SCIPABORT()
Definition: def.h:352
static SCIP_RETCODE separatePerspective(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, int nconss, SCIP_CONS **conss, int maxsepacuts, int *nGen)
public methods for global and local (sub)problems
static SCIP_RETCODE checkTransferBoolParam(SCIP *scip, SCIP_PARAM *param, const char *name, SCIP_Bool newvalue, SCIP_Bool *value)
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17611
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:17641
int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPchgBoolParam(SCIP *scip, SCIP_PARAM *param, SCIP_Bool value)
Definition: scip_param.c:403
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8631
SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
#define SCIP_CALL_PARAM(x)
static SCIP_RETCODE updateFirstRowGlobal(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
#define CONSHDLR_DELAYPROP
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1529
static SCIP_RETCODE fixAltLPVariables(SCIP *scip, SCIP_LPI *lp, int nconss, SCIP_CONS **conss, SCIP_Bool *S)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17749
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17575
#define DEFAULT_MAXSEPACUTSROOT
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:151
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:281
static SCIP_Real varGetObjDelta(SCIP_VAR *var)
memory allocation routines