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