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