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