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