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