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