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