Scippy

SCIP

Solving Constraint Integer Programs

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