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