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