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 reversed */
3379 if ( activeone || binvar == NULL )
3380 {
3381 binvarinternal = binvar;
3382 }
3383 else
3384 {
3385 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
3386 }
3387
3388 /* create constraint data */
3389 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
3390 (*consdata)->nfixednonzero = 0;
3391 (*consdata)->colindex = -1;
3392 (*consdata)->linconsactive = linconsactive;
3393 (*consdata)->binvar = binvarinternal;
3394 (*consdata)->slackvar = slackvar;
3395 (*consdata)->activeone = activeone;
3396 (*consdata)->lessthanineq = lessthanineq;
3397 (*consdata)->lincons = lincons;
3398 (*consdata)->implicationadded = FALSE;
3399 (*consdata)->slacktypechecked = FALSE;
3400 (*consdata)->varswithevents = NULL;
3401 (*consdata)->eventtypes = NULL;
3402 (*consdata)->nevents = 0;
3403
3404 /* if we are transformed, obtain transformed variables and catch events */
3405 if ( SCIPisTransformed(scip) )
3406 {
3407 SCIP_VAR* var;
3408
3409 /* handle binary variable */
3410 if ( binvarinternal != NULL )
3411 {
3412 SCIP_CALL( SCIPgetTransformedVar(scip, binvarinternal, &var) );
3413 assert( var != NULL );
3414 (*consdata)->binvar = var;
3415
3416 /* check type */
3417 if ( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY )
3418 {
3419 SCIPerrorMessage("Indicator variable <%s> is not binary %d.\n", SCIPvarGetName(var), SCIPvarGetType(var));
3420 return SCIP_ERROR;
3421 }
3422
3423 /* the indicator variable must not be multi-aggregated because the constraint handler propagation tries
3424 * to tighten its bounds, which is not allowed for multi-aggregated variables
3425 */
3427
3428 /* catch global bound change events on binary variable */
3429 if ( conshdlrdata->forcerestart )
3430 {
3431 SCIPdebugMsg(scip, "Catching GBDCHANGED event for <%s>.\n", SCIPvarGetName(var));
3432 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
3433 }
3434
3435 /* if binary variable is fixed to be nonzero */
3436 if ( SCIPvarGetLbLocal(var) > 0.5 )
3437 ++((*consdata)->nfixednonzero);
3438 }
3439
3440 /* handle slack variable */
3441 SCIP_CALL( SCIPgetTransformedVar(scip, slackvar, &var) );
3442 assert( var != NULL );
3443 (*consdata)->slackvar = var;
3444
3445 /* catch bound change events on slack variable and adjust nfixednonzero */
3446 if ( linconsactive )
3447 {
3448 /* if slack variable is fixed to be nonzero */
3450 ++((*consdata)->nfixednonzero);
3451 }
3452
3453 /* add corresponding column to alternative LP if the constraint is new */
3454 if ( conshdlrdata->sepaalternativelp && SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && lincons != NULL )
3455 {
3456 assert( lincons != NULL );
3457 assert( consname != NULL );
3458
3459 SCIP_CALL( addAltLPConstraint(scip, conshdlr, lincons, var, 1.0, &(*consdata)->colindex) );
3460
3461 SCIPdebugMsg(scip, "Added column for <%s> to alternative LP with column index %d.\n", consname, (*consdata)->colindex);
3462#ifdef SCIP_OUTPUT
3463 SCIP_CALL( SCIPprintCons(scip, lincons, NULL) );
3464 SCIPinfoMessage(scip, NULL, ";\n");
3465#endif
3466 }
3467
3468#ifdef SCIP_DEBUG
3469 if ( (*consdata)->nfixednonzero > 0 )
3470 {
3471 SCIPdebugMsg(scip, "Constraint <%s> has %d variables fixed to be nonzero.\n", consname, (*consdata)->nfixednonzero);
3472 }
3473#endif
3474 }
3475
3476 return SCIP_OKAY;
3477}
3478
3479
3480/** create variable upper bounds for constraints */
3481static
3483 SCIP* scip, /**< SCIP pointer */
3484 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3485 SCIP_CONS** conss, /**< constraints */
3486 int nconss, /**< number of constraints */
3487 int* ngen /**< number of successful operations */
3488 )
3489{
3490 char name[50] = "";
3491 int c;
3492
3493 assert( scip != NULL );
3494 assert( conshdlrdata != NULL );
3495 assert( ngen != NULL );
3496
3497 *ngen = 0;
3498
3499 /* check each constraint */
3500 for (c = 0; c < nconss; ++c)
3501 {
3502 SCIP_CONSDATA* consdata;
3503 SCIP_Real ub;
3504
3505 consdata = SCIPconsGetData(conss[c]);
3506 assert( consdata != NULL );
3507
3508 ub = SCIPvarGetUbGlobal(consdata->slackvar);
3509 assert( ! SCIPisNegative(scip, ub) );
3510
3511 /* insert corresponding row if helpful and coefficient is not too large */
3512 if ( ub <= conshdlrdata->maxcouplingvalue )
3513 {
3514 SCIP_CONS* cons;
3515
3516#ifndef NDEBUG
3517 (void) SCIPsnprintf(name, 50, "couple%d", c);
3518#endif
3519
3520 SCIPdebugMsg(scip, "Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
3521
3522 /* add variable upper bound:
3523 * - check constraint if we remove the indicator constraint afterwards
3524 * - constraint is dynamic if we do not remove indicator constraints
3525 * - constraint is removable if we do not remove indicator constraints
3526 */
3527 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
3528 TRUE, TRUE, TRUE, conshdlrdata->removeindicators, TRUE, FALSE, FALSE,
3529 !conshdlrdata->removeindicators, !conshdlrdata->removeindicators, FALSE) );
3530
3531 SCIP_CALL( SCIPaddCons(scip, cons) );
3532 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3533
3534 /* remove indicator constraint if required */
3535 if ( conshdlrdata->removeindicators )
3536 {
3537 SCIPdebugMsg(scip, "Removing indicator constraint <%s>.\n", SCIPconsGetName(conss[c]));
3538 assert( ! SCIPconsIsModifiable(conss[c]) );
3539 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
3540 }
3541
3542 ++(*ngen);
3543 }
3544 }
3545
3546 return SCIP_OKAY;
3547}
3548
3549
3550/** perform one presolving round */
3551static
3553 SCIP* scip, /**< SCIP pointer */
3554 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3555 SCIP_CONS* cons, /**< constraint */
3556 SCIP_CONSDATA* consdata, /**< constraint data */
3557 SCIP_Bool dualreductions, /**< should dual reductions be performed? */
3558 SCIP_Bool* cutoff, /**< whether a cutoff happened */
3559 SCIP_Bool* success, /**< whether we performed a successful reduction */
3560 int* ndelconss, /**< pointer to store the number of deleted constraints */
3561 int* nfixedvars /**< pointer to store the number of fixed variables */
3562 )
3563{
3564 SCIP_Bool infeasible;
3565 SCIP_Bool fixed;
3566
3567 assert( scip != NULL );
3568 assert( cons != NULL );
3569 assert( consdata != NULL );
3570 assert( cutoff != NULL );
3571 assert( success != NULL );
3572 assert( ndelconss != NULL );
3573 assert( nfixedvars != NULL );
3574 assert( consdata->binvar != NULL );
3575 assert( consdata->slackvar != NULL );
3576
3577 *cutoff = FALSE;
3578 *success = FALSE;
3579
3580 /* if the binary variable is fixed to nonzero */
3581 if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3582 {
3583 SCIPdebugMsg(scip, "Presolving <%s>: Binary variable fixed to 1.\n", SCIPconsGetName(cons));
3584
3585 /* if slack variable is fixed to nonzero, we are infeasible */
3586 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3587 {
3588 SCIPdebugMsg(scip, "The problem is infeasible: binary and slack variable are fixed to be nonzero.\n");
3589 *cutoff = TRUE;
3590 return SCIP_OKAY;
3591 }
3592
3593 /* otherwise fix slack variable to 0 */
3594 SCIPdebugMsg(scip, "Fix slack variable to 0 and delete constraint.\n");
3595 SCIP_CALL( SCIPfixVar(scip, consdata->slackvar, 0.0, &infeasible, &fixed) );
3596 assert( ! infeasible );
3597 if ( fixed )
3598 ++(*nfixedvars);
3599
3600 /* delete indicator constraint (leave linear constraint) */
3601 assert( ! SCIPconsIsModifiable(cons) );
3602 SCIP_CALL( SCIPdelCons(scip, cons) );
3603 ++(*ndelconss);
3604 *success = TRUE;
3605 return SCIP_OKAY;
3606 }
3607
3608 /* if the binary variable is fixed to zero */
3609 if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
3610 {
3611 SCIPdebugMsg(scip, "Presolving <%s>: Binary variable <%s> fixed to 0, deleting indicator constraint.\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->binvar));
3612
3613 /* delete indicator constraint */
3614 assert( ! SCIPconsIsModifiable(cons) );
3615 SCIP_CALL( SCIPdelCons(scip, cons) );
3616 ++(*ndelconss);
3617 *success = TRUE;
3618 return SCIP_OKAY;
3619 }
3620
3621 /* if the slack variable is fixed to nonzero */
3622 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3623 {
3624 SCIPdebugMsg(scip, "Presolving <%s>: Slack variable fixed to nonzero.\n", SCIPconsGetName(cons));
3625
3626 /* if binary variable is fixed to nonzero, we are infeasible */
3627 if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3628 {
3629 SCIPdebugMsg(scip, "The problem is infeasible: binary and slack variable are fixed to be nonzero.\n");
3630 *cutoff = TRUE;
3631 return SCIP_OKAY;
3632 }
3633
3634 /* otherwise fix binary variable to 0 */
3635 SCIPdebugMsg(scip, "Fix binary variable to 0 and delete indicator constraint.\n");
3636 SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
3637 assert( ! infeasible );
3638 if ( fixed )
3639 ++(*nfixedvars);
3640
3641 /* delete constraint */
3642 assert( ! SCIPconsIsModifiable(cons) );
3643 SCIP_CALL( SCIPdelCons(scip, cons) );
3644 ++(*ndelconss);
3645 *success = TRUE;
3646 return SCIP_OKAY;
3647 }
3648
3649 /* if the slack variable is fixed to zero */
3650 if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3651 {
3652 /* perform dual reductions - if required */
3653 if ( dualreductions )
3654 {
3655 SCIP_VAR* binvar;
3656 SCIP_Real obj;
3657
3658 /* check objective of binary variable */
3659 binvar = consdata->binvar;
3660 obj = varGetObjDelta(binvar);
3661
3662 /* if obj = 0, we prefer fixing the binary variable to 1 (if possible) */
3663 if ( obj <= 0.0 )
3664 {
3665 /* In this case we would like to fix the binary variable to 1, if it is not locked up
3666 * except by this indicator constraint. If more than one indicator constraint is
3667 * affected, we have to hope that they are all fulfilled - in this case the last
3668 * constraint will fix the binary variable to 1. */
3669 if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
3670 {
3671 if ( SCIPvarGetUbGlobal(binvar) > 0.5 )
3672 {
3673 SCIPdebugMsg(scip, "Presolving <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
3674 SCIP_CALL( SCIPfixVar(scip, binvar, 1.0, &infeasible, &fixed) );
3675 assert( ! infeasible );
3676 if ( fixed )
3677 ++(*nfixedvars);
3678 /* make sure that the other case does not occur */
3679 obj = -1.0;
3680 }
3681 }
3682 }
3683
3684 if ( obj >= 0.0 )
3685 {
3686 /* In this case we would like to fix the binary variable to 0, if it is not locked down
3687 * (should also have been performed by other dual reductions). */
3689 {
3690 if ( SCIPvarGetLbGlobal(binvar) < 0.5 )
3691 {
3692 SCIPdebugMsg(scip, "Presolving <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
3693 SCIP_CALL( SCIPfixVar(scip, binvar, 0.0, &infeasible, &fixed) );
3694 assert( ! infeasible );
3695 if ( fixed )
3696 ++(*nfixedvars);
3697 }
3698 }
3699 }
3700 }
3701
3702 SCIPdebugMsg(scip, "Presolving <%s>: Slack variable fixed to zero, delete redundant indicator constraint.\n", SCIPconsGetName(cons));
3703
3704 /* delete constraint */
3705 assert( ! SCIPconsIsModifiable(cons) );
3706 SCIP_CALL( SCIPdelCons(scip, cons) );
3707 ++(*ndelconss);
3708 *success = TRUE;
3709 return SCIP_OKAY;
3710 }
3711
3712 /* check whether indicator variable is aggregated */
3713 if ( SCIPvarGetStatus(consdata->binvar) == SCIP_VARSTATUS_AGGREGATED )
3714 {
3715 SCIP_Bool negated = FALSE;
3716 SCIP_VAR* var;
3717
3718 /* possibly get representation of indicator variable by active variable */
3719 var = consdata->binvar;
3720 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
3721 assert( var == consdata->binvar || SCIPvarIsActive(var) || SCIPvarIsNegated(var) );
3722
3723 /* we can replace the binary variable by the active variable if it is not negated */
3724 if ( var != consdata->binvar && ! negated )
3725 {
3726 SCIPdebugMsg(scip, "Indicator variable <%s> is aggregated and replaced by active/negated variable <%s>.\n", SCIPvarGetName(consdata->binvar), SCIPvarGetName(var) );
3727
3728 /* we need to update the events and locks */
3729 assert( conshdlrdata->eventhdlrbound != NULL );
3730 SCIP_CALL( SCIPdropVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, -1) );
3731 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, NULL) );
3732
3733 /* We also need to update the events and locks if restart is forced, since global bound change events on binary
3734 * variables are also caught in this case. If it would not be updated and forcerestart = TRUE, then an event
3735 * might be dropped on a wrong variable. */
3736 if ( conshdlrdata->forcerestart )
3737 {
3738 assert( conshdlrdata->eventhdlrrestart != NULL );
3740 conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, -1) );
3741 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
3742 (SCIP_EVENTDATA*) conshdlrdata, NULL) );
3743 }
3744
3745 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->binvar, SCIP_LOCKTYPE_MODEL, 0, -1) );
3747
3748 /* change binvary variable */
3749 consdata->binvar = var;
3750 }
3751 }
3752 else if ( SCIPvarGetStatus(consdata->binvar) == SCIP_VARSTATUS_NEGATED )
3753 {
3754 SCIP_VAR* var;
3755
3756 var = SCIPvarGetNegatedVar(consdata->binvar);
3757 assert( var != NULL );
3758
3759 /* if the binary variable is the negated slack variable, we have 1 - s = 1 -> s = 0, i.e., the constraint is redundant */
3760 if ( var == consdata->slackvar )
3761 {
3762 /* delete constraint */
3763 assert( ! SCIPconsIsModifiable(cons) );
3764 SCIP_CALL( SCIPdelCons(scip, cons) );
3765 ++(*ndelconss);
3766 *success = TRUE;
3767 return SCIP_OKAY;
3768 }
3769 }
3770
3771 /* check whether slack variable is aggregated */
3772 if ( SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_AGGREGATED || SCIPvarGetStatus(consdata->slackvar) == SCIP_VARSTATUS_NEGATED )
3773 {
3776 SCIP_VAR* var;
3777
3778 /* possibly get representation of slack variable by active variable */
3779 var = consdata->slackvar;
3781
3782 SCIP_CALL( SCIPvarGetProbvarBound(&var, &bound, &boundtype) );
3783 assert( var != consdata->slackvar );
3784
3785 /* we can replace the slack variable by the active variable if it is also a >= variable */
3786 if ( var != consdata->binvar && boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisEQ(scip, bound, 0.0) )
3787 {
3788 assert( SCIPvarIsActive(var) );
3789 SCIPdebugMsg(scip, "Slack variable <%s> is aggregated or negated and replaced by active variable <%s>.\n", SCIPvarGetName(consdata->slackvar), SCIPvarGetName(var) );
3790
3791 /* we need to update the events, locks, and captures */
3792 assert( conshdlrdata->eventhdlrbound != NULL );
3793 SCIP_CALL( SCIPdropVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, -1) );
3794 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) cons, NULL) );
3795
3796 SCIP_CALL( SCIPunlockVarCons(scip, consdata->slackvar, cons, FALSE, TRUE) );
3797 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
3798
3799 SCIP_CALL( SCIPreleaseVar(scip, &consdata->slackvar) );
3800 SCIP_CALL( SCIPcaptureVar(scip, var) );
3801
3802 /* change slack variable */
3803 consdata->slackvar = var;
3804 }
3805 else if ( var == consdata->binvar )
3806 {
3807 /* check special case that aggregating variable is equal to the indicator variable */
3808 assert( SCIPisEQ(scip, bound, 0.0) || SCIPisEQ(scip, bound, 1.0) );
3809
3810 /* if the lower bound is transformed to an upper bound, we have "y = 1 -> 1 - y = 0", i.e., the constraint is redundant */
3811 if ( boundtype == SCIP_BOUNDTYPE_UPPER )
3812 {
3813 SCIPdebugMsg(scip, "Slack variable <%s> is aggregated to negated indicator variable <%s> -> constraint redundant.\n",
3814 SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3815 assert( SCIPisEQ(scip, bound, 1.0) );
3816
3817 /* delete constraint */
3818 assert( ! SCIPconsIsModifiable(cons) );
3819 SCIP_CALL( SCIPdelCons(scip, cons) );
3820 ++(*ndelconss);
3821 *success = TRUE;
3822 return SCIP_OKAY;
3823 }
3824 else
3825 {
3826 /* if the lower bound is transformed to a lower bound, we have "y = 1 -> y = 0", i.e., we can fix the binary variable to 0 */
3827 SCIPdebugMsg(scip, "Slack variable <%s> is aggregated to the indicator variable <%s> -> fix indicator variable to 0.\n",
3828 SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3829 assert( boundtype == SCIP_BOUNDTYPE_LOWER );
3830 assert( SCIPisEQ(scip, bound, 0.0) );
3831
3832 SCIP_CALL( SCIPfixVar(scip, consdata->binvar, 0.0, &infeasible, &fixed) );
3833 assert( ! infeasible );
3834
3835 if ( fixed )
3836 ++(*nfixedvars);
3837
3838 SCIP_CALL( SCIPdelCons(scip, cons) );
3839
3840 ++(*ndelconss);
3841 *success = TRUE;
3842
3843 return SCIP_OKAY;
3844 }
3845 }
3846 }
3847
3848 /* Note that because of possible multi-aggregation we cannot simply remove the indicator
3849 * constraint if the linear constraint is not active or disabled - see the note in @ref
3850 * PREPROC. */
3851
3852 return SCIP_OKAY;
3853}
3854
3855
3856/** propagate indicator constraint */
3857static
3859 SCIP* scip, /**< SCIP pointer */
3860 SCIP_CONS* cons, /**< constraint */
3861 SCIP_CONSDATA* consdata, /**< constraint data */
3862 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3863 SCIP_Bool dualreductions, /**< should dual reductions be performed? */
3864 SCIP_Bool addopposite, /**< add opposite inequalities if binary var = 0? */
3865 SCIP_Bool* cutoff, /**< whether a cutoff happened */
3866 int* nGen /**< number of domain changes */
3867 )
3868{
3869 SCIP_Bool infeasible;
3870 SCIP_Bool tightened;
3871
3872 assert( scip != NULL );
3873 assert( cons != NULL );
3874 assert( consdata != NULL );
3875 assert( cutoff != NULL );
3876 assert( nGen != NULL );
3877
3878 *cutoff = FALSE;
3879 *nGen = 0;
3880
3881 /* if the linear constraint has not been generated, we do nothing */
3882 if ( ! consdata->linconsactive )
3883 return SCIP_OKAY;
3884
3885 assert( consdata->slackvar != NULL );
3886 assert( consdata->binvar != NULL );
3887 assert( SCIPisFeasGE(scip, SCIPvarGetLbLocal(consdata->slackvar), 0.0) );
3888
3889 /* increase age of constraint; age will be reset to zero, if a conflict or a propagation was found */
3890 if ( ! SCIPinRepropagation(scip) )
3891 {
3892 SCIP_CALL( SCIPincConsAge(scip, cons) );
3893 }
3894
3895 /* if both slackvar and binvar are fixed to be nonzero */
3896 if ( consdata->nfixednonzero > 1 )
3897 {
3898 SCIPdebugMsg(scip, "The node is infeasible, both the slack variable and the binary variable are fixed to be nonzero.\n");
3899 *cutoff = TRUE;
3900
3902 assert( SCIPvarGetLbLocal(consdata->binvar) > 0.5 );
3903 assert( SCIPisPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) );
3904
3905 /* check if conflict analysis is turned on */
3907 return SCIP_OKAY;
3908
3909 /* conflict analysis can only be applied in solving stage */
3911
3912 /* perform conflict analysis */
3914
3915 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->binvar) );
3916 SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, NULL) );
3918
3919 return SCIP_OKAY;
3920 }
3921
3922 /* if exactly one of the variables is fixed to be nonzero */
3923 if ( consdata->nfixednonzero == 1 )
3924 {
3925 /* if binvar is fixed to be nonzero */
3926 if ( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
3927 {
3928 assert( SCIPvarGetStatus(consdata->slackvar) != SCIP_VARSTATUS_MULTAGGR );
3929
3930 /* if slack variable is not already fixed to 0 */
3931 if ( ! SCIPisZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
3932 {
3933 SCIPdebugMsg(scip, "Binary variable <%s> is fixed to be nonzero, fixing slack variable <%s> to 0.\n",
3934 SCIPvarGetName(consdata->binvar), SCIPvarGetName(consdata->slackvar));
3935
3936 /* fix slack variable to 0 */
3937 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->slackvar, 0.0, cons, 0, FALSE, &infeasible, &tightened) );
3938 assert( ! infeasible );
3939 if ( tightened )
3940 ++(*nGen);
3941 }
3942 }
3943
3944 /* if slackvar is fixed to be nonzero */
3945 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->slackvar)) )
3946 {
3947 /* if binary variable is not yet fixed to 0 */
3948 if ( SCIPvarGetUbLocal(consdata->binvar) > 0.5 )
3949 {
3950 SCIPdebugMsg(scip, "Slack variable <%s> is fixed to be nonzero, fixing binary variable <%s> to 0.\n",
3951 SCIPvarGetName(consdata->slackvar), SCIPvarGetName(consdata->binvar));
3952
3953 /* fix binary variable to 0 */
3954 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->binvar, 0.0, cons, 1, FALSE, &infeasible, &tightened) );
3955 assert( ! infeasible );
3956 if ( tightened )
3957 ++(*nGen);
3958 }
3959 }
3960
3961 /* remove constraint if we are not in probing */
3962 if ( ! SCIPinProbing(scip) )
3963 {
3964 /* delete constraint locally */
3965 assert( ! SCIPconsIsModifiable(cons) );
3967 }
3968 }
3969 else
3970 {
3971 /* if the binary variable is fixed to zero */
3972 if ( SCIPvarGetUbLocal(consdata->binvar) < 0.5 )
3973 {
3974 if ( addopposite && consdata->linconsactive )
3975 {
3976 char name[SCIP_MAXSTRLEN];
3977 SCIP_CONS* reversecons;
3978 SCIP_VAR** linvars;
3979 SCIP_Real* linvals;
3980 SCIP_Bool allintegral = TRUE;
3981 SCIP_VAR* slackvar;
3982 SCIP_VAR** vars;
3983 SCIP_Real* vals;
3984 SCIP_Real lhs;
3985 SCIP_Real rhs;
3986 int nlinvars;
3987 int nvars = 0;
3988 int j;
3989
3990 /* determine lhs/rhs (first exchange lhs/rhs) */
3991 lhs = SCIPgetRhsLinear(scip, consdata->lincons);
3992 if ( SCIPisInfinity(scip, lhs) )
3993 lhs = -SCIPinfinity(scip);
3994 rhs = SCIPgetLhsLinear(scip, consdata->lincons);
3995 if ( SCIPisInfinity(scip, -rhs) )
3996 rhs = SCIPinfinity(scip);
3997
3998 assert( ! SCIPisInfinity(scip, lhs) );
3999 assert( ! SCIPisInfinity(scip, -rhs) );
4000
4001 /* consider only finite lhs/rhs */
4002 if ( ! SCIPisInfinity(scip, -lhs) || ! SCIPisInfinity(scip, rhs) )
4003 {
4004 /* ignore equations (cannot add opposite constraint) */
4005 if ( ! SCIPisEQ(scip, lhs, rhs) )
4006 {
4007 assert( consdata->lincons != NULL );
4008 nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
4009 linvars = SCIPgetVarsLinear(scip, consdata->lincons);
4010 linvals = SCIPgetValsLinear(scip, consdata->lincons);
4011 slackvar = consdata->slackvar;
4012 assert( slackvar != NULL );
4013
4014 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlinvars) );
4015 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlinvars) );
4016
4017 /* copy data and check whether the linear constraint is integral */
4018 for (j = 0; j < nlinvars; ++j)
4019 {
4020 if ( linvars[j] != slackvar )
4021 {
4022 if (! SCIPvarIsIntegral(linvars[j]) || ! SCIPisIntegral(scip, linvals[j]) )
4023 allintegral = FALSE;
4024
4025 vars[nvars] = linvars[j];
4026 vals[nvars++] = linvals[j];
4027 }
4028 }
4029 assert( nlinvars == nvars + 1 );
4030
4031 /* possibly adjust lhs/rhs */
4032 if ( allintegral && ! SCIPisInfinity(scip, REALABS(lhs)) )
4033 lhs += 1.0;
4034
4035 if ( allintegral && ! SCIPisInfinity(scip, REALABS(rhs)) )
4036 rhs -= 1.0;
4037
4038 /* create reverse constraint */
4039 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "reverse_%s", SCIPconsGetName(consdata->lincons));
4040
4041 /* constraint is initial, separated, not enforced, not checked, propagated, local, not modifiable, dynamic, removable */
4042 SCIP_CALL( SCIPcreateConsLinear(scip, &reversecons, name, nvars, vars, vals, lhs, rhs,
4044
4045 SCIPdebugMsg(scip, "Binary variable <%s> fixed to 0. Adding opposite linear inequality.\n", SCIPvarGetName(consdata->binvar));
4046 SCIPdebugPrintCons(scip, reversecons, NULL);
4047
4048 /* add constraint */
4049 SCIP_CALL( SCIPaddCons(scip, reversecons) );
4050 SCIP_CALL( SCIPreleaseCons(scip, &reversecons) );
4051
4052 SCIPfreeBufferArray(scip, &vals);
4053 SCIPfreeBufferArray(scip, &vars);
4054 }
4055 }
4056 }
4057
4058 /* remove constraint if we are not in probing */
4059 if ( ! SCIPinProbing(scip) )
4060 {
4061 /* delete constraint locally */
4062 assert( ! SCIPconsIsModifiable(cons) );
4064 }
4065 }
4066 /* if the slack variable is fixed to zero */
4067 else if ( SCIPisFeasZero(scip, SCIPvarGetUbLocal(consdata->slackvar)) )
4068 {
4069 /* perform dual reduction - if required */
4070 if ( dualreductions )
4071 {
4072 SCIP_VAR* binvar;
4073 SCIP_Real obj;
4074
4075 /* check objective of binary variable */
4076 binvar = consdata->binvar;
4077 obj = varGetObjDelta(binvar);
4078
4079 /* if obj = 0, we prefer setting the binary variable to 1 (if possible) */
4080 if ( obj <= 0.0 )
4081 {
4082 /* In this case we would like to fix the binary variable to 1, if it is not locked up
4083 * except by this indicator constraint. If more than one indicator constraint is
4084 * affected, we have to hope that they are all fulfilled - in this case the last
4085 * constraint will fix the binary variable to 1. */
4086 if ( SCIPvarGetNLocksUpType(binvar, SCIP_LOCKTYPE_MODEL) <= 1 )
4087 {
4088 if ( SCIPvarGetUbLocal(binvar) > 0.5 )
4089 {
4090 SCIPdebugMsg(scip, "Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 1.\n", SCIPconsGetName(cons));
4091 SCIP_CALL( SCIPinferVarLbCons(scip, binvar, 1.0, cons, 2, FALSE, &infeasible, &tightened) );
4092 assert( ! infeasible );
4093 if ( tightened )
4094 ++(*nGen);
4095 /* Make sure that the other case does not occur, since we are not sure whether SCIPinferVarLbCons() directly changes the bounds. */
4096 obj = -1.0;
4097 }
4098 }
4099 }
4100
4101 if ( obj >= 0.0 )
4102 {
4103 /* In this case we would like to fix the binary variable to 0, if it is not locked down
4104 * (should also have been performed by other dual reductions). */
4106 {
4107 if ( SCIPvarGetLbLocal(binvar) < 0.5 )
4108 {
4109 SCIPdebugMsg(scip, "Propagating <%s> - dual reduction: Slack variable fixed to 0, fix binary variable to 0.\n", SCIPconsGetName(cons));
4110 SCIP_CALL( SCIPinferVarUbCons(scip, binvar, 0.0, cons, 2, FALSE, &infeasible, &tightened) );
4111 assert( ! infeasible );
4112 if ( tightened )
4113 ++(*nGen);
4114 }
4115 }
4116 }
4117 }
4118
4119 SCIPdebugMsg(scip, "Slack variable fixed to zero, delete redundant indicator constraint <%s>.\n", SCIPconsGetName(cons));
4120
4121 /* delete constraint */
4122 assert( ! SCIPconsIsModifiable(cons) );
4123
4124 /* remove constraint if we are not in probing */
4125 if ( ! SCIPinProbing(scip) )
4126 {
4128 }
4129 }
4130
4131 /* Note that because of possible multi-aggregation we cannot simply remove the indicator
4132 * constraint if the linear constraint is not active or disabled - see the note in @ref
4133 * PREPROC and consPresolIndicator(). Moreover, it would drastically increase memory
4134 * consumption, because the linear constraints have to be stored in each node. */
4135 }
4136
4137 /* propagate maximal activity of linear constraint to upper bound of slack variable
4138 *
4139 * It is especially worth to tighten the upper bound if it is greater than maxcouplingvalue or sepacouplingvalue.
4140 * But do not tighten it if slackvar is locked down by other constraints,
4141 * or if it has a nonzero coefficient in the objective function.
4142 *
4143 * ax - c * s <= rhs -> s <= (maxActivity(ax) - rhs) / c;
4144 */
4145 if ( (SCIPvarGetUbLocal(consdata->slackvar) > conshdlrdata->maxcouplingvalue
4146 || SCIPvarGetUbLocal(consdata->slackvar) > conshdlrdata->sepacouplingvalue)
4147 && SCIPvarGetNLocksDownType(consdata->slackvar, SCIP_LOCKTYPE_MODEL) <= 1
4148 && SCIPvarGetObj(consdata->slackvar) == 0.0 && SCIPconsIsActive(consdata->lincons) )
4149 {
4150 SCIP_VAR** linconsvars;
4151 SCIP_Real* linconsvals;
4152 SCIP_Real maxactivity = 0.0;
4153 SCIP_Real coeffslack = SCIP_INVALID; /* -c */
4154 SCIP_Real newub;
4155 SCIP_Real rhs;
4156 int nlinconsvars;
4157 int j;
4158
4159 nlinconsvars = SCIPgetNVarsLinear(scip, consdata->lincons);
4160 linconsvars = SCIPgetVarsLinear(scip, consdata->lincons);
4161 linconsvals = SCIPgetValsLinear(scip, consdata->lincons);
4162
4163 /* calculate maximal activity of linear constraint without slackvar */
4164 for (j = 0; j < nlinconsvars; ++j)
4165 {
4166 SCIP_VAR* var;
4167 SCIP_Real val;
4169
4170 val = linconsvals[j];
4171 assert( ! SCIPisZero(scip, val) );
4172
4173 var = linconsvars[j];
4174 assert( var != NULL );
4175
4176 /* store slackvar coefficient */
4177 if ( var == consdata->slackvar )
4178 {
4179 coeffslack = val;
4180 continue;
4181 }
4182
4183 if ( val > 0.0 )
4184 bound = SCIPvarGetUbLocal(var);
4185 else
4186 bound = SCIPvarGetLbLocal(var);
4187
4189 {
4190 maxactivity = SCIPinfinity(scip);
4191 break;
4192 }
4193 else
4194 maxactivity += val * bound;
4195 }
4196
4197 /* continue only if maxactivity is not infinity */
4198 if ( !SCIPisInfinity(scip, maxactivity) && coeffslack != SCIP_INVALID && coeffslack < 0.0 ) /*lint !e777*/
4199 {
4200 rhs = SCIPgetRhsLinear(scip, consdata->lincons);
4201
4202 /* continue if rhs is not finite; happens, e.g., if variables are multiaggregated; we would need the minimal activity in this case */
4203 if ( !SCIPisInfinity(scip, rhs) )
4204 {
4205 /* divide by coeff of slackvar */
4206 newub = (maxactivity - rhs) / (-1.0 * coeffslack);
4207 assert( !SCIPisInfinity(scip, newub) );
4208
4209 /* adjust bound if slackvar is (implicit) integer */
4210 newub = SCIPadjustedVarUb(scip, consdata->slackvar, newub);
4211
4212 if ( SCIPisFeasLT(scip, newub, SCIPvarGetUbLocal(consdata->slackvar))
4213 && newub > SCIPvarGetLbLocal(consdata->slackvar) )
4214 {
4215 SCIPdebugMsg(scip, "Adjusting upper bound of slack variable <%s> to %g for indicator constraint <%s>.\n",
4216 SCIPvarGetName(consdata->slackvar), newub, SCIPconsGetName(cons));
4217
4218 /* propagate bound */
4219 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->slackvar, newub, cons, 3, FALSE, &infeasible, &tightened) );
4220 assert( !infeasible );
4221 if ( tightened )
4222 ++(*nGen);
4223 }
4224 }
4225 }
4226 }
4227
4228 /* reset constraint age counter */
4229 if ( *nGen > 0 )
4230 {
4232 }
4233
4234 return SCIP_OKAY;
4235}
4236
4237
4238/** enforcement method that produces cuts if possible
4239 *
4240 * This is a variant of the enforcement method that generates cuts/constraints via the alternative
4241 * LP, if possible.
4242 */
4243static
4245 SCIP* scip, /**< SCIP pointer */
4246 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4247 int nconss, /**< number of constraints */
4248 SCIP_CONS** conss, /**< indicator constraints */
4249 SCIP_SOL* sol, /**< solution to be enforced */
4250 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4251 SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
4252 SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
4253 int* nGen /**< number of cuts generated */
4254 )
4255{
4256 SCIP_CONSHDLRDATA* conshdlrdata;
4257 SCIP_LPI* lp;
4258 SCIP_Bool* S;
4259 SCIP_Real value = 0.0;
4260 SCIP_Bool error;
4261 int size = 0;
4262 int nCuts;
4263 int j;
4264
4265 assert( scip != NULL );
4266 assert( conshdlr != NULL );
4267 assert( conss != NULL );
4268 assert( cutoff != NULL );
4269 assert( nGen != NULL );
4270
4271 SCIPdebugMsg(scip, "Enforcing via cuts ...\n");
4272 *cutoff = FALSE;
4273 *nGen = 0;
4274
4275 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4276 assert( conshdlrdata != NULL );
4277 lp = conshdlrdata->altlp;
4278 assert( lp != NULL );
4279
4280#ifndef NDEBUG
4281 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4282#endif
4283
4284 /* change coefficients of bounds in alternative LP */
4285 if ( conshdlrdata->updatebounds )
4286 SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
4287
4288 /* possibly update upper bound */
4289 SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4290
4291 /* scale first row if necessary */
4292 SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
4293
4294 /* set objective function to current solution */
4295 SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
4296
4297 SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
4298
4299 /* set up variables fixed to 1 */
4300 for (j = 0; j < nconss; ++j)
4301 {
4302 SCIP_CONSDATA* consdata;
4303
4304 assert( conss[j] != NULL );
4305 consdata = SCIPconsGetData(conss[j]);
4306 assert( consdata != NULL );
4307
4308 assert( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
4309 if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
4310 {
4311 ++size;
4312 value += varGetObjDelta(consdata->binvar);
4313 S[j] = TRUE;
4314 }
4315 else
4316 S[j] = FALSE;
4317 }
4318
4319 /* fix the variables in S */
4320 SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
4321
4322 /* extend set S to a cover and generate cuts */
4323 error = FALSE;
4324 SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, genlogicor, nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
4325 *nGen = nCuts;
4326
4327 /* return with an error if no cuts have been produced and and error occurred in extendToCover() */
4328 if ( nCuts == 0 && error )
4329 return SCIP_LPERROR;
4330
4331 SCIPdebugMsg(scip, "Generated %d IIS-cuts.\n", nCuts);
4332
4333 /* reset bounds */
4334 SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
4335
4336#ifndef NDEBUG
4337 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4338#endif
4339
4341
4342 return SCIP_OKAY;
4343}
4344
4345
4346/** enforcement method
4347 *
4348 * We check whether the current solution is feasible, i.e., if binvar = 1
4349 * implies that slackvar = 0. If not, we branch as follows:
4350 *
4351 * In one branch we fix binvar = 1 and slackvar = 0. In the other branch
4352 * we fix binvar = 0 and leave slackvar unchanged.
4353 */
4354static
4356 SCIP* scip, /**< SCIP pointer */
4357 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4358 int nconss, /**< number of constraints */
4359 SCIP_CONS** conss, /**< indicator constraints */
4360 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
4361 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4362 SCIP_Bool genlogicor, /**< whether logicor constraint should be generated */
4363 SCIP_RESULT* result /**< result */
4364 )
4365{
4366 SCIP_CONSHDLRDATA* conshdlrdata;
4367 SCIP_CONSDATA* consdata;
4368 SCIP_NODE* node1;
4369 SCIP_NODE* node2;
4370 SCIP_VAR* slackvar;
4371 SCIP_VAR* binvar;
4373 SCIP_Real maxSlack = -1.0;
4374 SCIP_Bool someLinconsNotActive = FALSE;
4375 SCIP_Bool dualreductions;
4376 int c;
4377
4378 assert( scip != NULL );
4379 assert( conshdlr != NULL );
4380 assert( conss != NULL );
4381 assert( result != NULL );
4382
4383 *result = SCIP_FEASIBLE;
4384
4385 SCIPdebugMsg(scip, "Enforcing indicator constraints for <%s> ...\n", SCIPconshdlrGetName(conshdlr) );
4386
4387 /* get constraint handler data */
4388 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4389 assert( conshdlrdata != NULL );
4390
4391 dualreductions = conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip);
4392
4393 /* check each constraint */
4394 for (c = 0; c < nconss; ++c)
4395 {
4396 SCIP_Bool cutoff;
4397 SCIP_Real valSlack;
4398 int cnt;
4399
4400 assert( conss[c] != NULL );
4401 consdata = SCIPconsGetData(conss[c]);
4402 assert( consdata != NULL );
4403 assert( consdata->lincons != NULL );
4404
4405 /* if the linear constraint has not been generated, we do nothing */
4406 if ( ! consdata->linconsactive )
4407 {
4408 someLinconsNotActive = TRUE;
4409 continue;
4410 }
4411
4412 /* first perform propagation (it might happen that standard propagation is turned off) */
4413 SCIP_CALL( propIndicator(scip, conss[c], consdata, conshdlrdata, dualreductions, conshdlrdata->addopposite, &cutoff, &cnt) );
4414 if ( cutoff )
4415 {
4416 SCIPdebugMsg(scip, "Propagation in enforcing <%s> detected cutoff.\n", SCIPconsGetName(conss[c]));
4417 *result = SCIP_CUTOFF;
4418 return SCIP_OKAY;
4419 }
4420 if ( cnt > 0 )
4421 {
4422 SCIPdebugMsg(scip, "Propagation in enforcing <%s> reduced domains: %d.\n", SCIPconsGetName(conss[c]), cnt);
4423 *result = SCIP_REDUCEDDOM;
4424 return SCIP_OKAY;
4425 }
4426
4427 /* check whether constraint is infeasible */
4428 binvar = consdata->binvar;
4429 valSlack = SCIPgetSolVal(scip, sol, consdata->slackvar);
4430 assert( ! SCIPisFeasNegative(scip, valSlack) );
4431 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, binvar)) && ! SCIPisFeasZero(scip, valSlack) )
4432 {
4433 /* binary variable is not fixed - otherwise we would not be infeasible */
4434 assert( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 );
4435
4436 if ( valSlack > maxSlack )
4437 {
4438 maxSlack = valSlack;
4439 branchCons = conss[c];
4440#ifdef SCIP_OUTPUT
4441 SCIPinfoMessage(scip, NULL, "Violated indicator constraint:\n");
4442 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
4443 SCIPinfoMessage(scip, NULL, ";\n");
4444 SCIPinfoMessage(scip, NULL, "Corresponding linear constraint:\n");
4445 SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
4446 SCIPinfoMessage(scip, NULL, ";\n");
4447#endif
4448 }
4449 }
4450 }
4451
4452 /* if some constraint has a linear constraint that is not active, we need to check feasibility via the alternative polyhedron */
4453 if ( (someLinconsNotActive || conshdlrdata->enforcecuts) && conshdlrdata->sepaalternativelp )
4454 {
4455 SCIP_Bool cutoff;
4456 int ngen;
4457
4458 SCIP_CALL( enforceCuts(scip, conshdlr, nconss, conss, sol, enfosepatype, genlogicor, &cutoff, &ngen) );
4459 if ( cutoff )
4460 {
4461 conshdlrdata->niiscutsgen += ngen;
4462 *result = SCIP_CUTOFF;
4463 return SCIP_OKAY;
4464 }
4465
4466 if ( ngen > 0 )
4467 {
4468 conshdlrdata->niiscutsgen += ngen;
4469 if ( genlogicor )
4470 {
4471 SCIPdebugMsg(scip, "Generated %d constraints.\n", ngen);
4472 *result = SCIP_CONSADDED;
4473 }
4474 else
4475 {
4476 SCIPdebugMsg(scip, "Generated %d cuts.\n", ngen);
4477 *result = SCIP_SEPARATED;
4478 }
4479 return SCIP_OKAY;
4480 }
4481 SCIPdebugMsg(scip, "Enforcing produced no cuts.\n");
4482
4483 assert( ! someLinconsNotActive || branchCons == NULL );
4484 }
4485
4486 /* if all constraints are feasible */
4487 if ( branchCons == NULL )
4488 {
4489 SCIPdebugMsg(scip, "All indicator constraints are feasible.\n");
4490 return SCIP_OKAY;
4491 }
4492
4493 /* skip branching if required */
4494 if ( ! conshdlrdata->branchindicators )
4495 {
4496 *result = SCIP_INFEASIBLE;
4497 return SCIP_OKAY;
4498 }
4499
4500 /* otherwise create branches */
4501 SCIPdebugMsg(scip, "Branching on constraint <%s> (slack value: %f).\n", SCIPconsGetName(branchCons), maxSlack);
4502 consdata = SCIPconsGetData(branchCons);
4503 assert( consdata != NULL );
4504 binvar = consdata->binvar;
4505 slackvar = consdata->slackvar;
4506
4507 /* node1: binvar = 1, slackvar = 0 */
4508 SCIP_CALL( SCIPcreateChild(scip, &node1, 0.0, SCIPcalcChildEstimate(scip, binvar, 1.0) ) );
4509
4510 if ( SCIPvarGetLbLocal(binvar) < 0.5 )
4511 {
4512 SCIP_CALL( SCIPchgVarLbNode(scip, node1, binvar, 1.0) );
4513 }
4514
4515 /* if slack-variable is multi-aggregated */
4516 assert( SCIPvarGetStatus(slackvar) != SCIP_VARSTATUS_MULTAGGR );
4517 if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(slackvar)) )
4518 {
4519 SCIP_CALL( SCIPchgVarUbNode(scip, node1, slackvar, 0.0) );
4520 }
4521
4522 /* node2: binvar = 0, no restriction on slackvar */
4523 SCIP_CALL( SCIPcreateChild(scip, &node2, 0.0, SCIPcalcChildEstimate(scip, binvar, 0.0) ) );
4524
4525 if ( SCIPvarGetUbLocal(binvar) > 0.5 )
4526 {
4527 SCIP_CALL( SCIPchgVarUbNode(scip, node2, binvar, 0.0) );
4528 }
4529
4531 *result = SCIP_BRANCHED;
4532
4533 return SCIP_OKAY;
4534}
4535
4536
4537/** separate IIS-cuts via rounding
4538 *
4539 * @todo Check whether the cover produced at the end is a feasible solution.
4540 */
4541static
4543 SCIP* scip, /**< SCIP pointer */
4544 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4545 SCIP_SOL* sol, /**< solution to be separated */
4546 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4547 int nconss, /**< number of constraints */
4548 SCIP_CONS** conss, /**< indicator constraints */
4549 int maxsepacuts, /**< maximal number of cuts to be generated */
4550 SCIP_Bool* cutoff, /**< whether we detected a cutoff by an infeasible inequality */
4551 int* nGen /**< number of domain changes */
4552 )
4553{ /*lint --e{850}*/
4554 SCIP_CONSHDLRDATA* conshdlrdata;
4555 SCIP_LPI* lp;
4556 int rounds;
4557 SCIP_Real threshold;
4558 SCIP_Bool* S;
4559 SCIP_Bool error;
4560 int oldsize = -1;
4561 SCIPdebug( int nGenOld = *nGen; )
4562
4563 assert( scip != NULL );
4564 assert( conshdlr != NULL );
4565 assert( conss != NULL );
4566 assert( cutoff != NULL );
4567 assert( nGen != NULL );
4568
4569 if ( *nGen >= maxsepacuts )
4570 return SCIP_OKAY;
4571
4572 *cutoff = FALSE;
4573 rounds = 0;
4574
4575 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4576 assert( conshdlrdata != NULL );
4577 lp = conshdlrdata->altlp;
4578 assert( lp != NULL );
4579
4580 SCIPdebugMsg(scip, "Separating IIS-cuts by rounding ...\n");
4581
4582#ifndef NDEBUG
4583 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4584#endif
4585
4586 /* change coefficients of bounds in alternative LP */
4587 if ( conshdlrdata->updatebounds )
4588 {
4589 /* update to local bounds */
4590 SCIP_CALL( updateFirstRow(scip, conshdlrdata) );
4591 }
4592
4593 /* possibly update upper bound */
4594 SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4595
4596 /* scale first row if necessary */
4597 SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
4598
4599 /* set objective function to current solution */
4600 SCIP_CALL( setAltLPObj(scip, lp, sol, nconss, conss) );
4601
4602 SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
4603
4604 /* loop through the possible thresholds */
4605 for (threshold = conshdlrdata->roundingmaxthres;
4606 rounds < conshdlrdata->maxroundingrounds && threshold >= conshdlrdata->roundingminthres && *nGen < maxsepacuts && ! (*cutoff);
4607 threshold -= conshdlrdata->roundingoffset )
4608 {
4609 SCIP_Real value = 0.0;
4610 int size = 0;
4611 int nCuts = 0;
4612 int j;
4613#ifdef SCIP_DEBUG
4614 int nvarsone = 0;
4615 int nvarszero = 0;
4616 int nvarsfrac = 0;
4617#endif
4618
4619 SCIPdebugMsg(scip, "Threshold: %g.\n", threshold);
4620
4621 /* choose variables that have a value < current threshold value */
4622 for (j = 0; j < nconss; ++j)
4623 {
4624 SCIP_CONSDATA* consdata;
4625 SCIP_Real binvarval;
4626 SCIP_VAR* binvarneg;
4627
4628 assert( conss[j] != NULL );
4629 consdata = SCIPconsGetData(conss[j]);
4630 assert( consdata != NULL );
4631
4632 binvarval = SCIPgetVarSol(scip, consdata->binvar);
4633
4634#ifdef SCIP_DEBUG
4635 if ( SCIPisFeasEQ(scip, binvarval, 1.0) )
4636 ++nvarsone;
4637 else if ( SCIPisFeasZero(scip, binvarval) )
4638 ++nvarszero;
4639 else
4640 ++nvarsfrac;
4641#endif
4642
4643 /* check whether complementary (negated) variable is present as well */
4644 binvarneg = SCIPvarGetNegatedVar(consdata->binvar);
4645 assert( binvarneg != NULL );
4646
4647 /* negated variable is present as well */
4648 assert( conshdlrdata->binvarhash != NULL );
4649 if ( SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarneg) )
4650 {
4651 SCIP_Real binvarnegval = SCIPgetVarSol(scip, binvarneg);
4652
4653 /* take larger one */
4654 if ( binvarval > binvarnegval )
4655 S[j] = TRUE;
4656 else
4657 S[j] = FALSE;
4658 continue;
4659 }
4660
4661 /* check for threshold */
4662 if ( SCIPisFeasLT(scip, SCIPgetVarSol(scip, consdata->binvar), threshold) )
4663 {
4664 S[j] = TRUE;
4665 value += varGetObjDelta(consdata->binvar);
4666 ++size;
4667 }
4668 else
4669 S[j] = FALSE;
4670 }
4671
4672 if ( size == nconss )
4673 {
4674 SCIPdebugMsg(scip, "All variables in the set. Continue ...\n");
4675 continue;
4676 }
4677
4678 /* skip computation if size has not changed (computation is likely the same) */
4679 if ( size == oldsize )
4680 {
4681 SCIPdebugMsg(scip, "Skipping computation: size support has not changed.\n");
4682 continue;
4683 }
4684 oldsize = size;
4685
4686#ifdef SCIP_DEBUG
4687 SCIPdebugMsg(scip, " Vars with value 1: %d 0: %d and fractional: %d.\n", nvarsone, nvarszero, nvarsfrac);
4688#endif
4689
4690 /* fix the variables in S */
4691 SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
4692
4693 /* extend set S to a cover and generate cuts */
4694 SCIP_CALL( extendToCover(scip, conshdlr, conshdlrdata, lp, sol, enfosepatype, conshdlrdata->removable, conshdlrdata->genlogicor,
4695 nconss, conss, S, &size, &value, &error, cutoff, &nCuts) );
4696
4697 /* we ignore errors in extendToCover */
4698 if ( nCuts > 0 )
4699 {
4700 *nGen += nCuts;
4701 ++rounds;
4702 }
4703 else
4704 {
4705 /* possibly update upper bound */
4706 SCIP_CALL( updateObjUpperbound(scip, conshdlr, conshdlrdata) );
4707 }
4708
4709 /* reset bounds */
4710 SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
4711 }
4712 SCIPdebug( SCIPdebugMsg(scip, "Generated %d IISs.\n", *nGen - nGenOld); )
4713
4714#ifndef NDEBUG
4715 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
4716#endif
4717
4719
4720 return SCIP_OKAY;
4721}
4722
4723
4724
4725/** separate cuts based on perspective formulation
4726 *
4727 * Hijazi, Bonami, and Ouorou (2014) introduced the following cuts: We consider an indicator constraint
4728 * \f[
4729 * y = 1 \rightarrow \alpha^T x \leq \beta
4730 * \f]
4731 * and assume finite bounds \f$\ell \leq x \leq u\f$. Then for \f$I \subseteq \{1, \dots, n\}\f$ define
4732 * \f[
4733 * \Sigma(I,x,y) = \sum_{i \notin I} \alpha_i x_i +
4734 * y \Big(\sum_{i \in I, \alpha_i < 0} \alpha_i u_i + \sum_{i \in I, \alpha_i > 0} \alpha_i \ell_i +
4735 * \sum_{i \notin I, \alpha_i < 0} \alpha_i \ell_i + \sum_{i \notin I, \alpha_i > 0} \alpha_i u_i - \beta\Big).
4736 * \f]
4737 * Then the cuts
4738 * \f[
4739 * \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
4740 * \f]
4741 * are valid for the disjunction
4742 * \f[
4743 * \{y = 0,\; \ell \leq x \leq u\} \cup \{y = 1,\; \ell \leq x \leq u,\; \alpha^T x \leq \beta\}.
4744 * \f]
4745 * 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
4746 * \f[
4747 * y^*(\alpha_i\, u_i\, [\alpha_i < 0] + \alpha_i\, \ell_i\, [\alpha_i > 0]) >
4748 * \alpha_i x_i^* + y^* )\alpha_i \ell_i [\alpha_i < 0] + \alpha_i u_i [\alpha_i > 0]),
4749 * \f]
4750 * where \f$[C] = 1\f$ if condition \f$C\f$ is satisfied, otherwise it is 0.
4751 * If the above inequality holds, \f$i\f$ is included in \f$I\f$, otherwise not.
4752 */
4753static
4755 SCIP* scip, /**< SCIP pointer */
4756 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4757 SCIP_SOL* sol, /**< solution to be separated */
4758 int nconss, /**< number of constraints */
4759 SCIP_CONS** conss, /**< indicator constraints */
4760 int maxsepacuts, /**< maximal number of cuts to be generated */
4761 int* nGen /**< number of generated cuts */
4762 )
4763{ /*lint --e{850}*/
4764 SCIP_CONSHDLRDATA* conshdlrdata;
4765 SCIP_VAR** cutvars;
4766 SCIP_Real* cutvals;
4767 int nvars;
4768 int c;
4769
4770 assert( scip != NULL );
4771 assert( conshdlr != NULL );
4772 assert( conss != NULL );
4773 assert( nGen != NULL );
4774
4775 if ( *nGen >= maxsepacuts )
4776 return SCIP_OKAY;
4777
4778 nvars = SCIPgetNVars(scip);
4779 SCIP_CALL( SCIPallocBufferArray(scip, &cutvars, nvars+1) );
4780 SCIP_CALL( SCIPallocBufferArray(scip, &cutvals, nvars+1) );
4781
4782 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4783 assert( conshdlrdata != NULL );
4784
4785 /* loop through constraints */
4786 for (c = 0; c < nconss; ++c)
4787 {
4788 SCIP_CONSDATA* consdata;
4789 SCIP_CONS* lincons;
4790 SCIP_VAR* slackvar;
4791 SCIP_VAR* binvar;
4792 SCIP_Real binval;
4793
4794 assert( conss[c] != NULL );
4795 consdata = SCIPconsGetData(conss[c]);
4796 assert( consdata != NULL );
4797 slackvar = consdata->slackvar;
4798
4799 lincons = consdata->lincons;
4800 assert( lincons != NULL );
4801
4802 binvar = consdata->binvar;
4803 assert( binvar != NULL );
4804 binval = SCIPgetSolVal(scip, sol, binvar);
4805
4806 if ( SCIPconsIsActive(lincons) )
4807 {
4808 SCIP_VAR** linvars;
4809 SCIP_Real* linvals;
4810 SCIP_Real linrhs;
4811 SCIP_Bool finitebound = TRUE;
4812 SCIP_Real cutrhs = 0.0;
4813 SCIP_Real cutval;
4814 SCIP_Real signfactor = 1.0;
4815 SCIP_Real ypart;
4816 SCIP_Bool islocal = FALSE;
4817 int nlinvars;
4818 int cnt = 0;
4819 int j;
4820
4821 linvars = SCIPgetVarsLinear(scip, lincons);
4822 linvals = SCIPgetValsLinear(scip, lincons);
4823 nlinvars = SCIPgetNVarsLinear(scip, lincons);
4824
4825 linrhs = SCIPgetRhsLinear(scip, lincons);
4826 if ( SCIPisInfinity(scip, linrhs) )
4827 {
4828 if ( ! SCIPisInfinity(scip, SCIPgetLhsLinear(scip, lincons)) )
4829 {
4830 linrhs = -SCIPgetLhsLinear(scip, lincons);
4831 signfactor = -1.0;
4832 }
4833 else
4834 continue;
4835 }
4836 ypart = -linrhs;
4837 cutval = binval * ypart;
4838
4839 for (j = 0; j < nlinvars; ++j)
4840 {
4841 SCIP_Real linval;
4842 SCIP_Real lb;
4843 SCIP_Real ub;
4844 SCIP_Real din = 0.0;
4845 SCIP_Real dout = 0.0;
4846 SCIP_Real xpart;
4847 SCIP_Real xval;
4848
4849 if ( linvars[j] == slackvar )
4850 continue;
4851
4852 if ( conshdlrdata->sepapersplocal )
4853 {
4854 lb = SCIPvarGetLbLocal(linvars[j]);
4855 ub = SCIPvarGetUbLocal(linvars[j]);
4856
4857 if ( lb > SCIPvarGetLbGlobal(linvars[j]) )
4858 islocal = TRUE;
4859 if ( ub < SCIPvarGetUbGlobal(linvars[j]) )
4860 islocal = TRUE;
4861 }
4862 else
4863 {
4864 lb = SCIPvarGetLbGlobal(linvars[j]);
4865 ub = SCIPvarGetUbGlobal(linvars[j]);
4866 }
4867
4868 /* skip cases with unbounded variables */
4869 if ( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
4870 {
4871 finitebound = FALSE;
4872 break;
4873 }
4874
4875 /* compute rest parts for i in the set (din) or not in the set (dout) */
4876 linval = signfactor * linvals[j];
4877 if ( SCIPisNegative(scip, linval) )
4878 {
4879 din += linval * ub;
4880 dout += linval * lb;
4881 }
4882 else if ( SCIPisPositive(scip, linval) )
4883 {
4884 din += linval * lb;
4885 dout += linval * ub;
4886 }
4887
4888 xval = SCIPgetSolVal(scip, sol, linvars[j]);
4889 xpart = linval * xval;
4890
4891 /* if din > dout, we want to include i in the set */
4892 if ( SCIPisGT(scip, binval * din, binval * dout + xpart) )
4893 {
4894 ypart += din;
4895 cutval += binval * din;
4896 }
4897 else
4898 {
4899 /* otherwise i is not in the set */
4900 ypart += dout;
4901
4902 cutrhs += dout;
4903 cutval += binval * dout + xpart;
4904
4905 cutvars[cnt] = linvars[j];
4906 cutvals[cnt++] = linval;
4907 }
4908 }
4909
4910 if ( ! finitebound )
4911 continue;
4912
4913 if ( SCIPisEfficacious(scip, cutval - cutrhs) )
4914 {
4915 SCIP_ROW* row;
4916 SCIP_Bool infeasible;
4917 char name[50];
4918
4919 /* add y-variable */
4920 cutvars[cnt] = binvar;
4921 cutvals[cnt] = ypart;
4922 ++cnt;
4923
4924 SCIPdebugMsg(scip, "Found cut of lhs value %f > %f.\n", cutval, cutrhs);
4925 (void) SCIPsnprintf(name, 50, "persp%d", conshdlrdata->nperspcutsgen + *nGen);
4926 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), cutrhs, islocal, FALSE, conshdlrdata->removable) );
4927 SCIP_CALL( SCIPaddVarsToRow(scip, row, cnt, cutvars, cutvals) );
4928#ifdef SCIP_OUTPUT
4929 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
4930#endif
4931 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
4932 assert( ! infeasible );
4933 SCIP_CALL( SCIPreleaseRow(scip, &row));
4934 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
4935 ++(*nGen);
4936 }
4937 }
4938 if ( *nGen >= maxsepacuts )
4939 break;
4940 }
4941
4942 SCIPfreeBufferArray(scip, &cutvals);
4943 SCIPfreeBufferArray(scip, &cutvars);
4944
4945 return SCIP_OKAY;
4946}
4947
4948
4949/** separation method
4950 *
4951 * We first check whether coupling inequalities can be separated (if required). If not enough of
4952 * these could be generated, we check whether IIS inequalities can be separated.
4953 */
4954static
4956 SCIP* scip, /**< SCIP pointer */
4957 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4958 int nconss, /**< number of constraints */
4959 int nusefulconss, /**< number of useful constraints */
4960 SCIP_CONS** conss, /**< indicator constraints */
4961 SCIP_SOL* sol, /**< solution to be separated */
4962 SCIP_ENFOSEPATYPE enfosepatype, /**< type of enforcing/separating type */
4963 SCIP_RESULT* result /**< result */
4964 )
4965{
4966 SCIP_CONSHDLRDATA* conshdlrdata;
4967 int maxsepacuts;
4968 int ncuts;
4969
4970 assert( scip != NULL );
4971 assert( conshdlr != NULL );
4972 assert( conss != NULL );
4973 assert( result != NULL );
4974
4975 *result = SCIP_DIDNOTRUN;
4976
4977 if ( nconss == 0 )
4978 return SCIP_OKAY;
4979
4980 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4981 assert( conshdlrdata != NULL );
4982 ncuts = 0;
4983
4984 /* get the maximal number of cuts allowed in a separation round */
4985 if ( SCIPgetDepth(scip) == 0 )
4986 maxsepacuts = conshdlrdata->maxsepacutsroot;
4987 else
4988 maxsepacuts = conshdlrdata->maxsepacuts;
4989
4990 /* first separate coupling inequalities (if required) */
4991 if ( conshdlrdata->sepacouplingcuts )
4992 {
4993 int c;
4994
4995 *result = SCIP_DIDNOTFIND;
4996
4997 /* check each constraint */
4998 for (c = 0; c < nusefulconss && ncuts < maxsepacuts; ++c)
4999 {
5000 SCIP_CONSDATA* consdata;
5001 SCIP_Bool islocal;
5002 SCIP_Real ub;
5003
5004 assert( conss != NULL );
5005 assert( conss[c] != NULL );
5006 consdata = SCIPconsGetData(conss[c]);
5007 assert( consdata != NULL );
5008 assert( consdata->slackvar != NULL );
5009 assert( consdata->binvar != NULL );
5010
5011 /* get upper bound for slack variable in linear constraint */
5012 islocal = FALSE;
5013 if ( conshdlrdata->sepacouplinglocal )
5014 {
5015 ub = SCIPvarGetUbLocal(consdata->slackvar);
5016 if ( ub < SCIPvarGetUbGlobal(consdata->slackvar) )
5017 islocal = TRUE;
5018 }
5019 else
5020 ub = SCIPvarGetUbGlobal(consdata->slackvar);
5021 assert( ! SCIPisFeasNegative(scip, ub) );
5022
5023 /* only use coefficients that are not too large */
5024 if ( ub <= conshdlrdata->sepacouplingvalue )
5025 {
5026 SCIP_Real activity;
5027
5028 activity = SCIPgetSolVal(scip, sol, consdata->slackvar) + ub * SCIPgetSolVal(scip, sol, consdata->binvar) - ub;
5029 if ( SCIPisEfficacious(scip, activity) )
5030 {
5031 SCIP_ROW* row;
5032 SCIP_Bool infeasible;
5033#ifndef NDEBUG
5034 char name[50];
5035
5036 (void) SCIPsnprintf(name, 50, "couple%d", c);
5037 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
5038#else
5039 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], "", -SCIPinfinity(scip), ub, islocal, FALSE, conshdlrdata->removable) );
5040#endif
5042
5043 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
5044 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
5046
5047 SCIPdebugMsg(scip, "Separated coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
5048#ifdef SCIP_OUTPUT
5049 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
5050#endif
5051 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
5052 assert( ! infeasible );
5053 SCIP_CALL( SCIPreleaseRow(scip, &row));
5054
5055 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
5056 *result = SCIP_SEPARATED;
5057
5058 ++ncuts;
5059 }
5060 }
5061 }
5062 SCIPdebugMsg(scip, "Number of separated coupling inequalities: %d.\n", ncuts);
5063 }
5064
5065 /* separate cuts from the alternative lp (if required) */
5066 if ( conshdlrdata->sepaalternativelp && ncuts < SEPAALTTHRESHOLD )
5067 {
5068 SCIP_Bool cutoff;
5069 int noldcuts;
5070
5071 SCIPdebugMsg(scip, "Separating inequalities for indicator constraints.\n");
5072
5073 noldcuts = ncuts;
5074 if ( *result == SCIP_DIDNOTRUN )
5075 *result = SCIP_DIDNOTFIND;
5076
5077 /* start separation */
5078 SCIP_CALL( separateIISRounding(scip, conshdlr, sol, enfosepatype, nconss, conss, maxsepacuts, &cutoff, &ncuts) );
5079 SCIPdebugMsg(scip, "Separated %d cuts from indicator constraints.\n", ncuts - noldcuts);
5080
5081 if ( cutoff )
5082 *result = SCIP_CUTOFF;
5083 else if ( ncuts > noldcuts )
5084 {
5085 conshdlrdata->niiscutsgen += ncuts;
5086
5087 /* possibly overwrite result from separation above */
5088 if ( conshdlrdata->genlogicor )
5089 *result = SCIP_CONSADDED;
5090 else
5091 *result = SCIP_SEPARATED;
5092 }
5093 }
5094
5095 /* separate cuts based on perspective formulation */
5096 if ( conshdlrdata->sepaperspective && ncuts < SEPAALTTHRESHOLD )
5097 {
5098 int noldcuts;
5099
5100 SCIPdebugMsg(scip, "Separating inequalities based on perspective formulation.\n");
5101
5102 noldcuts = ncuts;
5103 if ( *result == SCIP_DIDNOTRUN )
5104 *result = SCIP_DIDNOTFIND;
5105
5106 /* start separation */
5107 SCIP_CALL( separatePerspective(scip, conshdlr, sol, nconss, conss, maxsepacuts, &ncuts) );
5108 SCIPdebugMsg(scip, "Separated %d cuts from perspective formulation.\n", ncuts - noldcuts);
5109
5110 if ( ncuts > noldcuts )
5111 {
5112 conshdlrdata->nperspcutsgen += ncuts;
5113
5114 /* possibly overwrite result from separation above */
5115 *result = SCIP_SEPARATED;
5116 }
5117 }
5118
5119 return SCIP_OKAY;
5120}
5121
5122
5123/** initializes the constraint handler data */
5124static
5126 SCIP* scip, /**< SCIP pointer */
5127 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
5128 )
5129{
5130 assert( conshdlrdata != NULL );
5131
5132 conshdlrdata->linconsevents = FALSE;
5133 conshdlrdata->linconsboundschanged = TRUE;
5134 conshdlrdata->boundhaschanged = TRUE;
5135 conshdlrdata->removable = TRUE;
5136 conshdlrdata->scaled = FALSE;
5137 conshdlrdata->altlp = NULL;
5138 conshdlrdata->nrows = 0;
5139 conshdlrdata->varhash = NULL;
5140 conshdlrdata->slackhash = NULL;
5141 conshdlrdata->lbhash = NULL;
5142 conshdlrdata->ubhash = NULL;
5143 conshdlrdata->nlbbounds = 0;
5144 conshdlrdata->nubbounds = 0;
5145 conshdlrdata->nslackvars = 0;
5146 conshdlrdata->objcutindex = -1;
5147 conshdlrdata->objupperbound = SCIPinfinity(scip);
5148 conshdlrdata->objaltlpbound = SCIPinfinity(scip);
5149 conshdlrdata->roundingminthres = 0.1;
5150 conshdlrdata->roundingmaxthres = 0.6;
5151 conshdlrdata->maxroundingrounds = MAXROUNDINGROUNDS;
5152 conshdlrdata->roundingoffset = 0.1;
5153 conshdlrdata->addedcouplingcons = FALSE;
5154 conshdlrdata->ninitconss = 0;
5155 conshdlrdata->nbinvarszero = 0;
5156 conshdlrdata->performedrestart = FALSE;
5157 conshdlrdata->objindicatoronly = FALSE;
5158 conshdlrdata->objothervarsonly = FALSE;
5159 conshdlrdata->minabsobj = 0.0;
5160 conshdlrdata->normtype = 'e';
5161 conshdlrdata->niiscutsgen = 0;
5162 conshdlrdata->nperspcutsgen = 0;
5163}
5164
5165
5166/* ---------------------------- upgrading methods -----------------------------------*/
5167
5168/** tries to upgrade a linear constraint into an indicator constraint
5169 *
5170 * 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
5171 * it to an indicator constraint if for the residual value \f$a^T x \geq \gamma\f$, we have \f$\alpha + \gamma \geq
5172 * \beta\f$: in this case, the constraint is always satisfied if \f$y = 1\f$.
5173 *
5174 * 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
5175 * upgrade it to an indicator constraint if for the residual value \f$a^T x \leq \gamma\f$, we have \f$\alpha + \gamma
5176 * \leq \beta\f$.
5177 */
5178static
5179SCIP_DECL_LINCONSUPGD(linconsUpgdIndicator)
5180{ /*lint --e{715}*/
5181 SCIP_CONSHDLRDATA* conshdlrdata;
5182 SCIP_CONSHDLR* conshdlr;
5183 SCIP_Real minactivity = 0.0;
5184 SCIP_Real maxactivity = 0.0;
5185 SCIP_Real maxabsval = -1.0;
5186 SCIP_Real secabsval = -1.0;
5187 int maxabsvalidx = -1;
5188 int j;
5189
5190 assert( scip != NULL );
5191 assert( upgdcons != NULL );
5192 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0 );
5193 assert( ! SCIPconsIsModifiable(cons) );
5194
5195 /* do not upgrade if there are at most 2 variables (2 variables should be upgraded to a varbound constraint) */
5196 if ( nvars <= 2 )
5197 return SCIP_OKAY;
5198
5199 /* cannot currently ranged constraints, since we can only return one constraint (and we would need one for each side each) */
5200 if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
5201 return SCIP_OKAY;
5202
5203 /* check whether upgrading is turned on */
5204 conshdlr = SCIPfindConshdlr(scip, "indicator");
5205 assert( conshdlr != NULL );
5206 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5207 assert( conshdlrdata != NULL );
5208
5209 if ( ! conshdlrdata->upgradelinear )
5210 return SCIP_OKAY;
5211
5212 /* calculate activities */
5213 for (j = 0; j < nvars; ++j)
5214 {
5215 SCIP_VAR* var;
5216 SCIP_Real val;
5217 SCIP_Real lb;
5218 SCIP_Real ub;
5219
5220 val = vals[j];
5221 assert( ! SCIPisZero(scip, val) );
5222
5223 var = vars[j];
5224 assert( var != NULL );
5225
5226 /* store maximal (and second to largest) value of coefficients */
5227 if ( SCIPisGE(scip, REALABS(val), maxabsval) )
5228 {
5229 secabsval = maxabsval;
5230 maxabsval = REALABS(val);
5231 maxabsvalidx = j;
5232 }
5233
5234 if ( ! SCIPvarIsBinary(var) )
5235 {
5236 if ( val > 0.0 )
5237 {
5238 lb = SCIPvarGetLbGlobal(var);
5239 ub = SCIPvarGetUbGlobal(var);
5240 }
5241 else
5242 {
5243 ub = SCIPvarGetLbGlobal(var);
5244 lb = SCIPvarGetUbGlobal(var);
5245 }
5246
5247 /* compute minimal activity */
5248 if ( SCIPisInfinity(scip, -lb) )
5249 minactivity = -SCIPinfinity(scip);
5250 else
5251 {
5252 if ( ! SCIPisInfinity(scip, -minactivity) )
5253 minactivity += val * lb;
5254 }
5255
5256 /* compute maximal activity */
5257 if ( SCIPisInfinity(scip, ub) )
5258 maxactivity = SCIPinfinity(scip);
5259 else
5260 {
5261 if ( ! SCIPisInfinity(scip, maxactivity) )
5262 maxactivity += val * ub;
5263 }
5264 }
5265 }
5266 assert( maxabsval >= 0.0 );
5267 assert( 0 <= maxabsvalidx && maxabsvalidx < nvars );
5268
5269 /* exit if largest coefficient does not belong to binary variable */
5270 if ( ! SCIPvarIsBinary(vars[maxabsvalidx]) )
5271 return SCIP_OKAY;
5272
5273 /* exit if the second largest coefficient is as large as largest */
5274 if ( SCIPisEQ(scip, secabsval, maxabsval) )
5275 return SCIP_OKAY;
5276
5277 /* cannot upgrade if all activities are infinity */
5278 if ( SCIPisInfinity(scip, -minactivity) && SCIPisInfinity(scip, maxactivity) )
5279 return SCIP_OKAY;
5280
5281 /* check each variable as indicator variable */
5282 for (j = 0; j < nvars; ++j)
5283 {
5284 SCIP_VAR** indconsvars;
5285 SCIP_Real* indconsvals;
5286 SCIP_Bool upgdlhs = FALSE;
5287 SCIP_Bool upgdrhs = FALSE;
5288 SCIP_Bool indneglhs = FALSE;
5289 SCIP_Bool indnegrhs = FALSE;
5290 SCIP_VAR* indvar;
5291 SCIP_Real indval;
5292 int l;
5293
5294 indvar = vars[j];
5295 indval = vals[j];
5296 assert( ! SCIPisZero(scip, indval) );
5297
5298 if ( ! SCIPvarIsBinary(indvar) )
5299 continue;
5300
5301 /* check for upgrading of lhs */
5302 if ( ! SCIPisInfinity(scip, -minactivity) && ! SCIPisInfinity(scip, -lhs) )
5303 {
5304 /* upgrading is possible with binary variable */
5305 if ( SCIPisGE(scip, minactivity, lhs) )
5306 upgdlhs = TRUE;
5307
5308 /* upgrading is possible with negated binary variable */
5309 if ( SCIPisGE(scip, minactivity + indval, lhs) )
5310 {
5311 upgdlhs = TRUE;
5312 indneglhs = TRUE;
5313 }
5314 }
5315
5316 /* check for upgrading of rhs */
5317 if ( ! SCIPisInfinity(scip, maxactivity) && ! SCIPisInfinity(scip, rhs) )
5318 {
5319 /* upgrading is possible with binary variable */
5320 if ( SCIPisLE(scip, maxactivity, rhs) )
5321 upgdrhs = TRUE;
5322
5323 /* upgrading is possible with negated binary variable */
5324 if ( SCIPisLE(scip, maxactivity + indval, rhs) )
5325 {
5326 upgdrhs = TRUE;
5327 indnegrhs = TRUE;
5328 }
5329 }
5330
5331 /* upgrade constraint */
5332 if ( upgdlhs || upgdrhs )
5333 {
5334 SCIP_VAR* indvar2;
5335 SCIP_Real bnd;
5336 int cnt = 0;
5337
5338 assert( ! upgdlhs || ! upgdrhs ); /* cannot treat ranged rows */
5339 SCIPdebugMsg(scip, "upgrading constraint <%s> to an indicator constraint.\n", SCIPconsGetName(cons));
5340
5341 SCIP_CALL( SCIPallocBufferArray(scip, &indconsvars, nvars - 1) );
5342 SCIP_CALL( SCIPallocBufferArray(scip, &indconsvals, nvars - 1) );
5343
5344 /* create constraint */
5345 for (l = 0; l < nvars; ++l)
5346 {
5347 if ( vars[l] == indvar )
5348 continue;
5349 indconsvars[cnt] = vars[l];
5350 if ( upgdlhs )
5351 indconsvals[cnt] = -vals[l];
5352 else
5353 indconsvals[cnt] = vals[l];
5354 ++cnt;
5355 }
5356
5357 if ( indneglhs || indnegrhs )
5358 {
5359 SCIP_CALL( SCIPgetNegatedVar(scip, indvar, &indvar2) );
5360 }
5361 else
5362 indvar2 = indvar;
5363
5364 if ( upgdlhs )
5365 {
5366 bnd = -lhs;
5367 if ( ! indneglhs )
5368 bnd -= indval;
5369 SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
5372 }
5373 else
5374 {
5375 bnd = rhs;
5376 if ( ! indnegrhs )
5377 bnd -= indval;
5378 SCIP_CALL( SCIPcreateConsIndicator(scip, upgdcons, SCIPconsGetName(cons), indvar2, nvars-1, indconsvars, indconsvals, bnd,
5381 }
5382
5383#ifdef SCIP_DEBUG
5384 SCIPinfoMessage(scip, NULL, "upgrade: \n");
5385 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
5386 SCIPinfoMessage(scip, NULL, "\n");
5387 SCIP_CALL( SCIPprintCons(scip, *upgdcons, NULL) );
5388 SCIPinfoMessage(scip, NULL, "\n");
5390 SCIPinfoMessage(scip, NULL, " (minact: %f, maxact: %f)\n", minactivity, maxactivity);
5391#endif
5392
5393 SCIPfreeBufferArray(scip, &indconsvars);
5394 SCIPfreeBufferArray(scip, &indconsvals);
5395
5396 return SCIP_OKAY;
5397 }
5398 }
5399
5400 return SCIP_OKAY;
5401}
5402
5403
5404/* ---------------------------- constraint handler callback methods ----------------------*/
5405
5406/** copy method for constraint handler plugins (called when SCIP copies plugins) */
5407static
5408SCIP_DECL_CONSHDLRCOPY(conshdlrCopyIndicator)
5409{ /*lint --e{715}*/
5410 assert( scip != NULL );
5411 assert( conshdlr != NULL );
5412 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5413 assert( valid != NULL );
5414
5415 /* call inclusion method of constraint handler */
5417
5418 *valid = TRUE;
5419
5420 return SCIP_OKAY;
5421}
5422
5423
5424/** initialization method of constraint handler (called after problem was transformed) */
5425static
5426SCIP_DECL_CONSINIT(consInitIndicator)
5427{ /*lint --e{715}*/
5428 SCIP_CONSHDLRDATA* conshdlrdata;
5429
5430 assert( scip != NULL );
5431 assert( conshdlr != NULL );
5432 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5433
5434 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5435 assert( conshdlrdata != NULL );
5436
5437 initConshdlrData(scip, conshdlrdata);
5438
5439 /* find trysol heuristic */
5440 if ( conshdlrdata->trysolutions && conshdlrdata->heurtrysol == NULL )
5441 {
5442 conshdlrdata->heurtrysol = SCIPfindHeur(scip, "trysol");
5443 }
5444
5445 return SCIP_OKAY;
5446}
5447
5448
5449/** deinitialization method of constraint handler (called before transformed problem is freed) */
5450static
5451SCIP_DECL_CONSEXIT(consExitIndicator)
5452{ /*lint --e{715}*/
5453 SCIP_CONSHDLRDATA* conshdlrdata;
5454 SCIP_CONSDATA* consdata;
5455 int i;
5456 int j;
5457
5458 assert( scip != NULL );
5459 assert( conshdlr != NULL );
5460 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5461
5462 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5463
5464 if ( conshdlrdata->binvarhash != NULL )
5465 SCIPhashmapFree(&conshdlrdata->binvarhash);
5466
5467 if ( conshdlrdata->binslackvarhash != NULL )
5468 SCIPhashmapFree(&conshdlrdata->binslackvarhash);
5469
5470 /* drop bound change events on variables of linear constraints */
5471 for (i = 0; i < nconss; i++)
5472 {
5473 consdata = SCIPconsGetData(conss[i]);
5474 assert( consdata != NULL );
5475
5476 if ( consdata->varswithevents != NULL )
5477 {
5478 assert( consdata->eventtypes != NULL );
5479 assert( consdata->lincons != NULL );
5480
5481 for (j = 0; j < consdata->nevents; ++j)
5482 {
5483 SCIP_CALL( SCIPdropVarEvent(scip, consdata->varswithevents[j], consdata->eventtypes[j], conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, -1) );
5484 }
5485 SCIPfreeBlockMemoryArray(scip, &consdata->varswithevents, consdata->nevents);
5486 SCIPfreeBlockMemoryArray(scip, &consdata->eventtypes, consdata->nevents);
5487
5488 consdata->nevents = 0;
5489 assert( consdata->varswithevents == NULL );
5490 assert( consdata->eventtypes == NULL );
5491 }
5492 }
5493
5494 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
5495 conshdlrdata->maxaddlincons = 0;
5496 conshdlrdata->naddlincons = 0;
5497 conshdlrdata->nrows = 0;
5498
5499 return SCIP_OKAY;
5500}
5501
5502
5503/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
5504static
5505SCIP_DECL_CONSFREE(consFreeIndicator)
5506{
5507 SCIP_CONSHDLRDATA* conshdlrdata;
5508
5509 assert( scip != NULL );
5510 assert( conshdlr != NULL );
5511 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5512
5513 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5514 assert( conshdlrdata != NULL );
5515 assert( conshdlrdata->altlp == NULL );
5516 assert( conshdlrdata->varhash == NULL );
5517 assert( conshdlrdata->lbhash == NULL );
5518 assert( conshdlrdata->ubhash == NULL );
5519 assert( conshdlrdata->slackhash == NULL );
5520
5521 if ( conshdlrdata->maxaddlincons > 0 )
5522 {
5523 /* if problem was not yet transformed the array may need to be freed, because we did not call the EXIT callback */
5524 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->addlincons, conshdlrdata->maxaddlincons);
5525 }
5526 assert( conshdlrdata->addlincons == NULL );
5527 conshdlrdata->naddlincons = 0;
5528 conshdlrdata->maxaddlincons = 0;
5529
5530 SCIPfreeBlockMemory(scip, &conshdlrdata);
5531
5532 return SCIP_OKAY;
5533}
5534
5535
5536/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
5537static
5538SCIP_DECL_CONSINITSOL(consInitsolIndicator)
5539{
5540 SCIP_CONSHDLRDATA* conshdlrdata;
5541 int c;
5542
5543 assert( scip != NULL );
5544 assert( conshdlr != NULL );
5545 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5546
5549 return SCIP_OKAY;
5550
5551 SCIPdebugMsg(scip, "Initsol for indicator constraints.\n");
5552
5553 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5554 assert( conshdlrdata != NULL );
5555 assert( conshdlrdata->slackhash == NULL );
5556
5557 conshdlrdata->boundhaschanged = TRUE; /* make sure that we propagate at the beginning */
5558
5559 SCIP_CALL( SCIPgetCharParam(scip, "separating/efficacynorm", &conshdlrdata->normtype) );
5560
5561 if ( conshdlrdata->sepaalternativelp )
5562 {
5563 /* generate hash for storing all slack variables (size is just a guess) */
5564 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->slackhash, SCIPblkmem(scip), SCIPgetNVars(scip)) );
5565 assert( conshdlrdata->slackhash != NULL );
5566
5567 /* first initialize slack hash */
5568 for (c = 0; c < nconss; ++c)
5569 {
5570 SCIP_CONSDATA* consdata;
5571
5572 assert( conss != NULL );
5573 assert( conss[c] != NULL );
5574 assert( SCIPconsIsTransformed(conss[c]) );
5575
5576 consdata = SCIPconsGetData(conss[c]);
5577 assert( consdata != NULL );
5578
5579 assert( consdata->slackvar != NULL );
5580
5581 /* insert slack variable into hash */
5582 SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->slackhash, consdata->slackvar, INT_MAX) );
5583 assert( SCIPhashmapExists(conshdlrdata->slackhash, consdata->slackvar) );
5584 ++conshdlrdata->nslackvars;
5585 }
5586
5587 if ( conshdlrdata->genlogicor )
5588 {
5589 SCIP_CONSHDLR* logicorconshdlr;
5590 int logicorsepafreq;
5591 int sepafreq;
5592
5593 /* If we generate logicor constraints, but the separation frequency is not 1, output warning */
5594 logicorconshdlr = SCIPfindConshdlr(scip, "logicor");
5595 if ( logicorconshdlr == NULL )
5596 {
5597 SCIPerrorMessage("Logicor constraint handler not included, cannot generate constraints.\n");
5598 return SCIP_ERROR;
5599 }
5600 logicorsepafreq = SCIPconshdlrGetSepaFreq(logicorconshdlr);
5601 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
5602 if ( (sepafreq != -1 || conshdlrdata->enforcecuts) && logicorsepafreq != 1 )
5603 {
5604 SCIPwarningMessage(scip, "For better performance set parameter 'constraints/logicor/sepafreq' to 1 if 'constraints/included/genlogicor' is true.\n");
5605 }
5606 }
5607 }
5608
5609 /* check each constraint */
5610 conshdlrdata->objothervarsonly = TRUE;
5611 for (c = 0; c < nconss; ++c)
5612 {
5613 SCIP_CONSDATA* consdata;
5614
5615 assert( conss != NULL );
5616 assert( conss[c] != NULL );
5617 assert( SCIPconsIsTransformed(conss[c]) );
5618
5619 consdata = SCIPconsGetData(conss[c]);
5620 assert( consdata != NULL );
5621 assert( consdata->binvar != NULL );
5622 assert( consdata->slackvar != NULL );
5623
5624 /* Presolving might replace a slack variable by an active variable. Thus, the objective of a slack variables might
5625 * be nonzero. However, we do not need to check slack variables here. */
5626 if ( ! SCIPisZero(scip, varGetObjDelta(consdata->binvar)) )
5627 conshdlrdata->objothervarsonly = FALSE;
5628
5629 /* deactivate */
5630 if ( ! consdata->linconsactive )
5631 {
5632 SCIP_CALL( SCIPdisableCons(scip, consdata->lincons) );
5633 }
5634 else
5635 {
5636 /* add constraint to alternative LP if not already done */
5637 if ( conshdlrdata->sepaalternativelp && consdata->colindex < 0 )
5638 {
5639 SCIP_CALL( addAltLPConstraint(scip, conshdlr, consdata->lincons, consdata->slackvar, 1.0, &consdata->colindex) );
5640 SCIPdebugMsg(scip, "Added column for <%s> to alternative LP with column index %d.\n", SCIPconsGetName(conss[c]),consdata->colindex);
5641#ifdef SCIP_OUTPUT
5642 SCIP_CALL( SCIPprintCons(scip, consdata->lincons, NULL) );
5643 SCIPinfoMessage(scip, NULL, ";\n");
5644#endif
5645 }
5646 }
5647
5648 /* add nlrow representation to NLP, if NLP had been constructed
5649 *
5650 * Note, that we did not tell SCIP in exitpre that we have something to add to the NLP, thus
5651 * indicators are only available in the NLP for MINLPs, but not for MIPs with indicators.
5652 */
5653 if ( SCIPisNLPConstructed(scip) && SCIPconsIsChecked(conss[c]) )
5654 {
5655 /* create nonlinear row binary variable * slack variable = 0 */
5656 SCIP_NLROW* nlrow;
5657 SCIP_EXPR* quadexpr;
5658 SCIP_EXPR* varexprs[2];
5659
5660 SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[0], consdata->binvar, NULL, NULL) );
5661 SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[1], consdata->slackvar, NULL, NULL) );
5662 SCIP_CALL( SCIPcreateExprProduct(scip, &quadexpr, 2, varexprs, 1.0, NULL, NULL) );
5663
5664 SCIP_CALL( SCIPcreateNlRow(scip, &nlrow, SCIPconsGetName(conss[c]), 0.0, 0, NULL, NULL, quadexpr, 0.0, 0.0, SCIP_EXPRCURV_UNKNOWN) );
5665
5666 SCIP_CALL( SCIPreleaseExpr(scip, &quadexpr) );
5667 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[1]) );
5668 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[0]) );
5669
5670 /* add row to NLP and forget about it */
5671 SCIP_CALL( SCIPaddNlRow(scip, nlrow) );
5672 SCIP_CALL( SCIPreleaseNlRow(scip, &nlrow) );
5673 }
5674 }
5675
5676 SCIPdebugMsg(scip, "Initialized %d indicator constraints.\n", nconss);
5677
5678 /* check additional constraints */
5679 if ( conshdlrdata->sepaalternativelp )
5680 {
5681 SCIP_CONS* cons;
5682 int colindex;
5683 int cnt = 0;
5684
5685 /* add stored linear constraints if they exist */
5686 if ( conshdlrdata->naddlincons > 0 )
5687 {
5688 for (c = 0; c < conshdlrdata->naddlincons; ++c)
5689 {
5690 cons = conshdlrdata->addlincons[c];
5691
5692 /* get transformed constraint - since it is needed only here, we do not store the information */
5693 if ( ! SCIPconsIsTransformed(cons) )
5694 {
5695 SCIP_CALL( SCIPgetTransformedCons(scip, conshdlrdata->addlincons[c], &cons) );
5696
5697 /* @todo check when exactly the transformed constraint does not exist - SCIPisActive() does not suffice */
5698 if ( cons == NULL )
5699 continue;
5700 }
5701 SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
5702 ++cnt;
5703
5704#ifdef SCIP_OUTPUT
5705 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
5706 SCIPinfoMessage(scip, NULL, ";\n");
5707#endif
5708 }
5709 SCIPdebugMsg(scip, "Added %d additional columns to alternative LP.\n", cnt);
5710 }
5711 else
5712 {
5713 /* if no stored linear constraints are available, possibly collect other linear constraints; we only use linear
5714 * constraints, since most other constraints involve integral variables, and in this context we will likely
5715 * benefit much more from continuous variables. */
5716 if ( conshdlrdata->useotherconss )
5717 {
5718 const char* conshdlrname;
5719 SCIP_CONS** allconss;
5720 int nallconss;
5721
5722 nallconss = SCIPgetNConss(scip);
5723 allconss = SCIPgetConss(scip);
5724
5725 /* loop through all constraints */
5726 for (c = 0; c < nallconss; ++c)
5727 {
5728 /* get constraint */
5729 cons = allconss[c];
5730 assert( cons != NULL );
5731 assert( SCIPconsIsTransformed(cons) );
5732
5733 /* get constraint handler name */
5734 conshdlrname = SCIPconshdlrGetName(SCIPconsGetHdlr(cons));
5735
5736 /* check type of constraint (only take modifiable linear constraints) */
5737 if ( strcmp(conshdlrname, "linear") == 0 && ! SCIPconsIsModifiable(cons) )
5738 {
5739 /* avoid adding linear constraints that correspond to indicator constraints */
5740 if ( strncmp(SCIPconsGetName(cons), "indlin", 6) != 0 )
5741 {
5742 SCIP_CALL( addAltLPConstraint(scip, conshdlr, cons, NULL, 0.0, &colindex) );
5743 SCIPdebugMsg(scip, "Added column for linear constraint <%s> to alternative LP with column index %d.\n", SCIPconsGetName(cons), colindex);
5744 ++cnt;
5745 }
5746 }
5747 }
5748 SCIPdebugMsg(scip, "Added %d additional columns from linear constraints to alternative LP.\n", cnt);
5749 }
5750 }
5751 }
5752
5753 /* initialize event handler if restart should be forced */
5754 if ( conshdlrdata->forcerestart )
5755 {
5756 SCIP_Bool* covered;
5757 SCIP_VAR** vars;
5758 int nvars;
5759 int j;
5760
5761 assert( conshdlrdata->eventhdlrrestart != NULL );
5762
5763 /* store number of initial constraints */
5764 conshdlrdata->ninitconss = SCIPconshdlrGetNActiveConss(conshdlr);
5765
5766 /* reset number of fixed binary variables */
5767 conshdlrdata->nbinvarszero = 0;
5768
5769 /* loop through variables */
5770 nvars = SCIPgetNVars(scip);
5771 vars = SCIPgetVars(scip);
5772
5773 conshdlrdata->objindicatoronly = FALSE;
5774 conshdlrdata->minabsobj = SCIP_REAL_MAX;
5775
5776 /* unmark all variables */
5777 SCIP_CALL( SCIPallocBufferArray(scip, &covered, nvars) );
5778 for (j = 0; j < nvars; ++j)
5779 covered[j] = FALSE;
5780
5781 /* mark indicator variables */
5782 for (c = 0; c < nconss; ++c)
5783 {
5784 SCIP_CONSDATA* consdata;
5785 int probindex;
5786
5787 assert( conss != NULL );
5788 assert( conss[c] != NULL );
5789
5790 /* avoid non-active indicator constraints */
5791 if ( ! SCIPconsIsActive(conss[c]) )
5792 continue;
5793
5794 consdata = SCIPconsGetData(conss[c]);
5795 assert( consdata != NULL );
5796 assert( consdata->binvar != NULL );
5797
5798 if ( SCIPvarIsNegated(consdata->binvar) )
5799 {
5800 assert( SCIPvarGetNegatedVar(consdata->binvar) != NULL );
5801 probindex = SCIPvarGetProbindex(SCIPvarGetNegatedVar(consdata->binvar));
5802 }
5803 else
5804 probindex = SCIPvarGetProbindex(consdata->binvar);
5805
5806 /* if presolving detected infeasibility it might be that the binary variables are not active */
5807 if ( probindex < 0 )
5808 continue;
5809
5810 assert( 0 <= probindex && probindex < nvars );
5811 covered[probindex] = TRUE;
5812 }
5813
5814 /* check all variables */
5815 for (j = 0; j < nvars; ++j)
5816 {
5817 SCIP_Real obj;
5818
5819 obj = SCIPvarGetObj(vars[j]);
5820 if ( ! SCIPisZero(scip, obj) )
5821 {
5822 if ( ! covered[j] )
5823 break;
5824 if ( ! SCIPisIntegral(scip, obj) )
5825 break;
5826 if ( REALABS(obj) < conshdlrdata->minabsobj )
5827 conshdlrdata->minabsobj = REALABS(obj);
5828 }
5829 }
5830
5831 /* if all variables have integral objective and only indicator variables have nonzero objective */
5832 if ( j >= nvars )
5833 {
5834 /* if there are variables with nonzero objective */
5835 if ( conshdlrdata->minabsobj < SCIP_REAL_MAX )
5836 {
5837 assert( SCIPisIntegral(scip, conshdlrdata->minabsobj) );
5838 assert( SCIPisGE(scip, conshdlrdata->minabsobj, 1.0) );
5839
5840 conshdlrdata->objindicatoronly = TRUE;
5841
5842 assert( conshdlrdata->eventhdlrrestart != NULL );
5843 SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, conshdlrdata->eventhdlrrestart, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
5844 }
5845 }
5846
5847 SCIPfreeBufferArray(scip, &covered);
5848 }
5849
5850 return SCIP_OKAY;
5851}
5852
5853
5854/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
5855static
5856SCIP_DECL_CONSEXITSOL(consExitsolIndicator)
5857{ /*lint --e{715}*/
5858 SCIP_CONSHDLRDATA* conshdlrdata;
5859 int c;
5860
5861 assert( scip != NULL );
5862 assert( conshdlr != NULL );
5863 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5864
5865 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5866 assert( conshdlrdata != NULL );
5867
5868 if ( conshdlrdata->sepaalternativelp )
5869 {
5870 if ( conshdlrdata->slackhash != NULL )
5871 {
5872#ifdef SCIP_DEBUG
5873 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator slack hash:\n");
5874 SCIPhashmapPrintStatistics(conshdlrdata->slackhash, SCIPgetMessagehdlr(scip));
5875#endif
5876 SCIPhashmapFree(&conshdlrdata->slackhash);
5877 }
5878
5879 if ( conshdlrdata->altlp != NULL )
5880 {
5881 assert( conshdlrdata->varhash != NULL );
5882 assert( conshdlrdata->lbhash != NULL );
5883 assert( conshdlrdata->ubhash != NULL );
5884
5885#ifdef SCIP_DEBUG
5886 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator var hash:\n");
5887 SCIPhashmapPrintStatistics(conshdlrdata->varhash, SCIPgetMessagehdlr(scip));
5888 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator lower bound hash:\n");
5889 SCIPhashmapPrintStatistics(conshdlrdata->lbhash, SCIPgetMessagehdlr(scip));
5890 SCIPinfoMessage(scip, NULL, "\nStatistics for cons_indicator upper bound hash:\n");
5891 SCIPhashmapPrintStatistics(conshdlrdata->ubhash, SCIPgetMessagehdlr(scip));
5892#endif
5893
5894 SCIPhashmapFree(&conshdlrdata->varhash);
5895 SCIPhashmapFree(&conshdlrdata->lbhash);
5896 SCIPhashmapFree(&conshdlrdata->ubhash);
5897
5898 SCIP_CALL( SCIPlpiFree(&conshdlrdata->altlp) );
5899
5900 /* save the information that the columns have been deleted */
5901 for (c = 0; c < nconss; ++c)
5902 {
5903 SCIP_CONSDATA* consdata;
5904
5905 assert( conss != NULL );
5906 assert( conss[c] != NULL );
5907
5908 consdata = SCIPconsGetData(conss[c]);
5909 assert( consdata != NULL );
5910 consdata->colindex = -1;
5911 }
5912 }
5913 }
5914 else
5915 {
5916 assert( conshdlrdata->slackhash == NULL );
5917 assert( conshdlrdata->varhash == NULL );
5918 assert( conshdlrdata->lbhash == NULL );
5919 assert( conshdlrdata->ubhash == NULL );
5920 }
5921
5922 return SCIP_OKAY;
5923}
5924
5925
5926/** frees specific constraint data */
5927static
5928SCIP_DECL_CONSDELETE(consDeleteIndicator)
5929{
5930 assert( scip != NULL );
5931 assert( conshdlr != NULL );
5932 assert( cons != NULL );
5933 assert( consdata != NULL );
5934 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
5935
5936#ifdef SCIP_MORE_DEBUG
5937 SCIPdebugMsg(scip, "Deleting indicator constraint <%s>.\n", SCIPconsGetName(cons) );
5938#endif
5939
5940 /* Make sure that the hash for binary variables is freed. If we read a problem and then another problem without
5941 * solving (transforming) between, then no callback of constraint handlers are called. Thus, we cannot easily free the
5942 * hash map there. */
5943 if ( SCIPconshdlrGetNConss(conshdlr) == 0 )
5944 {
5945 SCIP_CONSHDLRDATA* conshdlrdata;
5946
5947 /* get constraint handler data */
5948 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5949 assert( conshdlrdata != NULL );
5950
5951 if ( conshdlrdata->binslackvarhash != NULL )
5952 SCIPhashmapFree(&conshdlrdata->binslackvarhash);
5953 }
5954
5955 /* drop events on transformed variables */
5956 if ( SCIPconsIsTransformed(cons) )
5957 {
5958 SCIP_CONSHDLRDATA* conshdlrdata;
5959
5960 /* get constraint handler data */
5961 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5962 assert( conshdlrdata != NULL );
5963
5964 if ( conshdlrdata->sepaalternativelp )
5965 {
5966 SCIP_CALL( deleteAltLPConstraint(scip, conshdlr, cons) );
5967 }
5968
5969 assert( (*consdata)->slackvar != NULL );
5970 assert( (*consdata)->binvar != NULL );
5971
5972 /* free events only in correct stages */
5974 {
5975 if ( (*consdata)->linconsactive )
5976 {
5977 assert( conshdlrdata->eventhdlrbound != NULL );
5978 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
5979 (SCIP_EVENTDATA*) cons, -1) );
5980 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound,
5981 (SCIP_EVENTDATA*) cons, -1) );
5982 }
5983 if ( conshdlrdata->forcerestart )
5984 {
5985 assert( conshdlrdata->eventhdlrrestart != NULL );
5986 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->binvar, SCIP_EVENTTYPE_GBDCHANGED, conshdlrdata->eventhdlrrestart,
5987 (SCIP_EVENTDATA*) conshdlrdata, -1) );
5988 }
5989
5990 /* drop bound change events on variables of linear constraints */
5991 if ( conshdlrdata->linconsevents && (*consdata)->linconsactive && (*consdata)->varswithevents != NULL )
5992 {
5993 int j;
5994 assert( cons != NULL );
5995 assert( (*consdata)->eventtypes != NULL );
5996 assert( (*consdata)->lincons != NULL );
5997
5998 for (j = 0; j < (*consdata)->nevents; ++j)
5999 {
6000 assert( !SCIPvarIsDeleted((*consdata)->varswithevents[j]) );
6001 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->varswithevents[j], (*consdata)->eventtypes[j], conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, -1) );
6002 }
6003 SCIPfreeBlockMemoryArray(scip, &(*consdata)->varswithevents, (*consdata)->nevents);
6004 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventtypes, (*consdata)->nevents);
6005
6006 (*consdata)->nevents = 0;
6007 assert( (*consdata)->varswithevents == NULL );
6008 assert( (*consdata)->eventtypes == NULL );
6009 }
6010 }
6011 }
6012
6013 /* Can there be cases where lincons is NULL, e.g., if presolve found the problem infeasible? */
6014 assert( (*consdata)->lincons != NULL );
6015
6016 /* mark linear constraint to be upgrade-able */
6017 if ( SCIPconsIsActive((*consdata)->lincons) )
6018 {
6019 SCIPconsAddUpgradeLocks((*consdata)->lincons, -1);
6020 assert( SCIPconsGetNUpgradeLocks((*consdata)->lincons) == 0 );
6021 }
6022
6023 /* release linear constraint and slack variable */
6024 SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->slackvar) );
6025 SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->lincons) );
6026
6027 SCIPfreeBlockMemory(scip, consdata);
6028
6029 return SCIP_OKAY;
6030}
6031
6032
6033/** transforms constraint data into data belonging to the transformed problem */
6034static
6035SCIP_DECL_CONSTRANS(consTransIndicator)
6036{
6037 SCIP_CONSDATA* consdata;
6038 SCIP_CONSHDLRDATA* conshdlrdata;
6039 SCIP_CONSDATA* sourcedata;
6040 char s[SCIP_MAXSTRLEN];
6041
6042 assert( scip != NULL );
6043 assert( conshdlr != NULL );
6044 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6045 assert( sourcecons != NULL );
6046 assert( targetcons != NULL );
6047
6048 /* get constraint handler data */
6049 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6050 assert( conshdlrdata != NULL );
6051 assert( conshdlrdata->eventhdlrbound != NULL );
6052
6053#ifdef SCIP_MORE_DEBUG
6054 SCIPdebugMsg(scip, "Transforming indicator constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
6055#endif
6056
6057 /* get data of original constraint */
6058 sourcedata = SCIPconsGetData(sourcecons);
6059 assert( sourcedata != NULL );
6060 assert( sourcedata->binvar != NULL );
6061
6062 /* check for slackvar */
6063 if ( sourcedata->slackvar == NULL )
6064 {
6065 SCIPerrorMessage("The indicator constraint <%s> needs a slack variable.\n", SCIPconsGetName(sourcecons));
6066 return SCIP_INVALIDDATA;
6067 }
6068
6069 /* check for linear constraint */
6070 if ( sourcedata->lincons == NULL )
6071 {
6072 SCIPerrorMessage("The indicator constraint <%s> needs a linear constraint.\n", SCIPconsGetName(sourcecons));
6073 return SCIP_INVALIDDATA;
6074 }
6075 assert( sourcedata->lincons != NULL );
6076 assert( sourcedata->slackvar != NULL );
6077
6078 /* create constraint data */
6079 consdata = NULL;
6080 /* Note that the constraint has activeone = TRUE, since the binary variable has been negated already if needed. */
6081 SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, SCIPconsGetName(sourcecons), &consdata, conshdlrdata->eventhdlrrestart,
6082 sourcedata->binvar, TRUE, sourcedata->lessthanineq, sourcedata->slackvar, sourcedata->lincons, sourcedata->linconsactive) );
6083 consdata->activeone = sourcedata->activeone;
6084 assert( consdata != NULL );
6085
6086 /* capture slack variable and linear constraint */
6087 SCIP_CALL( SCIPcaptureVar(scip, consdata->slackvar) );
6088 SCIP_CALL( SCIPcaptureCons(scip, consdata->lincons) );
6089
6090 /* create transformed constraint with the same flags */
6091 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
6092 SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
6093 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
6094 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
6095 SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
6096 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
6097 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
6098
6099 /* catch local bound change events on binary variable */
6100 if ( sourcedata->linconsactive )
6101 {
6102 assert( SCIPisTransformed(scip) );
6103 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *targetcons, NULL) );
6104 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *targetcons, NULL) );
6105 }
6106
6107 /* make sure that binary variable hash exists */
6108 if ( conshdlrdata->sepaalternativelp )
6109 {
6110 if ( conshdlrdata->binvarhash == NULL )
6111 {
6112 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
6113 }
6114
6115 /* check whether binary variable is present: note that a binary variable might appear several times, but this seldomly happens. */
6116 assert( conshdlrdata->binvarhash != NULL );
6117 if ( ! SCIPhashmapExists(conshdlrdata->binvarhash, (void*) consdata->binvar) )
6118 {
6119 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binvarhash, (void*) consdata->binvar, (void*) (*targetcons)) );
6120 }
6121 }
6122
6123 return SCIP_OKAY;
6124}
6125
6126
6127/** presolving initialization method of constraint handler (called when presolving is about to begin) */
6128static
6129SCIP_DECL_CONSINITPRE(consInitpreIndicator)
6130{ /*lint --e{715}*/
6131 SCIP_CONSHDLRDATA* conshdlrdata;
6132 int c;
6133
6134 assert( scip != NULL );
6135 assert( conshdlr != NULL );
6136 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6137
6139 return SCIP_OKAY;
6140
6141 SCIPdebugMsg(scip, "Initpre method for indicator constraints.\n");
6142
6143 /* check each constraint and get transformed linear constraint */
6144 for (c = 0; c < nconss; ++c)
6145 {
6146 SCIP_CONSDATA* consdata;
6147
6148 assert( conss != NULL );
6149 assert( conss[c] != NULL );
6150 assert( SCIPconsIsTransformed(conss[c]) );
6151
6152 consdata = SCIPconsGetData(conss[c]);
6153 assert( consdata != NULL );
6154
6155 /* if not happened already, get transformed linear constraint */
6156 assert( consdata->lincons != NULL );
6157 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear") == 0 );
6158
6159 /* in a restart the linear constraint might already be transformed */
6160 if ( ! SCIPconsIsTransformed(consdata->lincons) )
6161 {
6162 SCIP_CONS* translincons;
6163
6164 SCIP_CALL( SCIPgetTransformedCons(scip, consdata->lincons, &translincons) );
6165 assert( translincons != NULL );
6166
6167 SCIP_CALL( SCIPreleaseCons(scip, &consdata->lincons) );
6168 SCIP_CALL( SCIPcaptureCons(scip, translincons) );
6169 consdata->lincons = translincons;
6170 }
6171 }
6172
6173 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6174 assert( conshdlrdata != NULL );
6175
6176 /* reset flag, in case presolve was called for some problem before */
6177 conshdlrdata->addedcouplingcons = FALSE;
6178
6179 return SCIP_OKAY;
6180}
6181
6182
6183/** presolving method of constraint handler
6184 *
6185 * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
6186 * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
6187 * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not
6188 * inserted. Depending on the parameter @a addcouplingcons we add a variable upper bound or a row
6189 * (in consInitlpIndicator()).
6190 *
6191 * @warning We can never delete linear constraints, because we need them to get the right values
6192 * for the slack variables!
6193 */
6194static
6195SCIP_DECL_CONSPRESOL(consPresolIndicator)
6196{ /*lint --e{715}*/
6197 SCIP_CONSHDLRDATA* conshdlrdata;
6198 SCIP_Bool noReductions;
6199 SCIPdebug( int oldnfixedvars = *nfixedvars; )
6200 SCIPdebug( int oldndelconss = *ndelconss; )
6201 int c;
6202
6203 assert( scip != NULL );
6204 assert( conshdlr != NULL );
6205 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6206 assert( result != NULL );
6207
6208 *result = SCIP_DIDNOTRUN;
6209
6210 /* get constraint handler data */
6211 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6212 assert( conshdlrdata != NULL );
6213
6214 SCIPdebugMsg(scip, "Presolving indicator constraints.\n");
6215
6216 /* only run if success is possible */
6217 if ( nrounds == 0 || nnewfixedvars > 0 || nnewchgbds > 0 || nnewaggrvars > 0 )
6218 {
6219 *result = SCIP_DIDNOTFIND;
6220
6221 /* check each constraint */
6222 for (c = 0; c < nconss; ++c)
6223 {
6224 SCIP_CONSDATA* consdata;
6225 SCIP_CONS* cons;
6226 SCIP_Bool success;
6227 SCIP_Bool cutoff;
6228
6229 assert( conss != NULL );
6230 assert( conss[c] != NULL );
6231 cons = conss[c];
6232 consdata = SCIPconsGetData(cons);
6233 assert( consdata != NULL );
6234 assert( consdata->binvar != NULL );
6235 assert( ! SCIPconsIsModifiable(cons) );
6236
6237#ifdef SCIP_MORE_DEBUG
6238 SCIPdebugMsg(scip, "Presolving indicator constraint <%s>.\n", SCIPconsGetName(cons) );
6239#endif
6240
6241 /* do nothing if the linear constraint is not active */
6242 if ( ! consdata->linconsactive )
6243 continue;
6244
6245 assert( consdata->lincons != NULL );
6246 assert( consdata->slackvar != NULL );
6247 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->lincons)), "linear") == 0 );
6248 assert( SCIPconsIsTransformed(consdata->lincons) );
6249
6250 /* add implications if not yet done */
6251 if ( ! consdata->implicationadded )
6252 {
6253 int nbnds = 0;
6254 SCIP_CALL( SCIPaddVarImplication(scip, consdata->binvar, TRUE, consdata->slackvar, SCIP_BOUNDTYPE_UPPER, 0.0,
6255 &cutoff, &nbnds) );
6256 *nchgbds += nbnds;
6257
6258 /* cutoff/infeasible might be true if preprocessing was truncated */
6259 /* note: nbdchgs == 0 is not necessarily true, because preprocessing might be truncated. */
6260 consdata->implicationadded = TRUE;
6261 if ( cutoff )
6262 {
6263 *result = SCIP_CUTOFF;
6264 return SCIP_OKAY;
6265 }
6266 }
6267
6268 /* check type of slack variable if not yet done */
6269 if ( ! consdata->slacktypechecked )
6270 {
6271 consdata->slacktypechecked = TRUE;
6272 /* check if slack variable can be made implicit integer. */
6273 if ( SCIPvarGetType(consdata->slackvar) == SCIP_VARTYPE_CONTINUOUS )
6274 {
6275 SCIP_Real* vals;
6276 SCIP_VAR** vars;
6277 SCIP_VAR* slackvar;
6278 SCIP_Bool foundslackvar = FALSE;
6279 int nvars;
6280 int j;
6281
6282 assert( consdata->lincons != NULL );
6283 vars = SCIPgetVarsLinear(scip, consdata->lincons);
6284 vals = SCIPgetValsLinear(scip, consdata->lincons);
6285 nvars = SCIPgetNVarsLinear(scip, consdata->lincons);
6286 slackvar = consdata->slackvar;
6287 assert( slackvar != NULL );
6288
6289 for (j = 0; j < nvars; ++j)
6290 {
6291 if ( vars[j] == slackvar )
6292 foundslackvar = TRUE;
6293 else
6294 {
6295 if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, vals[j]))
6296 break;
6297 }
6298 }
6299 /* something is strange if the slack variable does not appear in the linear constraint (possibly because it is an artificial constraint) */
6300 if ( j == nvars && foundslackvar )
6301 {
6302 SCIP_Bool infeasible;
6303 SCIP_Real lb;
6304 SCIP_Real ub;
6305
6306 lb = SCIPvarGetLbGlobal(consdata->slackvar);
6307 ub = SCIPvarGetUbGlobal(consdata->slackvar);
6308 if ( (SCIPisInfinity(scip, -lb) || SCIPisIntegral(scip, lb)) && (SCIPisInfinity(scip, ub) || SCIPisIntegral(scip, ub)) )
6309 {
6310 SCIP_CALL( SCIPchgVarType(scip, consdata->slackvar, SCIP_VARTYPE_IMPLINT, &infeasible) );
6311 /* don't assert feasibility here because the presolver should detect infeasibility */
6312 }
6313 else
6314 {
6315 /* It can happen that the bounds of the slack variable have been changed to be non-integral in
6316 * previous presolving steps. We then might get a problem with tightening the bounds. In this case,
6317 * we just leave the slack variable to be continuous. */
6318 SCIPdebugMsg(scip, "Cannot change type of slack variable (<%s>) to IMPLINT, since global bound is non-integral: (%g, %g).\n",
6319 SCIPvarGetName(consdata->slackvar), SCIPvarGetLbGlobal(consdata->slackvar), SCIPvarGetUbGlobal(consdata->slackvar));
6320 }
6321 }
6322 }
6323 }
6324
6325 /* perform one presolving round */
6326 SCIP_CALL( presolRoundIndicator(scip, conshdlrdata, cons, consdata,
6327 conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip), &cutoff, &success, ndelconss, nfixedvars) );
6328
6329 if ( cutoff )
6330 {
6331 *result = SCIP_CUTOFF;
6332 return SCIP_OKAY;
6333 }
6334 if ( success )
6335 *result = SCIP_SUCCESS;
6336 }
6337 }
6338
6339 /* determine whether other methods have found reductions */
6340 noReductions = nnewfixedvars == 0 && nnewaggrvars == 0 && nnewchgvartypes == 0 && nnewchgbds == 0
6341 && nnewdelconss == 0 && nnewchgcoefs == 0 && nnewchgsides == 0;
6342
6343 /* add variable upper bounds after bounds are likely to be strengthened */
6344 if ( noReductions && *result != SCIP_SUCCESS && conshdlrdata->addcouplingcons && ! conshdlrdata->addedcouplingcons )
6345 {
6346 int ngen;
6347
6348 /* create variable upper bounds, possibly removing indicator constraints */
6349 SCIP_CALL( createVarUbs(scip, conshdlrdata, conss, nconss, &ngen) );
6350
6351 if ( ngen > 0 )
6352 {
6353 *result = SCIP_SUCCESS;
6354 *nupgdconss += ngen;
6355 if ( conshdlrdata->removeindicators )
6356 *ndelconss += ngen;
6357 }
6358 conshdlrdata->addedcouplingcons = TRUE;
6359 }
6360
6361 SCIPdebug( SCIPdebugMsg(scip, "Presolved %d constraints (fixed %d variables, removed 0 variables, and deleted %d constraints).\n",
6362 nconss, *nfixedvars - oldnfixedvars, *ndelconss - oldndelconss); )
6363
6364 return SCIP_OKAY; /*lint !e438*/
6365}
6366
6367
6368/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved)
6369 *
6370 * For an indicator constraint with binary variable \f$y\f$ and slack variable \f$s\f$ the coupling
6371 * inequality \f$s \le M (1-y)\f$ (equivalently: \f$s + M y \le M\f$) is inserted, where \f$M\f$ is
6372 * an upper bound on the value of \f$s\f$. If \f$M\f$ is too large the inequality is not inserted.
6373 */
6374static
6375SCIP_DECL_CONSINITLP(consInitlpIndicator)
6376{
6377 int c;
6378 SCIP_CONSHDLRDATA* conshdlrdata;
6379
6380 assert( scip != NULL );
6381 assert( conshdlr != NULL );
6382 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6383
6384 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6385 assert( conshdlrdata != NULL );
6386
6387 *infeasible = FALSE;
6388
6389 /* check whether coupling constraints should be added */
6390 if ( ! conshdlrdata->addcoupling )
6391 return SCIP_OKAY;
6392
6393 /* check whether coupling constraints have been added already */
6394 if ( conshdlrdata->addcouplingcons && conshdlrdata->addedcouplingcons )
6395 return SCIP_OKAY;
6396
6397 SCIPdebugMsg(scip, "Handle initial rows for %d indicator constraints.\n", nconss);
6398
6399 /* check each constraint */
6400 for (c = 0; c < nconss && !(*infeasible); ++c)
6401 {
6402 SCIP_CONSDATA* consdata;
6403 SCIP_Real ub;
6404
6405 assert( conss != NULL );
6406 assert( conss[c] != NULL );
6407 consdata = SCIPconsGetData(conss[c]);
6408 assert( consdata != NULL );
6409
6410 /* do not add inequalities if there are no linear constraints (no slack variable available) */
6411 if ( ! consdata->linconsactive )
6412 continue;
6413
6414 /* get upper bound for slack variable in linear constraint */
6415 ub = SCIPvarGetUbGlobal(consdata->slackvar);
6416 assert( ! SCIPisNegative(scip, ub) );
6417
6418 /* insert corresponding row if helpful and coefficient is not too large */
6419 if ( ub <= conshdlrdata->maxcouplingvalue )
6420 {
6421 char name[50];
6422
6423#ifndef NDEBUG
6424 (void) SCIPsnprintf(name, 50, "couple%d", c);
6425#else
6426 name[0] = '\0';
6427#endif
6428
6429 /* add variable upper bound if required */
6430 if ( conshdlrdata->addcouplingcons )
6431 {
6432 SCIP_CONS* cons;
6433
6434 assert( ! conshdlrdata->addedcouplingcons );
6435
6436 SCIPdebugMsg(scip, "Insert coupling varbound constraint for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
6437
6438 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, consdata->slackvar, consdata->binvar, ub, -SCIPinfinity(scip), ub,
6440
6441 SCIP_CALL( SCIPaddCons(scip, cons) );
6442 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
6443 }
6444 else
6445 {
6446 SCIP_ROW* row;
6447
6448 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], name, -SCIPinfinity(scip), ub, FALSE, FALSE, FALSE) );
6450
6451 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->slackvar, 1.0) );
6452 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->binvar, ub) );
6454
6455 SCIPdebugMsg(scip, "Insert coupling inequality for indicator constraint <%s> (coeff: %f).\n", SCIPconsGetName(conss[c]), ub);
6456#ifdef SCIP_OUTPUT
6457 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
6458#endif
6459 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
6460 SCIP_CALL( SCIPreleaseRow(scip, &row));
6461 }
6462 }
6463 }
6464
6465 return SCIP_OKAY;
6466}
6467
6468
6469/** separation method of constraint handler for LP solutions */
6470static
6471SCIP_DECL_CONSSEPALP(consSepalpIndicator)
6472{ /*lint --e{715}*/
6473 assert( scip != NULL );
6474 assert( conshdlr != NULL );
6475 assert( conss != NULL );
6476 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6477 assert( result != NULL );
6478
6479 /* perform separation */
6480 SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, NULL, SCIP_TYPE_SEPALP, result) );
6481
6482 return SCIP_OKAY;
6483}
6484
6485
6486/** separation method of constraint handler for arbitrary primal solutions */
6487static
6488SCIP_DECL_CONSSEPASOL(consSepasolIndicator)
6489{ /*lint --e{715}*/
6490 assert( scip != NULL );
6491 assert( conshdlr != NULL );
6492 assert( conss != NULL );
6493 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6494 assert( result != NULL );
6495
6496 /* perform separation */
6497 SCIP_CALL( separateIndicators(scip, conshdlr, nconss, nusefulconss, conss, sol, SCIP_TYPE_SEPASOL, result) );
6498
6499 return SCIP_OKAY;
6500}
6501
6502
6503/** constraint enforcing method of constraint handler for LP solutions */
6504static
6505SCIP_DECL_CONSENFOLP(consEnfolpIndicator)
6506{ /*lint --e{715}*/
6507 SCIP_CONSHDLRDATA* conshdlrdata;
6508
6509 assert( scip != NULL );
6510 assert( conshdlr != NULL );
6511 assert( conss != NULL );
6512 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6513 assert( result != NULL );
6514
6515 if ( solinfeasible )
6516 {
6517 *result = SCIP_FEASIBLE;
6518 return SCIP_OKAY;
6519 }
6520
6521 /* get constraint handler data */
6522 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6523 assert( conshdlrdata != NULL );
6524
6525 SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, NULL, SCIP_TYPE_ENFOLP, conshdlrdata->genlogicor, result) );
6526
6527 return SCIP_OKAY;
6528}
6529
6530
6531/** constraint enforcing method of constraint handler for relaxation solutions */
6532static
6533SCIP_DECL_CONSENFORELAX(consEnforelaxIndicator)
6534{ /*lint --e{715}*/
6535 SCIP_CONSHDLRDATA* conshdlrdata;
6536
6537 assert( scip != NULL );
6538 assert( conshdlr != NULL );
6539 assert( conss != NULL );
6540 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6541 assert( result != NULL );
6542
6543 if ( solinfeasible )
6544 {
6545 *result = SCIP_FEASIBLE;
6546 return SCIP_OKAY;
6547 }
6548
6549 /* get constraint handler data */
6550 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6551 assert( conshdlrdata != NULL );
6552
6553 SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, sol, SCIP_TYPE_ENFORELAX, conshdlrdata->genlogicor, result) );
6554
6555 return SCIP_OKAY;
6556}
6557
6558
6559/** constraint enforcing method of constraint handler for pseudo solutions */
6560static
6561SCIP_DECL_CONSENFOPS(consEnfopsIndicator)
6562{ /*lint --e{715}*/
6563 assert( scip != NULL );
6564 assert( conshdlr != NULL );
6565 assert( conss != NULL );
6566 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6567 assert( result != NULL );
6568
6569 if ( solinfeasible )
6570 {
6571 *result = SCIP_FEASIBLE;
6572 return SCIP_OKAY;
6573 }
6574
6575 if ( objinfeasible )
6576 {
6577 *result = SCIP_DIDNOTRUN;
6578 return SCIP_OKAY;
6579 }
6580
6581 SCIP_CALL( enforceIndicators(scip, conshdlr, nconss, conss, NULL, SCIP_TYPE_ENFOPS, TRUE, result) );
6582
6583 return SCIP_OKAY;
6584}
6585
6586
6587/** feasibility check method of constraint handler for integral solutions */
6588static
6589SCIP_DECL_CONSCHECK(consCheckIndicator)
6590{ /*lint --e{715}*/
6591 SCIP_SOL* trysol = NULL;
6592 SCIP_CONSHDLRDATA* conshdlrdata;
6593 SCIP_Bool someLinconsNotActive;
6594 SCIP_Bool changedSol;
6595 int c;
6596
6597 assert( scip != NULL );
6598 assert( conshdlr != NULL );
6599 assert( conss != NULL );
6600 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6601 assert( result != NULL );
6602
6603 SCIPdebugMsg(scip, "Checking %d indicator constraints <%s>.\n", nconss, SCIPconshdlrGetName(conshdlr) );
6604
6605 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6606 assert( conshdlrdata != NULL );
6607
6608 /* try to repair solution below, if it makes sense (will send solution to trysol heuristic in any case (see below) */
6609 if ( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM && SCIPgetStage(scip) < SCIP_STAGE_SOLVED && conshdlrdata->trysolutions && conshdlrdata->heurtrysol != NULL )
6610 {
6611 SCIP_CALL( SCIPcreateSolCopy(scip, &trysol, sol) );
6612 assert( trysol != NULL );
6613 }
6614
6615 /* check each constraint */
6616 *result = SCIP_FEASIBLE;
6617 changedSol = FALSE;
6618 someLinconsNotActive = FALSE;
6619 for (c = 0; c < nconss; ++c)
6620 {
6621 SCIP_CONSDATA* consdata;
6622
6623 assert( conss[c] != NULL );
6624 consdata = SCIPconsGetData(conss[c]);
6625 assert( consdata != NULL );
6626 assert( consdata->binvar != NULL );
6627
6628 /* if the linear constraint has not been generated, we do nothing */
6629 if ( ! consdata->linconsactive )
6630 {
6631 someLinconsNotActive = TRUE;
6632 continue;
6633 }
6634
6635 assert( consdata->slackvar != NULL );
6636 /* if printreason is true it can happen that non-integral solutions are checked */
6637 assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
6638
6639 /* if constraint is infeasible */
6640 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) &&
6641 ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->slackvar)) )
6642 {
6643 SCIP_Real absviol = REALABS(SCIPgetSolVal(scip, sol, consdata->slackvar));
6644 SCIP_Real relviol = SCIPrelDiff(absviol, 0.0);
6645
6646 if( sol != NULL )
6647 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
6648
6649 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
6650 *result = SCIP_INFEASIBLE;
6651
6652 if ( printreason )
6653 {
6654 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
6655 SCIPinfoMessage(scip, NULL, ";\nviolation: <%s> = %g and <%s> = %.15g\n",
6656 SCIPvarGetName(consdata->binvar), SCIPgetSolVal(scip, sol, consdata->binvar),
6657 SCIPvarGetName(consdata->slackvar), SCIPgetSolVal(scip, sol, consdata->slackvar));
6658 }
6659
6660 /* try to make solution feasible if it makes sense - otherwise exit */
6661 if ( trysol != NULL )
6662 {
6663 SCIP_Bool changed;
6664 SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
6665 changedSol = changedSol || changed;
6666 }
6667 else
6668 {
6669 SCIPdebugMsg(scip, "Indicator constraint %s is not feasible.\n", SCIPconsGetName(conss[c]));
6670
6671 if ( ! completely )
6672 return SCIP_OKAY;
6673 }
6674 }
6675 else
6676 {
6677 if ( trysol != NULL )
6678 {
6679 SCIP_Bool changed;
6680 SCIP_CALL( SCIPmakeIndicatorFeasible(scip, conss[c], trysol, &changed) );
6681 changedSol = changedSol || changed;
6682 }
6683 }
6684 }
6685
6686 /* if some linear constraints are not active, we need to check feasibility via the alternative polyhedron */
6687 if ( someLinconsNotActive )
6688 {
6689 SCIP_LPI* lp;
6690 SCIP_Bool infeasible;
6691 SCIP_Bool error;
6692 SCIP_Bool* S;
6693
6694 lp = conshdlrdata->altlp;
6695 assert( conshdlrdata->sepaalternativelp );
6696
6697 /* the check maybe called before we have build the alternative polyhedron -> return SCIP_INFEASIBLE */
6698 if ( lp != NULL )
6699 {
6700#ifndef NDEBUG
6701 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
6702#endif
6703
6704 /* change coefficients of bounds in alternative LP */
6705 if ( conshdlrdata->updatebounds )
6706 {
6707 SCIP_CALL( updateFirstRowGlobal(scip, conshdlrdata) );
6708 }
6709
6710 /* scale first row if necessary */
6711 SCIP_CALL( scaleFirstRow(scip, conshdlrdata) );
6712
6713 /* set objective function to current solution */
6714 SCIP_CALL( setAltLPObjZero(scip, lp, nconss, conss) );
6715
6716 SCIP_CALL( SCIPallocBufferArray(scip, &S, nconss) );
6717
6718 /* set up variables fixed to 1 */
6719 for (c = 0; c < nconss; ++c)
6720 {
6721 SCIP_CONSDATA* consdata;
6722
6723 assert( conss[c] != NULL );
6724 consdata = SCIPconsGetData(conss[c]);
6725 assert( consdata != NULL );
6726
6727 /* if printreason is true it can happen that non-integral solutions are checked */
6728 assert( checkintegrality || SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) );
6729 if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->binvar)) )
6730 S[c] = TRUE;
6731 else
6732 S[c] = FALSE;
6733 }
6734
6735 /* fix the variables in S */
6736 SCIP_CALL( fixAltLPVariables(scip, lp, nconss, conss, S) );
6737
6738 /* check feasibility */
6740 SCIP_CALL( checkAltLPInfeasible(scip, lp, conshdlrdata->maxconditionaltlp, TRUE, &infeasible, &error) );
6742
6743 if ( error )
6744 return SCIP_LPERROR;
6745
6746 if ( ! infeasible )
6747 *result = SCIP_INFEASIBLE;
6748
6749 /* reset bounds */
6750 SCIP_CALL( unfixAltLPVariables(scip, lp, nconss, conss, S) );
6751
6752#ifndef NDEBUG
6753 SCIP_CALL( checkLPBoundsClean(scip, lp, nconss, conss) );
6754#endif
6755
6757 }
6758 else
6759 *result = SCIP_INFEASIBLE;
6760 }
6761 else
6762 {
6763 /* tell heur_trysol about solution - it will pass it to SCIP */
6764 if ( trysol != NULL && changedSol )
6765 {
6766 assert( conshdlrdata->heurtrysol != NULL );
6767 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->heurtrysol, trysol) );
6768 }
6769 }
6770
6771 if ( trysol != NULL )
6772 SCIP_CALL( SCIPfreeSol(scip, &trysol) );
6773
6774 if ( *result == SCIP_INFEASIBLE )
6775 {
6776 SCIPdebugMsg(scip, "Indicator constraints are not feasible.\n");
6777 return SCIP_OKAY;
6778 }
6779
6780 /* at this point we are feasible */
6781 SCIPdebugMsg(scip, "Indicator constraints are feasible.\n");
6782
6783 return SCIP_OKAY;
6784}
6785
6786
6787/** domain propagation method of constraint handler */
6788static
6789SCIP_DECL_CONSPROP(consPropIndicator)
6790{ /*lint --e{715}*/
6791 SCIP_CONSHDLRDATA* conshdlrdata;
6792 SCIP_Bool dualreductions;
6793 int ngen = 0;
6794 int c;
6795
6796 assert( scip != NULL );
6797 assert( conshdlr != NULL );
6798 assert( conss != NULL );
6799 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6800 assert( result != NULL );
6801
6802 *result = SCIP_DIDNOTRUN;
6803
6804 assert( SCIPisTransformed(scip) );
6805
6806 SCIPdebugMsg(scip, "Start propagation of constraint handler <%s>.\n", SCIPconshdlrGetName(conshdlr));
6807
6808 /* get constraint handler data */
6809 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6810 assert( conshdlrdata != NULL );
6811
6812 /* avoid propagation if no bound has changed */
6813 if ( ! conshdlrdata->boundhaschanged && ! SCIPinRepropagation(scip) && ! conshdlrdata->linconsboundschanged )
6814 {
6815 *result = SCIP_DIDNOTFIND;
6816 return SCIP_OKAY;
6817 }
6818
6819 /* if first time called, add events on variables of linear constraint */
6820 if ( !conshdlrdata->linconsevents )
6821 {
6822 for (c = 0; c < nconss; ++c)
6823 {
6824 SCIP_CONSDATA* consdata;
6825 SCIP_VAR** vars;
6826 SCIP_Real* vals;
6827 int nvars;
6828 int j;
6829 assert( conss[c] != NULL );
6830
6831 consdata = SCIPconsGetData(conss[c]);
6832 assert( consdata != NULL );
6833
6834 /* if the linear constraint is not present, we continue */
6835 if ( ! consdata->linconsactive )
6836 continue;
6837
6838 /* do not add events if upper bound of slackvar is already small */
6839 if ( SCIPvarGetUbLocal(consdata->slackvar) <= conshdlrdata->maxcouplingvalue )
6840 continue;
6841
6842 /* do not add events if it is not a <= inequality; we do not propagate in this case */
6843 if ( SCIPisInfinity(scip, SCIPgetRhsLinear(scip, consdata->lincons) ) )
6844 continue;
6845
6846 assert( consdata->lincons != NULL );
6847 vars = SCIPgetVarsLinear(scip, consdata->lincons);
6848 vals = SCIPgetValsLinear(scip, consdata->lincons);
6849 nvars = SCIPgetNVarsLinear(scip, consdata->lincons);
6850 assert( consdata->slackvar != NULL );
6851 assert( nvars != 0 );
6852
6853 /* alloc memory to store events on variables of linear constraint; otherwise we can not drop the events when the cons is deleted */
6854 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varswithevents, nvars - 1) );
6855 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventtypes, nvars - 1) );
6856
6857 for (j = 0; j < nvars; ++j)
6858 {
6859 if ( vars[j] == consdata->slackvar )
6860 continue;
6861
6862 /* catch only bound changes which are important for propagation of max activity to upper bound of slackvar */
6863 if ( vals[j] > 0.0 )
6864 {
6865 SCIP_CALL( SCIPcatchVarEvent(scip, vars[j], SCIP_EVENTTYPE_UBTIGHTENED, conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
6866 consdata->varswithevents[consdata->nevents] = vars[j];
6867 consdata->eventtypes[consdata->nevents] = SCIP_EVENTTYPE_UBTIGHTENED;
6868 consdata->nevents++;
6869 }
6870 else
6871 {
6872 SCIP_CALL( SCIPcatchVarEvent(scip, vars[j], SCIP_EVENTTYPE_LBTIGHTENED, conshdlrdata->eventhdlrlinconsbound, (SCIP_EVENTDATA*) conshdlrdata, NULL) );
6873 consdata->varswithevents[consdata->nevents] = vars[j];
6874 consdata->eventtypes[consdata->nevents] = SCIP_EVENTTYPE_LBTIGHTENED;
6875 consdata->nevents++;
6876 }
6877 }
6878 assert( consdata->nevents == nvars - 1 );
6879 }
6880 conshdlrdata->linconsevents = TRUE;
6881 }
6882
6883 /* already mark that no bound has changed */
6884 conshdlrdata->boundhaschanged = FALSE;
6885 conshdlrdata->linconsboundschanged = FALSE;
6886
6887 dualreductions = conshdlrdata->dualreductions && SCIPallowStrongDualReds(scip);
6888
6889 /* check each constraint */
6890 for (c = 0; c < nconss; ++c)
6891 {
6892 SCIP_CONS* cons;
6893 SCIP_CONSDATA* consdata;
6894 SCIP_Bool cutoff;
6895 int cnt;
6896
6897 *result = SCIP_DIDNOTFIND;
6898
6899 assert( conss[c] != NULL );
6900 cons = conss[c];
6901 consdata = SCIPconsGetData(cons);
6902 assert( consdata != NULL );
6903
6904#ifdef SCIP_MORE_DEBUG
6905 SCIPdebugMsg(scip, "Propagating indicator constraint <%s>.\n", SCIPconsGetName(cons) );
6906#endif
6907
6908 SCIP_CALL( propIndicator(scip, cons, consdata, conshdlrdata, dualreductions, conshdlrdata->addopposite, &cutoff, &cnt) );
6909
6910 if ( cutoff )
6911 {
6912 *result = SCIP_CUTOFF;
6913 return SCIP_OKAY;
6914 }
6915 ngen += cnt;
6916 }
6917
6918 SCIPdebugMsg(scip, "Propagated %d domains in constraint handler <%s>.\n", ngen, SCIPconshdlrGetName(conshdlr));
6919 if ( ngen > 0 )
6920 *result = SCIP_REDUCEDDOM;
6921
6922 return SCIP_OKAY;
6923}
6924
6925
6926/** propagation conflict resolving method of constraint handler
6927 *
6928 * We check which bound changes were the reason for infeasibility. We use that @a inferinfo is 0 if
6929 * the binary variable has bounds that fix it to be nonzero (these bounds are the reason). Likewise
6930 * @a inferinfo is 1 if the slack variable has bounds that fix it to be nonzero.
6931 */
6932static
6933SCIP_DECL_CONSRESPROP(consRespropIndicator)
6934{ /*lint --e{715}*/
6935 SCIP_CONSDATA* consdata;
6936
6937 assert( scip != NULL );
6938 assert( cons != NULL );
6939 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6940 assert( infervar != NULL );
6941 assert( bdchgidx != NULL );
6942 assert( result != NULL );
6943
6944 *result = SCIP_DIDNOTFIND;
6945 SCIPdebugMsg(scip, "Propagation resolution method of indicator constraint <%s>.\n", SCIPconsGetName(cons));
6946
6947 consdata = SCIPconsGetData(cons);
6948 assert( consdata != NULL );
6949 assert( inferinfo == 0 || inferinfo == 1 || inferinfo == 2 || inferinfo == 3 );
6950 assert( consdata->linconsactive );
6951
6952 /* if the binary variable was the reason */
6953 if ( inferinfo == 0 )
6954 {
6955 assert( SCIPgetVarLbAtIndex(scip, consdata->binvar, bdchgidx, FALSE) > 0.5 );
6956 assert( infervar != consdata->binvar );
6957
6958 SCIP_CALL( SCIPaddConflictLb(scip, consdata->binvar, bdchgidx) );
6959 }
6960 else if ( inferinfo == 1 )
6961 {
6962 /* if the slack variable fixed to a positive value was the reason */
6963 assert( infervar != consdata->slackvar );
6964 /* Use a weaker comparison to SCIPvarGetLbAtIndex here (i.e., SCIPisPositive instead of SCIPisFeasPositive),
6965 * because SCIPvarGetLbAtIndex might differ from the local bound at time bdchgidx by epsilon. */
6966 assert( SCIPisPositive(scip, SCIPgetVarLbAtIndex(scip, consdata->slackvar, bdchgidx, FALSE)) );
6967 SCIP_CALL( SCIPaddConflictLb(scip, consdata->slackvar, bdchgidx) );
6968 }
6969 else if ( inferinfo == 2 )
6970 {
6971 assert( SCIPisFeasZero(scip, SCIPgetVarUbAtIndex(scip, consdata->slackvar, bdchgidx, FALSE)) );
6972 assert( SCIPconshdlrGetData(conshdlr)->dualreductions && SCIPallowStrongDualReds(scip) && SCIPallowWeakDualReds(scip) );
6973 SCIP_CALL( SCIPaddConflictUb(scip, consdata->slackvar, bdchgidx) );
6974 }
6975 else
6976 {
6977 SCIP_VAR** linconsvars;
6978 SCIP_Real* linconsvals;
6979 int nlinconsvars;
6980 int j;
6981
6982 assert( inferinfo == 3 );
6983
6984 /* mark variables in linear constraint */
6985 nlinconsvars = SCIPgetNVarsLinear(scip, consdata->lincons);
6986 linconsvars = SCIPgetVarsLinear(scip, consdata->lincons);
6987 linconsvals = SCIPgetValsLinear(scip, consdata->lincons);
6988
6989 for (j = 0; j < nlinconsvars; ++j)
6990 {
6991 if ( linconsvals[j] > 0.0 )
6992 {
6993 assert( ! SCIPisInfinity(scip, SCIPgetVarUbAtIndex(scip, linconsvars[j], bdchgidx, FALSE)) );
6994 SCIP_CALL( SCIPaddConflictUb(scip, linconsvars[j], bdchgidx) );
6995 }
6996 else
6997 {
6998 assert( ! SCIPisInfinity(scip, -SCIPgetVarLbAtIndex(scip, linconsvars[j], bdchgidx, FALSE)) );
6999 SCIP_CALL( SCIPaddConflictLb(scip, linconsvars[j], bdchgidx) );
7000 }
7001 }
7002 }
7003
7004 *result = SCIP_SUCCESS;
7005
7006 return SCIP_OKAY;
7007}
7008
7009
7010/** variable rounding lock method of constraint handler
7011 *
7012 * The up-rounding of the binary and slack variable may violate the constraint. If the linear
7013 * constraint is not active, we lock all variables in the depending constraint - otherwise they
7014 * will be fixed by dual presolving methods.
7015 */
7016static
7017SCIP_DECL_CONSLOCK(consLockIndicator)
7018{
7019 SCIP_CONSDATA* consdata;
7020
7021 assert( scip != NULL );
7022 assert( conshdlr != NULL );
7023 assert( cons != NULL );
7024 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7025 consdata = SCIPconsGetData(cons);
7026 assert( consdata != NULL );
7027 assert( consdata->binvar != NULL );
7028
7029#ifdef SCIP_MORE_DEBUG
7030 SCIPdebugMsg(scip, "%socking constraint <%s>.\n", (nlocksneg < 0) || (nlockspos < 0) ? "Unl" : "L", SCIPconsGetName(cons));
7031#endif
7032
7033 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->binvar, locktype, nlocksneg, nlockspos) );
7034
7035 if ( consdata->linconsactive )
7036 {
7037 assert( consdata->slackvar != NULL );
7038
7039 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->slackvar, locktype, nlocksneg, nlockspos) );
7040 }
7041 else
7042 {
7043 SCIP_VAR** linvars;
7044 SCIP_Real* linvals;
7045 SCIP_Bool haslhs;
7046 SCIP_Bool hasrhs;
7047 int nlinvars;
7048 int j;
7049
7050 assert( consdata->lincons != NULL );
7051 assert( consdata->slackvar == NULL );
7052
7053 nlinvars = SCIPgetNVarsLinear(scip, consdata->lincons);
7054 linvars = SCIPgetVarsLinear(scip, consdata->lincons);
7055 linvals = SCIPgetValsLinear(scip, consdata->lincons);
7056 haslhs = ! SCIPisInfinity(scip, REALABS(SCIPgetLhsLinear(scip, consdata->lincons)));
7057 hasrhs = ! SCIPisInfinity(scip, REALABS(SCIPgetRhsLinear(scip, consdata->lincons)));
7058
7059 for (j = 0; j < nlinvars; ++j)
7060 {
7061 assert( ! SCIPisZero(scip, linvals[j]) );
7062 if ( SCIPisPositive(scip, linvals[j]) )
7063 {
7064 if ( haslhs )
7065 {
7066 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlockspos, nlocksneg) );
7067 }
7068 if ( hasrhs )
7069 {
7070 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlocksneg, nlockspos) );
7071 }
7072 }
7073 else
7074 {
7075 if ( haslhs )
7076 {
7077 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlocksneg, nlockspos) );
7078 }
7079 if ( hasrhs )
7080 {
7081 SCIP_CALL( SCIPaddVarLocksType(scip, linvars[j], locktype, nlockspos, nlocksneg) );
7082 }
7083 }
7084 }
7085 }
7086
7087 return SCIP_OKAY;
7088}
7089
7090
7091/** constraint display method of constraint handler */
7092static
7093SCIP_DECL_CONSPRINT(consPrintIndicator)
7094{
7095 SCIP_CONSDATA* consdata;
7096 SCIP_VAR* binvar;
7097 int rhs;
7098
7099 assert( scip != NULL );
7100 assert( conshdlr != NULL );
7101 assert( cons != NULL );
7102 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7103
7104 consdata = SCIPconsGetData(cons);
7105 assert( consdata != NULL );
7106 assert( consdata->binvar != NULL );
7107
7108 binvar = consdata->binvar;
7109 rhs = 1;
7111 {
7112 rhs = 0;
7113 binvar = SCIPvarGetNegatedVar(binvar);
7114 }
7115 SCIPinfoMessage(scip, file, "<%s> = %d", SCIPvarGetName(binvar), rhs);
7116
7117 assert( consdata->slackvar != NULL );
7118 assert( consdata->lincons != NULL );
7119 SCIPinfoMessage(scip, file, " -> <%s> = 0", SCIPvarGetName(consdata->slackvar));
7120 SCIPinfoMessage(scip, file, " (<%s>)", SCIPconsGetName(consdata->lincons));
7121
7122 return SCIP_OKAY;
7123}
7124
7125
7126/** constraint copying method of constraint handler */
7127static
7128SCIP_DECL_CONSCOPY(consCopyIndicator)
7129{ /*lint --e{715}*/
7130 SCIP_CONSDATA* sourceconsdata;
7131 SCIP_CONS* targetlincons = NULL;
7132 SCIP_VAR* targetbinvar = NULL;
7133 SCIP_VAR* targetslackvar = NULL;
7134 SCIP_CONS* sourcelincons;
7135 SCIP_CONSHDLR* conshdlrlinear;
7136 const char* consname;
7137
7138 assert( scip != NULL );
7139 assert( sourcescip != NULL );
7140 assert( sourcecons != NULL );
7141 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 );
7142
7143 *valid = TRUE;
7144
7145 if ( name != NULL )
7146 consname = name;
7147 else
7148 consname = SCIPconsGetName(sourcecons);
7149
7150#ifdef SCIP_MORE_DEBUG
7151 SCIPdebugMsg(scip, "Copying indicator constraint <%s> ...\n", consname);
7152#endif
7153
7154 if ( modifiable )
7155 {
7156 SCIPwarningMessage(scip, "cannot create modifiable indicator constraint when trying to copy constraint <%s>,\n", SCIPconsGetName(sourcecons));
7157 *valid = FALSE;
7158 return SCIP_OKAY;
7159 }
7160
7161 sourceconsdata = SCIPconsGetData(sourcecons);
7162 assert( sourceconsdata != NULL );
7163
7164 /* get linear constraint */
7165 sourcelincons = sourceconsdata->lincons;
7166
7167 /* if the constraint has been deleted -> create empty constraint (multi-aggregation might still contain slack variable, so indicator is valid) */
7168 if ( SCIPconsIsDeleted(sourcelincons) )
7169 {
7170 SCIPdebugMsg(scip, "Linear constraint <%s> deleted! Create empty linear constraint.\n", SCIPconsGetName(sourceconsdata->lincons));
7171
7172 SCIP_CALL( SCIPcreateConsLinear(scip, &targetlincons, "dummy", 0, NULL, NULL, 0.0, SCIPinfinity(scip),
7174 SCIP_CALL( SCIPaddCons(scip, targetlincons) );
7175 }
7176 else
7177 {
7178 /* get copied version of linear constraint */
7179 assert( sourcelincons != NULL );
7180 conshdlrlinear = SCIPfindConshdlr(sourcescip, "linear");
7181 assert( conshdlrlinear != NULL );
7182
7183 /* if copying scip after transforming the original instance before presolving, we need to correct the linear
7184 * constraint pointer */
7185 if ( SCIPisTransformed(sourcescip) && ! SCIPconsIsTransformed(sourcelincons) )
7186 {
7187 SCIP_CONS* translincons;
7188
7189 /* adjust the linear constraint in the original constraint (no need to release translincons) */
7190 SCIP_CALL( SCIPgetTransformedCons(sourcescip, sourcelincons, &translincons) );
7191 assert( translincons != NULL );
7192 SCIP_CALL( SCIPreleaseCons(sourcescip, &sourceconsdata->lincons) );
7193 SCIP_CALL( SCIPcaptureCons(sourcescip, translincons) );
7194 sourceconsdata->lincons = translincons;
7195 sourcelincons = translincons;
7196 }
7197
7198 SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, sourcelincons, &targetlincons, conshdlrlinear, varmap, consmap, SCIPconsGetName(sourcelincons),
7199 SCIPconsIsInitial(sourcelincons), SCIPconsIsSeparated(sourcelincons), SCIPconsIsEnforced(sourcelincons), SCIPconsIsChecked(sourcelincons),
7200 SCIPconsIsPropagated(sourcelincons), SCIPconsIsLocal(sourcelincons), SCIPconsIsModifiable(sourcelincons), SCIPconsIsDynamic(sourcelincons),
7201 SCIPconsIsRemovable(sourcelincons), SCIPconsIsStickingAtNode(sourcelincons), global, valid) );
7202 }
7203
7204 /* find copied variable corresponding to binvar */
7205 if ( *valid )
7206 {
7207 SCIP_VAR* sourcebinvar;
7208
7209 sourcebinvar = sourceconsdata->binvar;
7210 assert( sourcebinvar != NULL );
7211
7212 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcebinvar, &targetbinvar, varmap, consmap, global, valid) );
7213 }
7214
7215 /* find copied variable corresponding to slackvar */
7216 if ( *valid )
7217 {
7218 SCIP_VAR* sourceslackvar;
7219
7220 sourceslackvar = sourceconsdata->slackvar;
7221 assert( sourceslackvar != NULL );
7222
7223 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourceslackvar, &targetslackvar, varmap, consmap, global, valid) );
7224 }
7225
7226 /* create indicator constraint */
7227 if ( *valid )
7228 {
7229 assert( targetlincons != NULL );
7230 assert( targetbinvar != NULL );
7231 assert( targetslackvar != NULL );
7232
7233 /* creates indicator constraint (and captures the linear constraint) */
7234 /* Note that the copied constraint has activeone = TRUE, since the target binary variable already was negated if needed. */
7235 SCIP_CALL( SCIPcreateConsIndicatorGenericLinCons(scip, cons, consname, targetbinvar, targetlincons, targetslackvar, TRUE,
7236 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
7237 }
7238 else
7239 {
7240 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "could not copy linear constraint <%s>\n", SCIPconsGetName(sourcelincons));
7241 }
7242
7243 /* release copied linear constraint */
7244 if ( targetlincons != NULL )
7245 {
7246 SCIP_CALL( SCIPreleaseCons(scip, &targetlincons) );
7247 }
7248
7249 return SCIP_OKAY;
7250}
7251
7252
7253/** constraint parsing method of constraint handler */
7254static
7255SCIP_DECL_CONSPARSE(consParseIndicator)
7256{ /*lint --e{715}*/
7257 char binvarname[1024];
7258 char slackvarname[1024];
7259 char linconsname[1024];
7260 SCIP_VAR* binvar;
7261 SCIP_VAR* slackvar;
7262 SCIP_CONS* lincons;
7263 int zeroone;
7264 int nargs;
7265
7266 *success = TRUE;
7267
7268 /* read indicator constraint */
7269 /* coverity[secure_coding] */
7270 nargs = sscanf(str, " <%1023[^>]> = %d -> <%1023[^>]> = 0 (<%1023[^>]>)", binvarname, &zeroone, slackvarname, linconsname);
7271
7272 /* downward compatible: accept missing linear constraint at end */
7273 if ( nargs != 3 && nargs != 4 )
7274 {
7275 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0 (<lincons>).\n%s\n", str);
7276 *success = FALSE;
7277 return SCIP_OKAY;
7278 }
7279
7280 if ( zeroone != 0 && zeroone != 1 )
7281 {
7282 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <var> = 0.\n%s\n", str);
7283 *success = FALSE;
7284 return SCIP_OKAY;
7285 }
7286
7287 /* get binary variable */
7288 binvar = SCIPfindVar(scip, binvarname);
7289 if ( binvar == NULL )
7290 {
7291 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", binvarname);
7292 *success = FALSE;
7293 return SCIP_OKAY;
7294 }
7295 /* check whether we need the complemented variable */
7296 if ( zeroone == 0 )
7297 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
7298
7299 /* get slack variable */
7300 slackvar = SCIPfindVar(scip, slackvarname);
7301 if ( slackvar == NULL )
7302 {
7303 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", slackvarname);
7304 *success = FALSE;
7305 return SCIP_OKAY;
7306 }
7307
7308 /* determine linear constraint */
7309 if ( nargs == 4 )
7310 {
7311 lincons = SCIPfindCons(scip, linconsname);
7312 if ( lincons == NULL )
7313 {
7314 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown constraint <%s>\n", linconsname);
7315 *success = FALSE;
7316 return SCIP_OKAY;
7317 }
7318 if ( strncmp(SCIPconshdlrGetName(SCIPconsGetHdlr(lincons)), "linear", 6) != 0 )
7319 {
7320 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "constraint <%s> is not linear\n", linconsname);
7321 *success = FALSE;
7322 return SCIP_OKAY;
7323 }
7324 }
7325 else
7326 {
7327 const char* posstr;
7328
7329 /* for backward compability try to determine name of linear constraint from variables names */
7330 assert( nargs == 3 );
7331
7332 /* find matching linear constraint */
7333 posstr = strstr(slackvarname, "indslack");
7334 if ( posstr == NULL )
7335 {
7336 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "strange slack variable name: <%s>\n", slackvarname);
7337 *success = FALSE;
7338 return SCIP_OKAY;
7339 }
7340
7341 /* overwrite binvarname: set up name for linear constraint */
7342 (void) SCIPsnprintf(binvarname, 1023, "indlin%s", posstr+8);
7343
7344 lincons = SCIPfindCons(scip, binvarname);
7345 if ( lincons == NULL )
7346 {
7347 /* if not found - check without indlin */
7348 (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+9);
7349 lincons = SCIPfindCons(scip, binvarname);
7350
7351 if ( lincons == NULL )
7352 {
7353 /* if not found - check without indrhs or indlhs */
7354 (void) SCIPsnprintf(binvarname, 1023, "%s", posstr+16);
7355 lincons = SCIPfindCons(scip, binvarname);
7356
7357 if( lincons == NULL )
7358 {
7359 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: unknown linear constraint <indlin%s>, <%s> or <%s>.\n",
7360 name, posstr+8, posstr+9, posstr+16);
7361 *success = FALSE;
7362 return SCIP_OKAY;
7363 }
7364 }
7365 }
7366 }
7367 assert( lincons != NULL );
7368
7369 /* check correct linear constraint */
7370 if ( ! SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, lincons)) && ! SCIPisInfinity(scip, SCIPgetRhsLinear(scip, lincons)) )
7371 {
7372 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "while parsing indicator constraint <%s>: linear constraint is ranged or equation.\n", name);
7373 *success = FALSE;
7374 return SCIP_OKAY;
7375 }
7376
7377 /* create indicator constraint */
7378 SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
7379 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
7380
7381 return SCIP_OKAY;
7382}
7383
7384
7385/** constraint enabling notification method of constraint handler */
7386static
7387SCIP_DECL_CONSENABLE(consEnableIndicator)
7388{
7389 SCIP_CONSHDLRDATA* conshdlrdata;
7390 SCIP_CONSDATA* consdata;
7391
7392 assert( scip != NULL );
7393 assert( conshdlr != NULL );
7394 assert( cons != NULL );
7395 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7396
7397#ifdef SCIP_MORE_DEBUG
7398 SCIPdebugMsg(scip, "Enabling constraint <%s>.\n", SCIPconsGetName(cons));
7399#endif
7400
7401 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7402 assert( conshdlrdata != NULL );
7403
7404 consdata = SCIPconsGetData(cons);
7405 assert( consdata != NULL );
7406
7407 if ( conshdlrdata->altlp != NULL )
7408 {
7409 assert( conshdlrdata->sepaalternativelp );
7410
7411 if ( consdata->colindex >= 0 )
7412 {
7413 SCIP_CALL( unfixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
7414 }
7415 }
7416
7417 return SCIP_OKAY;
7418}
7419
7420
7421/** constraint disabling notification method of constraint handler */
7422static
7423SCIP_DECL_CONSDISABLE(consDisableIndicator)
7424{
7425 SCIP_CONSHDLRDATA* conshdlrdata;
7426
7427 assert( scip != NULL );
7428 assert( conshdlr != NULL );
7429 assert( cons != NULL );
7430 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7431
7432#ifdef SCIP_MORE_DEBUG
7433 SCIPdebugMsg(scip, "Disabling constraint <%s>.\n", SCIPconsGetName(cons));
7434#endif
7435
7436 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7437 assert( conshdlrdata != NULL );
7438
7439 if ( conshdlrdata->altlp != NULL )
7440 {
7441 SCIP_CONSDATA* consdata;
7442
7443 consdata = SCIPconsGetData(cons);
7444 assert( consdata != NULL );
7445 assert( conshdlrdata->sepaalternativelp );
7446
7447 if ( consdata->colindex >= 0 )
7448 {
7449 SCIP_CALL( fixAltLPVariable(conshdlrdata->altlp, consdata->colindex) );
7450 }
7451 }
7452
7453 return SCIP_OKAY;
7454}
7455
7456
7457/** constraint method of constraint handler which returns the variables (if possible) */
7458static
7459SCIP_DECL_CONSGETVARS(consGetVarsIndicator)
7460{ /*lint --e{715}*/
7461 SCIP_CONSDATA* consdata;
7462 int nvars = 0;
7463
7464 assert( scip != NULL );
7465 assert( cons != NULL );
7466 assert( vars != NULL );
7467 assert( success != NULL );
7468
7469 if ( varssize < 0 )
7470 return SCIP_INVALIDDATA;
7471 assert( varssize >= 0 );
7472
7473 (*success) = TRUE;
7474
7475 /* if indicator constraint is already deleted */
7476 if ( SCIPconsIsDeleted(cons) )
7477 return SCIP_OKAY;
7478
7479 consdata = SCIPconsGetData(cons);
7480 assert( consdata != NULL );
7481 assert( consdata->lincons != NULL );
7482
7483 if ( consdata->binvar != NULL )
7484 {
7485 assert( varssize > 0 );
7486 vars[nvars++] = consdata->binvar;
7487 }
7488 if ( consdata->slackvar != NULL )
7489 {
7490 assert( varssize > nvars );
7491 vars[nvars++] = consdata->slackvar;
7492 }
7493
7494 /* if linear constraint of indicator is already deleted */
7495 if ( SCIPconsIsDeleted(consdata->lincons) )
7496 return SCIP_OKAY;
7497
7498 SCIP_CALL( SCIPgetConsVars(scip, consdata->lincons, &(vars[nvars]), varssize - nvars, success) );
7499
7500 return SCIP_OKAY;
7501}
7502
7503
7504/** constraint method of constraint handler which returns the number of variables (if possible) */
7505static
7506SCIP_DECL_CONSGETNVARS(consGetNVarsIndicator)
7507{ /*lint --e{715}*/
7508 SCIP_CONSDATA* consdata;
7509 int nlinvars;
7510
7511 assert( scip != NULL );
7512 assert( cons != NULL );
7513 assert( nvars != NULL );
7514 assert( success != NULL );
7515
7516 *success = TRUE;
7517 *nvars = 0;
7518
7519 /* if indicator constraint is already deleted */
7520 if ( SCIPconsIsDeleted(cons) )
7521 return SCIP_OKAY;
7522
7523 consdata = SCIPconsGetData(cons);
7524 assert( consdata != NULL );
7525 assert( consdata->lincons != NULL );
7526
7527 if ( consdata->binvar != NULL )
7528 ++(*nvars);
7529 if ( consdata->slackvar != NULL )
7530 ++(*nvars);
7531
7532 /* if linear constraint of indicator is already deleted */
7533 if ( SCIPconsIsDeleted(consdata->lincons) )
7534 return SCIP_OKAY;
7535
7536 SCIP_CALL( SCIPgetConsNVars(scip, consdata->lincons, &nlinvars, success) );
7537
7538 if ( *success )
7539 {
7540 assert( nlinvars >= 0 );
7541 *nvars += nlinvars;
7542 }
7543
7544 return SCIP_OKAY;
7545}
7546
7547
7548/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
7549static
7550SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsIndicator)
7551{
7552 SCIP_CONS** indconss;
7553 int nindconss;
7554 int c;
7555 SCIP_VAR* bestvar = NULL;
7556 SCIP_Bool bestvarroundup = FALSE;
7557 SCIP_Real bestscore = SCIP_REAL_MIN;
7558
7559 assert(scip != NULL);
7560 assert(conshdlr != NULL);
7561 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7562 assert(diveset != NULL);
7563 assert(success != NULL);
7564 assert(infeasible != NULL);
7565
7566 *success = FALSE;
7567 *infeasible = FALSE;
7568
7569 indconss = SCIPconshdlrGetConss(conshdlr);
7570 nindconss = SCIPconshdlrGetNConss(conshdlr);
7571
7572 /* loop over indicator constraints and score indicator variables with already integral solution value */
7573 for (c = 0; c < nindconss; ++c)
7574 {
7575 /* check whether constraint is violated */
7576 if ( SCIPisViolatedIndicator(scip, indconss[c], sol) )
7577 {
7578 SCIP_VAR* binvar;
7579 SCIP_Real solval;
7580
7581 binvar = SCIPgetBinaryVarIndicator(indconss[c]);
7582 solval = SCIPgetSolVal(scip, sol, binvar);
7583
7584 /* we only treat indicator variables with integral solution values that are not yet fixed */
7585 if ( SCIPisFeasIntegral(scip, solval) && SCIPvarGetLbLocal(binvar) < SCIPvarGetUbLocal(binvar) - 0.5 )
7586 {
7587 SCIP_Real score;
7588 SCIP_Bool roundup;
7589
7590 SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_INTEGRALITY, binvar, solval, 0.0,
7591 &score, &roundup) );
7592
7593 /* best candidate maximizes the score */
7594 if ( score > bestscore )
7595 {
7596 bestscore = score;
7597 *success = TRUE;
7598 bestvar = binvar;
7599 bestvarroundup = roundup;
7600 }
7601 }
7602 }
7603 }
7604
7605 assert(! *success || bestvar != NULL);
7606
7607 if ( *success )
7608 {
7609 /* if the diving score voted for fixing the best variable to 1.0, we add this as the preferred bound change */
7610 SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_UPWARDS, 1.0, bestvarroundup) );
7611 SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_DOWNWARDS, 0.0, ! bestvarroundup) );
7612 }
7613
7614 return SCIP_OKAY;
7615}
7616
7617/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
7618static
7619SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphIndicator)
7620{ /*lint --e{715}*/
7621 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
7622
7623 return SCIP_OKAY;
7624}
7625
7626/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
7627static
7628SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphIndicator)
7629{ /*lint --e{715}*/
7630 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
7631
7632 return SCIP_OKAY;
7633}
7634
7635/* ---------------- Constraint specific interface methods ---------------- */
7636
7637/** creates the handler for indicator constraints and includes it in SCIP */
7639 SCIP* scip /**< SCIP data structure */
7640 )
7641{
7642 SCIP_CONFLICTHDLRDATA* conflicthdlrdata;
7643 SCIP_CONFLICTHDLR* conflicthdlr;
7644 SCIP_CONSHDLRDATA* conshdlrdata;
7645 SCIP_CONSHDLR* conshdlr;
7646
7647 /* create constraint handler data (used in conflicthdlrdata) */
7648 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
7649
7650 /* create event handler for bound change events */
7651 conshdlrdata->eventhdlrbound = NULL;
7653 eventExecIndicatorBound, NULL) );
7654 assert(conshdlrdata->eventhdlrbound != NULL);
7655
7656 /* create event handler for bound change events on linear constraint */
7657 conshdlrdata->eventhdlrlinconsbound = NULL;
7659 eventExecIndicatorLinconsBound, NULL) );
7660 assert(conshdlrdata->eventhdlrlinconsbound != NULL);
7661
7662 /* create event handler for restart events */
7663 conshdlrdata->eventhdlrrestart = NULL;
7665 eventExecIndicatorRestart, NULL) );
7666 assert( conshdlrdata->eventhdlrrestart != NULL );
7667
7668 conshdlrdata->heurtrysol = NULL;
7669 conshdlrdata->sepaalternativelp = DEFAULT_SEPAALTERNATIVELP;
7670 conshdlrdata->nolinconscont = DEFAULT_NOLINCONSCONT;
7671 conshdlrdata->forcerestart = DEFAULT_FORCERESTART;
7672 conshdlrdata->binvarhash = NULL;
7673 conshdlrdata->binslackvarhash = NULL;
7674
7675 /* initialize constraint handler data */
7676 initConshdlrData(scip, conshdlrdata);
7677
7678 /* the following three variables cannot be initialized in the above method, because initConshdlrData() is also called
7679 * in the CONSINIT callback, but these variables might be used even before the is ccallback is called, so we would
7680 * lose the data added before calling this callback */
7681 conshdlrdata->addlincons = NULL;
7682 conshdlrdata->naddlincons = 0;
7683 conshdlrdata->maxaddlincons = 0;
7684
7685 /* include constraint handler */
7688 consEnfolpIndicator, consEnfopsIndicator, consCheckIndicator, consLockIndicator,
7689 conshdlrdata) );
7690
7691 assert( conshdlr != NULL );
7692
7693 /* set non-fundamental callbacks via specific setter functions */
7694 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyIndicator, consCopyIndicator) );
7695 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteIndicator) );
7696 SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableIndicator) );
7697 SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableIndicator) );
7698 SCIP_CALL( SCIPsetConshdlrGetDiveBdChgs(scip, conshdlr, consGetDiveBdChgsIndicator) );
7699 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitIndicator) );
7700 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolIndicator) );
7701 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeIndicator) );
7702 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsIndicator) );
7703 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsIndicator) );
7704 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitIndicator) );
7705 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreIndicator) );
7706 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolIndicator) );
7707 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpIndicator) );
7708 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseIndicator) );
7710 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintIndicator) );
7713 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropIndicator) );
7714 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpIndicator, consSepasolIndicator, CONSHDLR_SEPAFREQ,
7716 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransIndicator) );
7717 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxIndicator) );
7718 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphIndicator) );
7719 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphIndicator) );
7720
7721 /* add upgrading method */
7722 if ( SCIPfindConshdlr(scip, "linear") != NULL )
7723 {
7724 /* include the linear constraint upgrade in the linear constraint handler */
7726 }
7727
7728 /* create conflict handler data */
7729 SCIP_CALL( SCIPallocBlockMemory(scip, &conflicthdlrdata) );
7730 conflicthdlrdata->conshdlrdata = conshdlrdata;
7731 conflicthdlrdata->conshdlr = conshdlr;
7732 assert( conflicthdlrdata->conshdlr != NULL );
7733
7734 /* create conflict handler for indicator constraints */
7736 conflictExecIndicator, conflicthdlrdata) );
7737
7738 SCIP_CALL( SCIPsetConflicthdlrFree(scip, conflicthdlr, conflictFreeIndicator) );
7739
7740 /* add indicator constraint handler parameters */
7742 "constraints/indicator/branchindicators",
7743 "Branch on indicator constraints in enforcing?",
7744 &conshdlrdata->branchindicators, TRUE, DEFAULT_BRANCHINDICATORS, NULL, NULL) );
7745
7747 "constraints/indicator/genlogicor",
7748 "Generate logicor constraints instead of cuts?",
7749 &conshdlrdata->genlogicor, TRUE, DEFAULT_GENLOGICOR, NULL, NULL) );
7750
7752 "constraints/indicator/addcoupling",
7753 "Add coupling constraints or rows if big-M is small enough?",
7754 &conshdlrdata->addcoupling, TRUE, DEFAULT_ADDCOUPLING, NULL, NULL) );
7755
7757 "constraints/indicator/maxcouplingvalue",
7758 "maximum coefficient for binary variable in coupling constraint",
7759 &conshdlrdata->maxcouplingvalue, TRUE, DEFAULT_MAXCOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
7760
7762 "constraints/indicator/addcouplingcons",
7763 "Add initial variable upper bound constraints, if 'addcoupling' is true?",
7764 &conshdlrdata->addcouplingcons, TRUE, DEFAULT_ADDCOUPLINGCONS, NULL, NULL) );
7765
7767 "constraints/indicator/sepacouplingcuts",
7768 "Should the coupling inequalities be separated dynamically?",
7769 &conshdlrdata->sepacouplingcuts, TRUE, DEFAULT_SEPACOUPLINGCUTS, NULL, NULL) );
7770
7772 "constraints/indicator/sepacouplinglocal",
7773 "Allow to use local bounds in order to separate coupling inequalities?",
7774 &conshdlrdata->sepacouplinglocal, TRUE, DEFAULT_SEPACOUPLINGLOCAL, NULL, NULL) );
7775
7777 "constraints/indicator/sepacouplingvalue",
7778 "maximum coefficient for binary variable in separated coupling constraint",
7779 &conshdlrdata->sepacouplingvalue, TRUE, DEFAULT_SEPACOUPLINGVALUE, 0.0, 1e9, NULL, NULL) );
7780
7782 "constraints/indicator/sepaperspective",
7783 "Separate cuts based on perspective formulation?",
7784 &conshdlrdata->sepaperspective, TRUE, DEFAULT_SEPAPERSPECTIVE, NULL, NULL) );
7785
7787 "constraints/indicator/sepapersplocal",
7788 "Allow to use local bounds in order to separate perspective cuts?",
7789 &conshdlrdata->sepapersplocal, TRUE, DEFAULT_SEPAPERSPLOCAL, NULL, NULL) );
7790
7792 "constraints/indicator/maxsepanonviolated",
7793 "maximal number of separated non violated IISs, before separation is stopped",
7794 &conshdlrdata->maxsepanonviolated, FALSE, DEFAULT_MAXSEPANONVIOLATED, 0, INT_MAX, NULL, NULL) );
7795
7797 "constraints/indicator/updatebounds",
7798 "Update bounds of original variables for separation?",
7799 &conshdlrdata->updatebounds, TRUE, DEFAULT_UPDATEBOUNDS, NULL, NULL) );
7800
7802 "constraints/indicator/maxconditionaltlp",
7803 "maximum estimated condition of the solution basis matrix of the alternative LP to be trustworthy (0.0 to disable check)",
7804 &conshdlrdata->maxconditionaltlp, TRUE, DEFAULT_MAXCONDITIONALTLP, 0.0, SCIP_REAL_MAX, NULL, NULL) );
7805
7807 "constraints/indicator/maxsepacuts",
7808 "maximal number of cuts separated per separation round",
7809 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
7810
7812 "constraints/indicator/maxsepacutsroot",
7813 "maximal number of cuts separated per separation round in the root node",
7814 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
7815
7817 "constraints/indicator/removeindicators",
7818 "Remove indicator constraint if corresponding variable bound constraint has been added?",
7819 &conshdlrdata->removeindicators, TRUE, DEFAULT_REMOVEINDICATORS, NULL, NULL) );
7820
7822 "constraints/indicator/generatebilinear",
7823 "Do not generate indicator constraint, but a bilinear constraint instead?",
7824 &conshdlrdata->generatebilinear, TRUE, DEFAULT_GENERATEBILINEAR, NULL, NULL) );
7825
7827 "constraints/indicator/scaleslackvar",
7828 "Scale slack variable coefficient at construction time?",
7829 &conshdlrdata->scaleslackvar, TRUE, DEFAULT_SCALESLACKVAR, NULL, NULL) );
7830
7832 "constraints/indicator/trysolutions",
7833 "Try to make solutions feasible by setting indicator variables?",
7834 &conshdlrdata->trysolutions, TRUE, DEFAULT_TRYSOLUTIONS, NULL, NULL) );
7835
7837 "constraints/indicator/enforcecuts",
7838 "In enforcing try to generate cuts (only if sepaalternativelp is true)?",
7839 &conshdlrdata->enforcecuts, TRUE, DEFAULT_ENFORCECUTS, NULL, NULL) );
7840
7842 "constraints/indicator/dualreductions",
7843 "Should dual reduction steps be performed?",
7844 &conshdlrdata->dualreductions, TRUE, DEFAULT_DUALREDUCTIONS, NULL, NULL) );
7845
7847 "constraints/indicator/addopposite",
7848 "Add opposite inequality in nodes in which the binary variable has been fixed to 0?",
7849 &conshdlrdata->addopposite, TRUE, DEFAULT_ADDOPPOSITE, NULL, NULL) );
7850
7852 "constraints/indicator/conflictsupgrade",
7853 "Try to upgrade bounddisjunction conflicts by replacing slack variables?",
7854 &conshdlrdata->conflictsupgrade, TRUE, DEFAULT_CONFLICTSUPGRADE, NULL, NULL) );
7855
7857 "constraints/indicator/restartfrac",
7858 "fraction of binary variables that need to be fixed before restart occurs (in forcerestart)",
7859 &conshdlrdata->restartfrac, TRUE, DEFAULT_RESTARTFRAC, 0.0, 1.0, NULL, NULL) );
7860
7862 "constraints/indicator/useotherconss",
7863 "Collect other constraints to alternative LP?",
7864 &conshdlrdata->useotherconss, TRUE, DEFAULT_USEOTHERCONSS, NULL, NULL) );
7865
7867 "constraints/indicator/useobjectivecut",
7868 "Use objective cut with current best solution to alternative LP?",
7869 &conshdlrdata->useobjectivecut, TRUE, DEFAULT_USEOBJECTIVECUT, NULL, NULL) );
7870
7872 "constraints/indicator/trysolfromcover",
7873 "Try to construct a feasible solution from a cover?",
7874 &conshdlrdata->trysolfromcover, TRUE, DEFAULT_TRYSOLFROMCOVER, NULL, NULL) );
7875
7877 "constraints/indicator/upgradelinear",
7878 "Try to upgrade linear constraints to indicator constraints?",
7879 &conshdlrdata->upgradelinear, TRUE, DEFAULT_UPGRADELINEAR, NULL, NULL) );
7880
7882 "constraints/indicator/usesameslackvar",
7883 "Use same slack variable for indicator constraints with common binary variable?",
7884 &conshdlrdata->usesameslackvar, TRUE, DEFAULT_USESAMESLACKVAR, NULL, NULL) );
7885
7886 /* parameters that should not be changed after problem stage: */
7888 "constraints/indicator/sepaalternativelp",
7889 "Separate using the alternative LP?",
7890 &conshdlrdata->sepaalternativelp_, TRUE, DEFAULT_SEPAALTERNATIVELP, paramChangedIndicator, NULL) );
7891
7893 "constraints/indicator/forcerestart",
7894 "Force restart if absolute gap is 1 or enough binary variables have been fixed?",
7895 &conshdlrdata->forcerestart_, TRUE, DEFAULT_FORCERESTART, paramChangedIndicator, NULL) );
7896
7898 "constraints/indicator/nolinconscont",
7899 "Decompose problem (do not generate linear constraint if all variables are continuous)?",
7900 &conshdlrdata->nolinconscont_, TRUE, DEFAULT_NOLINCONSCONT, paramChangedIndicator, NULL) );
7901
7902 return SCIP_OKAY;
7903}
7904
7905/** creates and captures an indicator constraint
7906 *
7907 * @note @a binvar is checked to be binary only later. This enables a change of the type in
7908 * procedures reading an instance.
7909 *
7910 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7911 */
7913 SCIP* scip, /**< SCIP data structure */
7914 SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
7915 const char* name, /**< name of constraint */
7916 SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
7917 int nvars, /**< number of variables in the inequality */
7918 SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
7919 SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
7920 SCIP_Real rhs, /**< rhs of the inequality */
7921 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
7922 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
7923 * Usually set to TRUE. */
7924 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
7925 * TRUE for model constraints, FALSE for additional, redundant constraints. */
7926 SCIP_Bool check, /**< should the constraint be checked for feasibility?
7927 * TRUE for model constraints, FALSE for additional, redundant constraints. */
7928 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
7929 * Usually set to TRUE. */
7930 SCIP_Bool local, /**< is constraint only valid locally?
7931 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7932 SCIP_Bool dynamic, /**< is constraint subject to aging?
7933 * Usually set to FALSE. Set to TRUE for own cuts which
7934 * are separated as constraints. */
7935 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
7936 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
7937 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
7938 * if it may be moved to a more global node?
7939 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
7940 )
7941{
7942 return SCIPcreateConsIndicatorGeneric(scip, cons, name, binvar, nvars, vars, vals, rhs, TRUE, TRUE, initial,
7943 separate, enforce, check, propagate, local, dynamic, removable, stickingatnode);
7944}
7945
7946/** creates and captures a indicator constraint in a more generic version.
7947 *
7948 * The key difference from SCIPcreateConsIndicator() is the activeone and lessthanineq Booleans.
7949 * If \f$z = o\f$, with \f$o\f$ the activeone flag, then:
7950 * 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$.
7951 * The underlying linear constraint is always created as a less-than inequality.
7952 */
7954 SCIP* scip, /**< SCIP data structure */
7955 SCIP_CONS** cons, /**< pointer to hold the created constraint (indicator or quadratic) */
7956 const char* name, /**< name of constraint */
7957 SCIP_VAR* binvar, /**< binary indicator variable (or NULL) */
7958 int nvars, /**< number of variables in the inequality */
7959 SCIP_VAR** vars, /**< array with variables of inequality (or NULL) */
7960 SCIP_Real* vals, /**< values of variables in inequality (or NULL) */
7961 SCIP_Real rhs, /**< rhs of the inequality */
7962 SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
7963 SCIP_Bool lessthanineq, /**< is the linear constraint a less than RHS (TRUE) or greater than RHS (FALSE)? */
7964 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
7965 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
7966 * Usually set to TRUE. */
7967 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
7968 * TRUE for model constraints, FALSE for additional, redundant constraints. */
7969 SCIP_Bool check, /**< should the constraint be checked for feasibility?
7970 * TRUE for model constraints, FALSE for additional, redundant constraints. */
7971 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
7972 * Usually set to TRUE. */
7973 SCIP_Bool local, /**< is constraint only valid locally?
7974 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7975 SCIP_Bool dynamic, /**< is constraint subject to aging?
7976 * Usually set to FALSE. Set to TRUE for own cuts which
7977 * are separated as constraints. */
7978 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
7979 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
7980 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
7981 * if it may be moved to a more global node?
7982 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
7983 )
7984{
7985 SCIP_CONSHDLR* conshdlr;
7986 SCIP_CONSHDLRDATA* conshdlrdata;
7987 SCIP_CONSDATA* consdata = NULL;
7988 SCIP_CONS* lincons;
7989 SCIP_VAR* slackvar = NULL;
7990 SCIP_VAR* binvarinternal;
7991 SCIP_Bool modifiable = FALSE;
7992 SCIP_Bool linconsactive = TRUE;
7993 SCIP_VARTYPE slackvartype;
7994 SCIP_Real absvalsum = 0.0;
7995 char s[SCIP_MAXSTRLEN];
7996 SCIP_Real* valscopy;
7997 int j;
7998
7999 if ( nvars < 0 )
8000 {
8001 SCIPerrorMessage("Indicator constraint <%s> needs nonnegative number of variables in linear constraint.\n", name);
8002 return SCIP_INVALIDDATA;
8003 }
8004
8005 /* find the indicator constraint handler */
8006 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
8007 if ( conshdlr == NULL )
8008 {
8009 SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
8010 return SCIP_PLUGINNOTFOUND;
8011 }
8012
8013 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8014 assert( conshdlrdata != NULL );
8015
8016 if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
8017 {
8018 SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
8019 return SCIP_INVALIDDATA;
8020 }
8021
8022 if ( conshdlrdata->nolinconscont && conshdlrdata->generatebilinear )
8023 {
8024 SCIPerrorMessage("constraint handler <%s>: parameters <nolinconscont> and <generatebilinear> cannot both be true.\n", CONSHDLR_NAME);
8025 return SCIP_INVALIDDATA;
8026 }
8027
8028 valscopy = NULL;
8029 if ( lessthanineq )
8030 valscopy = vals;
8031 else
8032 {
8033 /* flip coefficients and RHS of indicator */
8034 SCIP_CALL( SCIPallocBufferArray(scip, &valscopy, nvars) );
8035 for (j = 0; j < nvars; ++j)
8036 valscopy[j] = -vals[j];
8037 rhs = -rhs;
8038 }
8039 assert( nvars == 0 || valscopy != NULL );
8040
8041 /* check if slack variable can be made implicit integer */
8042 slackvartype = SCIP_VARTYPE_IMPLINT;
8043 for (j = 0; j < nvars; ++j)
8044 {
8045 if ( conshdlrdata->scaleslackvar )
8046 absvalsum += REALABS(valscopy[j]);
8047 if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, valscopy[j]) )
8048 {
8049 slackvartype = SCIP_VARTYPE_CONTINUOUS;
8050 if ( ! conshdlrdata->scaleslackvar )
8051 break;
8052 }
8053 }
8054
8055 /* if active on 0, a provided binary variable is reversed */
8056 if ( activeone || binvar == NULL )
8057 binvarinternal = binvar;
8058 else
8059 {
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 reversed */
8382 SCIP_VAR* binvarinternal;
8383 if ( activeone )
8384 {
8385 binvarinternal = binvar;
8386 }
8387 else
8388 {
8389 SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
8390 }
8391
8392 /* create a quadratic constraint with a single bilinear term - note that cons is used */
8393 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
8395 }
8396 else
8397 {
8398 /* create constraint data */
8399 SCIP_CALL( consdataCreate(scip, conshdlr, conshdlrdata, name, &consdata, conshdlrdata->eventhdlrrestart,
8400 binvar, activeone, TRUE, slackvar, lincons, linconsactive) );
8401 assert( consdata != NULL );
8402
8403 /* create constraint */
8404 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
8405 local, modifiable, dynamic, removable, stickingatnode) );
8406
8407 /* catch local bound change events on binary variable */
8408 if ( consdata->linconsactive && SCIPisTransformed(scip) )
8409 {
8410 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->binvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
8411 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->slackvar, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlrbound, (SCIP_EVENTDATA*) *cons, NULL) );
8412 }
8413 }
8414
8415 /* capture slack variable and linear constraint */
8416 SCIP_CALL( SCIPcaptureVar(scip, slackvar) );
8417 SCIP_CALL( SCIPcaptureCons(scip, lincons) );
8418
8419 return SCIP_OKAY;
8420}
8421
8422/** creates and captures an indicator constraint with given linear constraint and slack variable
8423 *
8424 * @note @a binvar is checked to be binary only later. This enables a change of the type in
8425 * procedures reading an instance.
8426 *
8427 * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
8428 * the role of a slack variable!
8429 *
8430 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8431 */
8433 SCIP* scip, /**< SCIP data structure */
8434 SCIP_CONS** cons, /**< pointer to hold the created constraint */
8435 const char* name, /**< name of constraint */
8436 SCIP_VAR* binvar, /**< binary indicator variable */
8437 SCIP_CONS* lincons, /**< linear constraint */
8438 SCIP_VAR* slackvar, /**< slack variable */
8439 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
8440 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
8441 * Usually set to TRUE. */
8442 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
8443 * TRUE for model constraints, FALSE for additional, redundant constraints. */
8444 SCIP_Bool check, /**< should the constraint be checked for feasibility?
8445 * TRUE for model constraints, FALSE for additional, redundant constraints. */
8446 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
8447 * Usually set to TRUE. */
8448 SCIP_Bool local, /**< is constraint only valid locally?
8449 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
8450 SCIP_Bool dynamic, /**< is constraint subject to aging?
8451 * Usually set to FALSE. Set to TRUE for own cuts which
8452 * are separated as constraints. */
8453 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
8454 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
8455 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
8456 * if it may be moved to a more global node?
8457 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
8458 )
8459{
8460 return SCIPcreateConsIndicatorGenericLinCons(scip, cons, name, binvar, lincons, slackvar, TRUE, initial, separate,
8461 enforce, check, propagate, local, dynamic, removable, stickingatnode);
8462}
8463
8464
8465/** creates and captures an indicator constraint with given linear constraint and slack variable
8466 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
8467 * method SCIPcreateConsIndicator(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
8468 *
8469 * @note @a binvar is checked to be binary only later. This enables a change of the type in
8470 * procedures reading an instance.
8471 *
8472 * @note we assume that @a slackvar actually appears in @a lincons and we also assume that it takes
8473 * the role of a slack variable!
8474 *
8475 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8476 *
8477 * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
8478 *
8479 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8480 */
8482 SCIP* scip, /**< SCIP data structure */
8483 SCIP_CONS** cons, /**< pointer to hold the created constraint */
8484 const char* name, /**< name of constraint */
8485 SCIP_VAR* binvar, /**< binary indicator variable */
8486 SCIP_CONS* lincons, /**< linear constraint */
8487 SCIP_VAR* slackvar /**< slack variable */
8488 )
8489{
8490 assert( scip != NULL );
8491
8492 SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, cons, name, binvar, lincons, slackvar,
8494
8495 return SCIP_OKAY;
8496}
8497
8498
8499/** creates and captures an indicator constraint with given linear constraint in a generic version, i. e., with a flag
8500 * activeone indicating whether the constraint is active on value 1 or 0 of the binary variable; no slack variable is
8501 * given
8502
8503 * @note @a binvar is checked to be binary only later. This enables a change of the type in
8504 * procedures reading an instance.
8505 *
8506 * @note The linear constraint must be single-sided, i.e., either rhs or lhs have to be infinite.
8507 *
8508 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8509 *
8510 * @see SCIPcreateConsIndicatorLinCons() for information about the basic constraint flag configuration
8511 */
8513 SCIP* scip, /**< SCIP data structure */
8514 SCIP_CONS** cons, /**< pointer to hold the created constraint */
8515 const char* name, /**< name of constraint */
8516 SCIP_VAR* binvar, /**< binary indicator variable */
8517 SCIP_CONS* lincons, /**< linear constraint */
8518 SCIP_Bool activeone, /**< is the constraint active when the binary is 1? */
8519 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? Usually set to TRUE. */
8520 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
8521 * Usually set to TRUE. */
8522 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
8523 * TRUE for model constraints, FALSE for additional, redundant constraints. */
8524 SCIP_Bool check, /**< should the constraint be checked for feasibility?
8525 * TRUE for model constraints, FALSE for additional, redundant constraints. */
8526 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
8527 * Usually set to TRUE. */
8528 SCIP_Bool local, /**< is constraint only valid locally?
8529 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
8530 SCIP_Bool dynamic, /**< is constraint subject to aging?
8531 * Usually set to FALSE. Set to TRUE for own cuts which
8532 * are separated as constraints. */
8533 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
8534 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
8535 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
8536 * if it may be moved to a more global node?
8537 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
8538 )
8539{
8540 char s[SCIP_MAXSTRLEN];
8541 SCIP_CONSHDLR* conshdlr;
8542 SCIP_CONSHDLRDATA* conshdlrdata;
8543 SCIP_CONSDATA* consdata = NULL;
8544 SCIP_Bool modifiable = FALSE;
8545 SCIP_Bool linconsactive = TRUE;
8546 SCIP_VAR* binvarinternal;
8547 SCIP_VAR* slackvar = NULL;
8548 SCIP_VARTYPE slackvartype;
8549 SCIP_VAR** vars;
8550 SCIP_Real* vals;
8551 SCIP_Real sign;
8552 SCIP_Real lhs;
8553 SCIP_Real rhs;
8554 int nvars;
8555 int j;
8556
8557 assert( scip != NULL );
8558 assert( lincons != NULL );
8559 assert( binvar != NULL );
8560
8561 /* check whether lincons is really a linear constraint */
8562 conshdlr = SCIPconsGetHdlr(lincons);
8563 if ( strcmp(SCIPconshdlrGetName(conshdlr), "linear") != 0 )
8564 {
8565 SCIPerrorMessage("Lincons constraint is not linear.\n");
8566 return SCIP_INVALIDDATA;
8567 }
8568
8569 /* find the indicator constraint handler */
8570 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
8571 if ( conshdlr == NULL )
8572 {
8573 SCIPerrorMessage("<%s> constraint handler not found.\n", CONSHDLR_NAME);
8574 return SCIP_PLUGINNOTFOUND;
8575 }
8576
8577 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8578 assert( conshdlrdata != NULL );
8579
8580 if ( conshdlrdata->nolinconscont && ! conshdlrdata->sepaalternativelp )
8581 {
8582 SCIPerrorMessage("constraint handler <%s>: need parameter <sepaalternativelp> to be true if parameter <nolinconscont> is true.\n", CONSHDLR_NAME);
8583 return SCIP_INVALIDDATA;
8584 }
8585
8586 lhs = SCIPgetLhsLinear(scip, lincons);
8587 rhs = SCIPgetRhsLinear(scip, lincons);
8588 if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
8589 {
8590 SCIPerrorMessage("Lincons constraint has finite lhs and rhs.\n");
8591 return SCIP_INVALIDDATA;
8592 }
8593
8594 /* determine type of slack variable */
8595 slackvartype = SCIP_VARTYPE_IMPLINT;
8596 nvars = SCIPgetNVarsLinear(scip, lincons);
8597 vars = SCIPgetVarsLinear(scip, lincons);
8598 vals = SCIPgetValsLinear(scip, lincons);
8599 for (j = 0; j < nvars; ++j)
8600 {
8601 if ( ! SCIPvarIsIntegral(vars[j]) || ! SCIPisIntegral(scip, vals[j]) )
8602 slackvartype = SCIP_VARTYPE_CONTINUOUS;
8603
8604 /* Check whether variable is marked to not be multi-aggregated: this should only be the case for slack variables
8605 * added by the indicator constraint handler. */
8606 if ( SCIPdoNotMultaggrVar(scip, vars[j]) )
8607 {
8608 /* double check name */
8609 if ( strncmp(SCIPvarGetName(vars[j]), "indslack", 8) == 0 )
8610 {
8611 SCIPerrorMessage("Linear constraint <%s> already used in an indicator constraint.\n", SCIPconsGetName(lincons));
8612 return SCIP_INVALIDDATA;
8613 }
8614 }
8615 }
8616
8617 /* if active on 0, the binary variable is reversed */
8618 if ( activeone )
8619 binvarinternal = binvar;
8620 else
8621 {
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:1167
SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:3919
SCIP_Bool SCIPlpiIsInfinity(SCIP_LPI *lpi, SCIP_Real val)
Definition: lpi_clp.cpp:3931
SCIP_Bool SCIPlpiExistsPrimalRay(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2450
SCIP_RETCODE SCIPlpiAddRows(SCIP_LPI *lpi, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition: lpi_clp.cpp:914
SCIP_RETCODE SCIPlpiWriteLP(SCIP_LPI *lpi, const char *fname)
Definition: lpi_clp.cpp:4001
SCIP_RETCODE SCIPlpiGetBounds(SCIP_LPI *lpi, int firstcol, int lastcol, SCIP_Real *lbs, SCIP_Real *ubs)
Definition: lpi_clp.cpp:1709
int SCIPlpiGetInternalStatus(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2752
SCIP_RETCODE SCIPlpiChgBounds(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *lb, const SCIP_Real *ub)
Definition: lpi_clp.cpp:1084
SCIP_Bool SCIPlpiIsPrimalUnbounded(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2488
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:1771
SCIP_RETCODE SCIPlpiGetRealSolQuality(SCIP_LPI *lpi, SCIP_LPSOLQUALITY qualityindicator, SCIP_Real *quality)
Definition: lpi_clp.cpp:2940
SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
Definition: lpi_clp.cpp:3692
SCIP_RETCODE SCIPlpiGetRows(SCIP_LPI *lpi, int firstrow, int lastrow, SCIP_Real *lhs, SCIP_Real *rhs, int *nnonz, int *beg, int *ind, SCIP_Real *val)
Definition: lpi_clp.cpp:1538
SCIP_Bool SCIPlpiIsOptimal(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2623
SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
Definition: lpi_clp.cpp:2788
SCIP_Bool SCIPlpiIsPrimalInfeasible(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2502
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1880
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:1805
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:1240
SCIP_Bool SCIPlpiIsStable(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2647
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
Definition: lpi_clp.cpp:1435
SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
Definition: lpi_clp.cpp:1417
SCIP_RETCODE SCIPlpiChgCoef(SCIP_LPI *lpi, int row, int col, SCIP_Real newval)
Definition: lpi_clp.cpp:1197
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:17070
SCIP_BOUNDTYPE SCIPboundtypeOpposite(SCIP_BOUNDTYPE boundtype)
Definition: lp.c:17231
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:4636
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:4197
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:941
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:4217
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:4670
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:5130
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4593
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:2622
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8244
SCIP_RETCODE SCIPenfopsCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool solinfeasible, SCIP_Bool objinfeasible, SCIP_RESULT *result)
Definition: scip_cons.c:2164
void SCIPconsAddUpgradeLocks(SCIP_CONS *cons, int nlocks)
Definition: cons.c:8653
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8473
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8234
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8383
SCIP_RETCODE SCIPenfolpCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool solinfeasible, SCIP_RESULT *result)
Definition: scip_cons.c:2195
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2537
int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
Definition: cons.c:8665
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8413
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8343
SCIP_RETCODE SCIPsepalpCons(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result)
Definition: scip_cons.c:2284
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8523
SCIP_RETCODE SCIPgetConsVars(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **vars, int varssize, SCIP_Bool *success)
Definition: scip_cons.c:2578
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8403
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8275
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:998
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8433
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8453
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8311
SCIP_RETCODE SCIPdisableCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1872
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8214
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1813
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8463
SCIP_RETCODE SCIPgetTransformedCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONS **transcons)
Definition: scip_cons.c:1675
SCIP_RETCODE SCIPenforelaxCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
Definition: scip_cons.c:2225
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8493
SCIP_RETCODE SCIPsepasolCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_RESULT *result)
Definition: scip_cons.c:2311
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8393
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1139
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1785
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8483
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:17320
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:17241
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17266
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17330
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:17429
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:17379
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:17286
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:17276
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:12496
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:17667
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:17921
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17775
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17626
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17565
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3353
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18171
SCIP_Bool SCIPdoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8709
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:5738
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:17953
SCIP_Real SCIPvarGetAggrScalar(SCIP_VAR *var)
Definition: var.c:17849
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17611
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:18115
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:17795
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17446
SCIP_VAR * SCIPbdchginfoGetVar(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18707
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:17637
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip_var.c:8299
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:6903
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18161
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17601
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition: var.c:17931
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:18105
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8826
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8399
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:12337
SCIP_BOUNDTYPE SCIPbdchginfoGetBoundtype(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18727
SCIP_Real SCIPbdchginfoGetNewbound(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18697
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3295
SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
Definition: scip_var.c:8767
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:8740
SCIP_VAR * SCIPvarGetAggrVar(SCIP_VAR *var)
Definition: var.c:17837
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:5103
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