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