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