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