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_sos1.c 26 * @ingroup DEFPLUGINS_CONS 27 * @brief constraint handler for SOS type 1 constraints 28 * @author Tobias Fischer 29 * @author Marc Pfetsch 30 * 31 * A specially ordered set of type 1 (SOS1) is a sequence of variables such that at most one 32 * variable is nonzero. The special case of two variables arises, for instance, from equilibrium or 33 * complementary conditions like \f$x \cdot y = 0\f$. Note that it is in principle allowed that a 34 * variables appears twice, but it then can be fixed to 0. 35 * 36 * This implementation of this constraint handler is based on classical ideas, see e.g.@n 37 * "Special Facilities in General Mathematical Programming System for 38 * Non-Convex Problems Using Ordered Sets of Variables"@n 39 * E. Beale and J. Tomlin, Proc. 5th IFORS Conference, 447-454 (1970) 40 * 41 * 42 * The order of the variables is determined as follows: 43 * 44 * - If the constraint is created with SCIPcreateConsSOS1() and weights are given, the weights 45 * determine the order (decreasing weights). Additional variables can be added with 46 * SCIPaddVarSOS1(), which adds a variable with given weight. 47 * 48 * - If an empty constraint is created and then variables are added with SCIPaddVarSOS1(), weights 49 * are needed and stored. 50 * 51 * - All other calls ignore the weights, i.e., if a nonempty constraint is created or variables are 52 * added with SCIPappendVarSOS1(). 53 * 54 * The validity of the SOS1 constraints can be enforced by different branching rules: 55 * 56 * - If classical SOS branching is used, branching is performed on only one SOS1 constraint. 57 * Depending on the parameters, there are two ways to choose this branching constraint. Either 58 * the constraint with the most number of nonzeros or the one with the largest nonzero-variable 59 * weight. The later version allows the user to specify an order for the branching importance of 60 * the constraints. Constraint branching can also be turned off. 61 * 62 * - Another way is to branch on the neighborhood of a single variable @p i, i.e., in one branch 63 * \f$x_i\f$ is fixed to zero and in the other its neighbors from the conflict graph. 64 * 65 * - If bipartite branching is used, then we branch using complete bipartite subgraphs of the 66 * conflict graph, i.e., in one branch fix the variables from the first bipartite partition and 67 * the variables from the second bipartite partition in the other. 68 * 69 * - In addition to variable domain fixings, it is sometimes also possible to add new SOS1 70 * constraints to the branching nodes. This results in a nonstatic conflict graph, which may 71 * change dynamically with every branching node. 72 * 73 * 74 * @todo Possibly allow to generate local cuts via strengthened local cuts (would need to modified coefficients of rows). 75 * 76 * @todo Check whether we can avoid turning off multi-aggregation (it is sometimes possible to fix a multi-aggregated 77 * variable to 0 by fixing the aggregating variables to 0). 78 */ 79 80 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 81 82 #include "blockmemshell/memory.h" 83 #include "scip/cons_linear.h" 84 #include "scip/cons_setppc.h" 85 #include "scip/cons_sos1.h" 86 #include "scip/pub_cons.h" 87 #include "scip/pub_event.h" 88 #include "scip/pub_heur.h" 89 #include "scip/pub_lp.h" 90 #include "scip/pub_message.h" 91 #include "scip/pub_misc.h" 92 #include "scip/pub_misc_sort.h" 93 #include "scip/pub_tree.h" 94 #include "scip/pub_var.h" 95 #include "scip/scip_branch.h" 96 #include "scip/scip_conflict.h" 97 #include "scip/scip_cons.h" 98 #include "scip/scip_copy.h" 99 #include "scip/scip_cut.h" 100 #include "scip/scip_datastructures.h" 101 #include "scip/scip_event.h" 102 #include "scip/scip_general.h" 103 #include "scip/scip_lp.h" 104 #include "scip/scip_mem.h" 105 #include "scip/scip_message.h" 106 #include "scip/scip_numerics.h" 107 #include "scip/scip_param.h" 108 #include "scip/scip_prob.h" 109 #include "scip/scip_probing.h" 110 #include "scip/scip_sol.h" 111 #include "scip/scip_solvingstats.h" 112 #include "scip/scip_tree.h" 113 #include "scip/scip_var.h" 114 #include "scip/symmetry_graph.h" 115 #include "symmetry/struct_symmetry.h" 116 #include "tclique/tclique.h" 117 118 119 /* constraint handler properties */ 120 #define CONSHDLR_NAME "SOS1" 121 #define CONSHDLR_DESC "SOS1 constraint handler" 122 #define CONSHDLR_SEPAPRIORITY 1000 /**< priority of the constraint handler for separation */ 123 #define CONSHDLR_ENFOPRIORITY 100 /**< priority of the constraint handler for constraint enforcing */ 124 #define CONSHDLR_CHECKPRIORITY -10 /**< priority of the constraint handler for checking feasibility */ 125 #define CONSHDLR_SEPAFREQ 10 /**< frequency for separating cuts; zero means to separate only in the root node */ 126 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */ 127 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation, 128 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */ 129 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */ 130 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */ 131 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */ 132 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */ 133 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP 134 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM 135 136 /* adjacency matrix */ 137 #define DEFAULT_MAXSOSADJACENCY 10000 /**< do not create an adjacency matrix if number of SOS1 variables is larger than predefined value 138 * (-1: no limit) */ 139 140 /* presolving */ 141 #define DEFAULT_MAXEXTENSIONS 1 /**< maximal number of extensions that will be computed for each SOS1 constraint */ 142 #define DEFAULT_MAXTIGHTENBDS 5 /**< maximal number of bound tightening rounds per presolving round (-1: no limit) */ 143 #define DEFAULT_PERFIMPLANALYSIS FALSE /**< if TRUE then perform implication graph analysis (might add additional SOS1 constraints) */ 144 #define DEFAULT_DEPTHIMPLANALYSIS -1 /**< number of recursive calls of implication graph analysis (-1: no limit) */ 145 146 /* propagation */ 147 #define DEFAULT_CONFLICTPROP TRUE /**< whether to use conflict graph propagation */ 148 #define DEFAULT_IMPLPROP TRUE /**< whether to use implication graph propagation */ 149 #define DEFAULT_SOSCONSPROP FALSE /**< whether to use SOS1 constraint propagation */ 150 151 /* branching rules */ 152 #define DEFAULT_BRANCHSTRATEGIES "nbs" /**< possible branching strategies (see parameter DEFAULT_BRANCHINGRULE) */ 153 #define DEFAULT_BRANCHINGRULE 'n' /**< which branching rule should be applied ? ('n': neighborhood, 'b': bipartite, 's': SOS1/clique) 154 * (note: in some cases an automatic switching to SOS1 branching is possible) */ 155 #define DEFAULT_AUTOSOS1BRANCH TRUE /**< if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap */ 156 #define DEFAULT_FIXNONZERO FALSE /**< if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the 157 * feasibility tolerance */ 158 #define DEFAULT_ADDCOMPS FALSE /**< if TRUE then add complementarity constraints to the branching nodes (can be used in combination with 159 * neighborhood or bipartite branching) */ 160 #define DEFAULT_MAXADDCOMPS -1 /**< maximal number of complementarity constraints added per branching node (-1: no limit) */ 161 #define DEFAULT_ADDCOMPSDEPTH 30 /**< only add complementarity constraints to branching nodes for predefined depth (-1: no limit) */ 162 #define DEFAULT_ADDCOMPSFEAS -0.6 /**< minimal feasibility value for complementarity constraints in order to be added to the branching node */ 163 #define DEFAULT_ADDBDSFEAS 1.0 /**< minimal feasibility value for bound inequalities in order to be added to the branching node */ 164 #define DEFAULT_ADDEXTENDEDBDS TRUE /**< should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities */ 165 166 /* selection rules */ 167 #define DEFAULT_NSTRONGROUNDS 0 /**< maximal number of strong branching rounds to perform for each node (-1: auto) 168 * (only available for neighborhood and bipartite branching) */ 169 #define DEFAULT_NSTRONGITER 10000 /**< maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit) */ 170 171 /* separation */ 172 #define DEFAULT_BOUNDCUTSFROMSOS1 FALSE /**< if TRUE separate bound inequalities from SOS1 constraints */ 173 #define DEFAULT_BOUNDCUTSFROMGRAPH TRUE /**< if TRUE separate bound inequalities from the conflict graph */ 174 #define DEFAULT_AUTOCUTSFROMSOS1 TRUE /**< if TRUE then automatically switch to separating from SOS1 constraints if the SOS1 constraints do not overlap */ 175 #define DEFAULT_BOUNDCUTSFREQ 10 /**< frequency for separating bound cuts; zero means to separate only in the root node */ 176 #define DEFAULT_BOUNDCUTSDEPTH 40 /**< node depth of separating bound cuts (-1: no limit) */ 177 #define DEFAULT_MAXBOUNDCUTS 50 /**< maximal number of bound cuts separated per branching node */ 178 #define DEFAULT_MAXBOUNDCUTSROOT 150 /**< maximal number of bound cuts separated per iteration in the root node */ 179 #define DEFAULT_STRTHENBOUNDCUTS TRUE /**< if TRUE then bound cuts are strengthened in case bound variables are available */ 180 #define DEFAULT_IMPLCUTSFREQ 0 /**< frequency for separating implied bound cuts; zero means to separate only in the root node */ 181 #define DEFAULT_IMPLCUTSDEPTH 40 /**< node depth of separating implied bound cuts (-1: no limit) */ 182 #define DEFAULT_MAXIMPLCUTS 50 /**< maximal number of implied bound cuts separated per branching node */ 183 #define DEFAULT_MAXIMPLCUTSROOT 150 /**< maximal number of implied bound cuts separated per iteration in the root node */ 184 185 /* event handler properties */ 186 #define EVENTHDLR_NAME "SOS1" 187 #define EVENTHDLR_DESC "bound change event handler for SOS1 constraints" 188 189 #define EVENTHDLR_EVENT_TYPE (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_GBDCHANGED) 190 191 /* defines */ 192 #define DIVINGCUTOFFVALUE 1e6 193 194 195 /** constraint data for SOS1 constraints */ 196 struct SCIP_ConsData 197 { 198 int nvars; /**< number of variables in the constraint */ 199 int maxvars; /**< maximal number of variables (= size of storage) */ 200 int nfixednonzeros; /**< number of variables fixed to be nonzero */ 201 SCIP_Bool local; /**< TRUE if constraint is only valid locally */ 202 SCIP_VAR** vars; /**< variables in constraint */ 203 SCIP_ROW* rowlb; /**< row corresponding to lower bounds, or NULL if not yet created */ 204 SCIP_ROW* rowub; /**< row corresponding to upper bounds, or NULL if not yet created */ 205 SCIP_Real* weights; /**< weights determining the order (ascending), or NULL if not used */ 206 }; 207 208 209 /** node data of a given node in the conflict graph */ 210 struct SCIP_NodeData 211 { 212 SCIP_VAR* var; /**< variable belonging to node */ 213 SCIP_VAR* lbboundvar; /**< bound variable @p z from constraint \f$x \geq \mu \cdot z\f$ (or NULL if not existent) */ 214 SCIP_VAR* ubboundvar; /**< bound variable @p z from constraint \f$x \leq \mu \cdot z\f$ (or NULL if not existent) */ 215 SCIP_Real lbboundcoef; /**< value \f$\mu\f$ from constraint \f$x \geq \mu z \f$ (0.0 if not existent) */ 216 SCIP_Real ubboundcoef; /**< value \f$\mu\f$ from constraint \f$x \leq \mu z \f$ (0.0 if not existent) */ 217 SCIP_Bool lbboundcomp; /**< TRUE if the nodes from the connected component of the conflict graph the given node belongs to 218 * all have the same lower bound variable */ 219 SCIP_Bool ubboundcomp; /**< TRUE if the nodes from the connected component of the conflict graph the given node belongs to 220 * all have the same lower bound variable */ 221 }; 222 typedef struct SCIP_NodeData SCIP_NODEDATA; 223 224 225 /** successor data of a given nodes successor in the implication graph */ 226 struct SCIP_SuccData 227 { 228 SCIP_Real lbimpl; /**< lower bound implication */ 229 SCIP_Real ubimpl; /**< upper bound implication */ 230 }; 231 typedef struct SCIP_SuccData SCIP_SUCCDATA; 232 233 234 /** tclique data for bound cut generation */ 235 struct TCLIQUE_Data 236 { 237 SCIP* scip; /**< SCIP data structure */ 238 SCIP_CONSHDLR* conshdlr; /**< SOS1 constraint handler */ 239 SCIP_DIGRAPH* conflictgraph; /**< conflict graph */ 240 SCIP_SOL* sol; /**< LP solution to be separated (or NULL) */ 241 SCIP_Real scaleval; /**< factor for scaling weights */ 242 SCIP_Bool cutoff; /**< whether a cutoff occurred */ 243 int ncuts; /**< number of bound cuts found in this iteration */ 244 int nboundcuts; /**< number of bound cuts found so far */ 245 int maxboundcuts; /**< maximal number of clique cuts separated per separation round (-1: no limit) */ 246 SCIP_Bool strthenboundcuts; /**< if TRUE then bound cuts are strengthened in case bound variables are available */ 247 }; 248 249 250 /** SOS1 constraint handler data */ 251 struct SCIP_ConshdlrData 252 { 253 /* conflict graph */ 254 SCIP_DIGRAPH* conflictgraph; /**< conflict graph */ 255 SCIP_DIGRAPH* localconflicts; /**< local conflicts */ 256 SCIP_Bool isconflocal; /**< if TRUE then local conflicts are present and conflict graph has to be updated for each node */ 257 SCIP_HASHMAP* varhash; /**< hash map from variable to node in the conflict graph */ 258 int nsos1vars; /**< number of problem variables that are part of the SOS1 conflict graph */ 259 /* adjacency matrix */ 260 int maxsosadjacency; /**< do not create an adjacency matrix if number of SOS1 variables is larger than predefined 261 * value (-1: no limit) */ 262 /* implication graph */ 263 SCIP_DIGRAPH* implgraph; /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */ 264 int nimplnodes; /**< number of nodes in the implication graph */ 265 /* tclique graph */ 266 TCLIQUE_GRAPH* tcliquegraph; /**< tclique graph data structure */ 267 TCLIQUE_DATA* tcliquedata; /**< tclique data */ 268 /* event handler */ 269 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */ 270 SCIP_VAR** fixnonzerovars; /**< stack of variables fixed to nonzero marked by event handler */ 271 int maxnfixnonzerovars; /**< size of stack fixnonzerovars */ 272 int nfixnonzerovars; /**< number of variables fixed to nonzero marked by event handler */ 273 /* presolving */ 274 int cntextsos1; /**< counts number of extended SOS1 constraints */ 275 int maxextensions; /**< maximal number of extensions that will be computed for each SOS1 constraint */ 276 int maxtightenbds; /**< maximal number of bound tightening rounds per presolving round (-1: no limit) */ 277 SCIP_Bool perfimplanalysis; /**< if TRUE then perform implication graph analysis (might add additional SOS1 constraints) */ 278 int depthimplanalysis; /**< number of recursive calls of implication graph analysis (-1: no limit) */ 279 /* propagation */ 280 SCIP_Bool conflictprop; /**< whether to use conflict graph propagation */ 281 SCIP_Bool implprop; /**< whether to use implication graph propagation */ 282 SCIP_Bool sosconsprop; /**< whether to use SOS1 constraint propagation */ 283 /* branching */ 284 char branchingrule; /**< which branching rule should be applied ? ('n': neighborhood, 'b': bipartite, 's': SOS1/clique) 285 * (note: in some cases an automatic switching to SOS1 branching is possible) */ 286 SCIP_Bool autosos1branch; /**< if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap */ 287 SCIP_Bool fixnonzero; /**< if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the 288 * feasibility tolerance */ 289 SCIP_Bool addcomps; /**< if TRUE then add complementarity constraints to the branching nodes additionally to domain fixings 290 * (can be used in combination with neighborhood or bipartite branching) */ 291 int maxaddcomps; /**< maximal number of complementarity cons. and cor. bound ineq. added per branching node (-1: no limit) */ 292 int addcompsdepth; /**< only add complementarity constraints to branching nodes for predefined depth (-1: no limit) */ 293 SCIP_Real addcompsfeas; /**< minimal feasibility value for complementarity constraints in order to be added to the branching node */ 294 SCIP_Real addbdsfeas; /**< minimal feasibility value for bound inequalities in order to be added to the branching node */ 295 SCIP_Bool addextendedbds; /**< should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities */ 296 SCIP_Bool branchsos; /**< Branch on SOS condition in enforcing? This value can only be set to false if all SOS1 variables are binary */ 297 SCIP_Bool branchnonzeros; /**< Branch on SOS cons. with most number of nonzeros? */ 298 SCIP_Bool branchweight; /**< Branch on SOS cons. with highest nonzero-variable weight for branching - needs branchnonzeros to be false */ 299 SCIP_Bool switchsos1branch; /**< whether to switch to SOS1 branching */ 300 /* selection rules */ 301 int nstrongrounds; /**< maximal number of strong branching rounds to perform for each node (-1: auto) 302 * (only available for neighborhood and bipartite branching) */ 303 int nstrongiter; /**< maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit) */ 304 /* separation */ 305 SCIP_Bool boundcutsfromsos1; /**< if TRUE separate bound inequalities from SOS1 constraints */ 306 SCIP_Bool boundcutsfromgraph; /**< if TRUE separate bound inequalities from the conflict graph */ 307 SCIP_Bool autocutsfromsos1; /**< if TRUE then automatically switch to separating SOS1 constraints if the SOS1 constraints do not overlap */ 308 SCIP_Bool switchcutsfromsos1; /**< whether to switch to separate bound inequalities from SOS1 constraints */ 309 int boundcutsfreq; /**< frequency for separating bound cuts; zero means to separate only in the root node */ 310 int boundcutsdepth; /**< node depth of separating bound cuts (-1: no limit) */ 311 int maxboundcuts; /**< maximal number of bound cuts separated per branching node */ 312 int maxboundcutsroot; /**< maximal number of bound cuts separated per iteration in the root node */ 313 int nboundcuts; /**< number of bound cuts found so far */ 314 SCIP_Bool strthenboundcuts; /**< if TRUE then bound cuts are strengthened in case bound variables are available */ 315 int implcutsfreq; /**< frequency for separating implied bound cuts; zero means to separate only in the root node */ 316 int implcutsdepth; /**< node depth of separating implied bound cuts (-1: no limit) */ 317 int maximplcuts; /**< maximal number of implied bound cuts separated per branching node */ 318 int maximplcutsroot; /**< maximal number of implied bound cuts separated per iteration in the root node */ 319 }; 320 321 322 323 /* 324 * local methods 325 */ 326 327 /** returns whether two vertices are adjacent in the conflict graph */ 328 static 329 SCIP_Bool isConnectedSOS1( 330 SCIP_Bool** adjacencymatrix, /**< adjacency matrix of conflict graph (lower half) (or NULL if an adjacencymatrix is not at hand) */ 331 SCIP_DIGRAPH* conflictgraph, /**< conflict graph (or NULL if an adjacencymatrix is at hand) */ 332 int vertex1, /**< first vertex */ 333 int vertex2 /**< second vertex */ 334 ) 335 { 336 assert( adjacencymatrix != NULL || conflictgraph != NULL ); 337 338 /* we do not allow self-loops */ 339 if ( vertex1 == vertex2 ) 340 return FALSE; 341 342 /* for debugging */ 343 if ( adjacencymatrix == NULL ) 344 { 345 int succvertex; 346 int* succ; 347 int nsucc1; 348 int nsucc2; 349 int j; 350 351 nsucc1 = SCIPdigraphGetNSuccessors(conflictgraph, vertex1); 352 nsucc2 = SCIPdigraphGetNSuccessors(conflictgraph, vertex2); 353 354 if ( nsucc1 < 1 || nsucc2 < 1 ) 355 return FALSE; 356 357 if ( nsucc1 > nsucc2 ) 358 { 359 SCIPswapInts(&vertex1, &vertex2); 360 SCIPswapInts(&nsucc1, &nsucc2); 361 } 362 363 succ = SCIPdigraphGetSuccessors(conflictgraph, vertex1); 364 SCIPsortInt(succ, nsucc1); 365 366 for (j = 0; j < nsucc1; ++j) 367 { 368 succvertex = succ[j]; 369 if ( succvertex == vertex2 ) 370 return TRUE; 371 else if ( succvertex > vertex2 ) 372 return FALSE; 373 } 374 } 375 else 376 { 377 if ( vertex1 < vertex2 ) 378 return adjacencymatrix[vertex2][vertex1]; 379 else 380 return adjacencymatrix[vertex1][vertex2]; 381 } 382 383 return FALSE; 384 } 385 386 387 /** checks whether a variable violates an SOS1 constraint w.r.t. sol together with at least one other variable */ 388 static 389 SCIP_Bool isViolatedSOS1( 390 SCIP* scip, /**< SCIP data structure */ 391 SCIP_DIGRAPH* conflictgraph, /**< conflict graph (or NULL if an adjacencymatrix is at hand) */ 392 int node, /**< node of variable in the conflict graph */ 393 SCIP_SOL* sol /**< solution, or NULL to use current node's solution */ 394 ) 395 { 396 SCIP_Real solval; 397 SCIP_VAR* var; 398 399 assert( scip != NULL ); 400 assert( conflictgraph != NULL ); 401 assert( node >= 0 ); 402 403 var = SCIPnodeGetVarSOS1(conflictgraph, node); 404 assert( var != NULL ); 405 solval = SCIPgetSolVal(scip, sol, var); 406 407 /* check whether variable is nonzero w.r.t. sol and the bounds have not been fixed to zero by propagation */ 408 if ( ! SCIPisFeasZero(scip, solval) && ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) ) 409 { 410 int* succ; 411 int nsucc; 412 int s; 413 414 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node); 415 succ = SCIPdigraphGetSuccessors(conflictgraph, node); 416 417 /* check whether a neighbor variable is nonzero w.r.t. sol */ 418 for (s = 0; s < nsucc; ++s) 419 { 420 var = SCIPnodeGetVarSOS1(conflictgraph, succ[s]); 421 assert( var != NULL ); 422 solval = SCIPgetSolVal(scip, sol, var); 423 if ( ! SCIPisFeasZero(scip, solval) && ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) ) 424 return TRUE; 425 } 426 } 427 428 return FALSE; 429 } 430 431 432 /** returns solution value of imaginary binary big-M variable of a given node from the conflict graph */ 433 static 434 SCIP_Real nodeGetSolvalBinaryBigMSOS1( 435 SCIP* scip, /**< SCIP pointer */ 436 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 437 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */ 438 int node /**< node of the conflict graph */ 439 ) 440 { 441 SCIP_Real bound; 442 SCIP_VAR* var; 443 SCIP_Real val; 444 445 assert( scip != NULL ); 446 assert( conflictgraph != NULL ); 447 assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) ); 448 449 var = SCIPnodeGetVarSOS1(conflictgraph, node); 450 val = SCIPgetSolVal(scip, sol, var); 451 452 if ( SCIPisFeasNegative(scip, val) ) 453 { 454 bound = SCIPvarGetLbLocal(var); 455 assert( SCIPisFeasNegative(scip, bound) ); 456 457 if ( SCIPisInfinity(scip, -val) ) 458 return 1.0; 459 else if ( SCIPisInfinity(scip, -bound) ) 460 return 0.0; 461 else 462 return (val/bound); 463 } 464 else if ( SCIPisFeasPositive(scip, val) ) 465 { 466 bound = SCIPvarGetUbLocal(var); 467 assert( SCIPisFeasPositive(scip, bound) ); 468 assert( SCIPisFeasPositive(scip, val) ); 469 470 if ( SCIPisInfinity(scip, val) ) 471 return 1.0; 472 else if ( SCIPisInfinity(scip, bound) ) 473 return 0.0; 474 else 475 return (val/bound); 476 } 477 else 478 return 0.0; 479 } 480 481 482 /** gets (variable) lower bound value of current LP relaxation solution for a given node from the conflict graph */ 483 static 484 SCIP_Real nodeGetSolvalVarboundLbSOS1( 485 SCIP* scip, /**< SCIP pointer */ 486 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 487 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */ 488 int node /**< node of the conflict graph */ 489 ) 490 { 491 SCIP_NODEDATA* nodedata; 492 493 assert( scip != NULL ); 494 assert( conflictgraph != NULL ); 495 assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) ); 496 497 /* get node data */ 498 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node); 499 assert( nodedata != NULL ); 500 501 /* if variable is not involved in a variable upper bound constraint */ 502 if ( nodedata->lbboundvar == NULL || ! nodedata->lbboundcomp ) 503 return SCIPvarGetLbLocal(nodedata->var); 504 505 return nodedata->lbboundcoef * SCIPgetSolVal(scip, sol, nodedata->lbboundvar); 506 } 507 508 509 /** gets (variable) upper bound value of current LP relaxation solution for a given node from the conflict graph */ 510 static 511 SCIP_Real nodeGetSolvalVarboundUbSOS1( 512 SCIP* scip, /**< SCIP pointer */ 513 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 514 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */ 515 int node /**< node of the conflict graph */ 516 ) 517 { 518 SCIP_NODEDATA* nodedata; 519 520 assert( scip != NULL ); 521 assert( conflictgraph != NULL ); 522 assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) ); 523 524 /* get node data */ 525 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node); 526 assert( nodedata != NULL ); 527 528 /* if variable is not involved in a variable upper bound constraint */ 529 if ( nodedata->ubboundvar == NULL || ! nodedata->ubboundcomp ) 530 return SCIPvarGetUbLocal(nodedata->var); 531 532 return nodedata->ubboundcoef * SCIPgetSolVal(scip, sol, nodedata->ubboundvar); 533 } 534 535 536 /** returns whether variable is part of the SOS1 conflict graph */ 537 static 538 SCIP_Bool varIsSOS1( 539 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler */ 540 SCIP_VAR* var /**< variable */ 541 ) 542 { 543 assert( conshdlrdata != NULL ); 544 assert( var != NULL ); 545 546 if ( conshdlrdata->varhash == NULL || ! SCIPhashmapExists(conshdlrdata->varhash, var) ) 547 return FALSE; 548 549 return TRUE; 550 } 551 552 553 /** returns SOS1 index of variable or -1 if variable is not part of the SOS1 conflict graph */ 554 static 555 int varGetNodeSOS1( 556 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler */ 557 SCIP_VAR* var /**< variable */ 558 ) 559 { 560 assert( conshdlrdata != NULL ); 561 assert( var != NULL ); 562 assert( conshdlrdata->varhash != NULL ); 563 564 if ( ! SCIPhashmapExists(conshdlrdata->varhash, var) ) 565 return -1; 566 567 return SCIPhashmapGetImageInt(conshdlrdata->varhash, var); 568 } 569 570 571 /** fix variable in given node to 0 or add constraint if variable is multi-aggregated 572 * 573 * @todo Try to handle multi-aggregated variables as in fixVariableZero() below. 574 */ 575 static 576 SCIP_RETCODE fixVariableZeroNode( 577 SCIP* scip, /**< SCIP pointer */ 578 SCIP_VAR* var, /**< variable to be fixed to 0*/ 579 SCIP_NODE* node, /**< node */ 580 SCIP_Bool* infeasible /**< if fixing is infeasible */ 581 ) 582 { 583 /* if variable cannot be nonzero */ 584 *infeasible = FALSE; 585 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(var)) ) 586 { 587 *infeasible = TRUE; 588 return SCIP_OKAY; 589 } 590 591 /* if variable is multi-aggregated */ 592 if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR ) 593 { 594 SCIP_CONS* cons; 595 SCIP_Real val; 596 597 val = 1.0; 598 599 if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) 600 { 601 SCIPdebugMsg(scip, "creating constraint to force multi-aggregated variable <%s> to 0.\n", SCIPvarGetName(var)); 602 /* we have to insert a local constraint var = 0 */ 603 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, "branch", 1, &var, &val, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE, 604 TRUE, FALSE, FALSE, FALSE, FALSE) ); 605 SCIP_CALL( SCIPaddConsNode(scip, node, cons, NULL) ); 606 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 607 } 608 } 609 else 610 { 611 if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) ) 612 SCIP_CALL( SCIPchgVarLbNode(scip, node, var, 0.0) ); 613 if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) 614 SCIP_CALL( SCIPchgVarUbNode(scip, node, var, 0.0) ); 615 } 616 617 return SCIP_OKAY; 618 } 619 620 621 /** try to fix variable to 0 622 * 623 * Try to treat fixing by special consideration of multiaggregated variables. For a multi-aggregation 624 * \f[ 625 * x = \sum_{i=1}^n \alpha_i x_i + c, 626 * \f] 627 * we can express the fixing \f$x = 0\f$ by fixing all \f$x_i\f$ to 0 if \f$c = 0\f$ and the lower bounds of \f$x_i\f$ 628 * are nonnegative if \f$\alpha_i > 0\f$ or the upper bounds are nonpositive if \f$\alpha_i < 0\f$. 629 */ 630 static 631 SCIP_RETCODE fixVariableZero( 632 SCIP* scip, /**< SCIP pointer */ 633 SCIP_VAR* var, /**< variable to be fixed to 0*/ 634 SCIP_Bool* infeasible, /**< if fixing is infeasible */ 635 SCIP_Bool* tightened /**< if fixing was performed */ 636 ) 637 { 638 assert( scip != NULL ); 639 assert( var != NULL ); 640 assert( infeasible != NULL ); 641 assert( tightened != NULL ); 642 643 *infeasible = FALSE; 644 *tightened = FALSE; 645 646 if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR ) 647 { 648 SCIP_Real aggrconst; 649 650 /* if constant is 0 */ 651 aggrconst = SCIPvarGetMultaggrConstant(var); 652 if ( SCIPisZero(scip, aggrconst) ) 653 { 654 SCIP_VAR** aggrvars; 655 SCIP_Real* aggrvals; 656 SCIP_Bool allnonnegative = TRUE; 657 int naggrvars; 658 int i; 659 660 SCIP_CALL( SCIPflattenVarAggregationGraph(scip, var) ); 661 662 /* check whether all variables are "nonnegative" */ 663 naggrvars = SCIPvarGetMultaggrNVars(var); 664 aggrvars = SCIPvarGetMultaggrVars(var); 665 aggrvals = SCIPvarGetMultaggrScalars(var); 666 for (i = 0; i < naggrvars; ++i) 667 { 668 if ( (SCIPisPositive(scip, aggrvals[i]) && SCIPisNegative(scip, SCIPvarGetLbLocal(aggrvars[i]))) || 669 (SCIPisNegative(scip, aggrvals[i]) && SCIPisPositive(scip, SCIPvarGetUbLocal(aggrvars[i]))) ) 670 { 671 allnonnegative = FALSE; 672 break; 673 } 674 } 675 676 if ( allnonnegative ) 677 { 678 /* all variables are nonnegative -> fix variables */ 679 for (i = 0; i < naggrvars; ++i) 680 { 681 SCIP_Bool fixed; 682 SCIP_CALL( SCIPfixVar(scip, aggrvars[i], 0.0, infeasible, &fixed) ); 683 if ( *infeasible ) 684 return SCIP_OKAY; 685 *tightened = *tightened || fixed; 686 } 687 } 688 } 689 } 690 else 691 { 692 SCIP_CALL( SCIPfixVar(scip, var, 0.0, infeasible, tightened) ); 693 } 694 695 return SCIP_OKAY; 696 } 697 698 699 /** fix variable in local node to 0, and return whether the operation was feasible 700 * 701 * @note We do not add a linear constraint if the variable is multi-aggregated as in 702 * fixVariableZeroNode(), since this would be too time consuming. 703 */ 704 static 705 SCIP_RETCODE inferVariableZero( 706 SCIP* scip, /**< SCIP pointer */ 707 SCIP_VAR* var, /**< variable to be fixed to 0*/ 708 SCIP_CONS* cons, /**< constraint */ 709 int inferinfo, /**< info for reverse prop. */ 710 SCIP_Bool* infeasible, /**< if fixing is infeasible */ 711 SCIP_Bool* tightened, /**< if fixing was performed */ 712 SCIP_Bool* success /**< whether fixing was successful, i.e., variable is not multi-aggregated */ 713 ) 714 { 715 *infeasible = FALSE; 716 *tightened = FALSE; 717 *success = FALSE; 718 719 /* if variable cannot be nonzero */ 720 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(var)) ) 721 { 722 *infeasible = TRUE; 723 return SCIP_OKAY; 724 } 725 726 /* directly fix variable if it is not multi-aggregated */ 727 if ( SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR ) 728 { 729 SCIP_Bool tighten; 730 731 /* fix lower bound */ 732 SCIP_CALL( SCIPinferVarLbCons(scip, var, 0.0, cons, inferinfo, FALSE, infeasible, &tighten) ); 733 *tightened = *tightened || tighten; 734 735 /* fix upper bound */ 736 SCIP_CALL( SCIPinferVarUbCons(scip, var, 0.0, cons, inferinfo, FALSE, infeasible, &tighten) ); 737 *tightened = *tightened || tighten; 738 739 *success = TRUE; 740 } 741 742 return SCIP_OKAY; 743 } 744 745 746 /** add lock on variable */ 747 static 748 SCIP_RETCODE lockVariableSOS1( 749 SCIP* scip, /**< SCIP data structure */ 750 SCIP_CONS* cons, /**< constraint */ 751 SCIP_VAR* var /**< variable */ 752 ) 753 { 754 assert( scip != NULL ); 755 assert( cons != NULL ); 756 assert( var != NULL ); 757 758 /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */ 759 SCIP_CALL( SCIPlockVarCons(scip, var, cons, SCIPisFeasNegative(scip, SCIPvarGetLbGlobal(var)), 760 SCIPisFeasPositive(scip, SCIPvarGetUbGlobal(var))) ); 761 762 return SCIP_OKAY; 763 } 764 765 766 /** remove lock on variable */ 767 static 768 SCIP_RETCODE unlockVariableSOS1( 769 SCIP* scip, /**< SCIP data structure */ 770 SCIP_CONS* cons, /**< constraint */ 771 SCIP_VAR* var /**< variable */ 772 ) 773 { 774 assert( scip != NULL ); 775 assert( cons != NULL ); 776 assert( var != NULL ); 777 778 /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */ 779 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, SCIPisFeasNegative(scip, SCIPvarGetLbGlobal(var)), 780 SCIPisFeasPositive(scip, SCIPvarGetUbGlobal(var))) ); 781 782 return SCIP_OKAY; 783 } 784 785 786 /** ensures that the vars and weights array can store at least num entries */ 787 static 788 SCIP_RETCODE consdataEnsurevarsSizeSOS1( 789 SCIP* scip, /**< SCIP data structure */ 790 SCIP_CONSDATA* consdata, /**< constraint data */ 791 int num, /**< minimum number of entries to store */ 792 SCIP_Bool reserveWeights /**< whether the weights array is handled */ 793 ) 794 { 795 assert( consdata != NULL ); 796 assert( consdata->nvars <= consdata->maxvars ); 797 798 if ( num > consdata->maxvars ) 799 { 800 int newsize; 801 802 newsize = SCIPcalcMemGrowSize(scip, num); 803 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->maxvars, newsize) ); 804 if ( reserveWeights ) 805 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->maxvars, newsize) ); 806 consdata->maxvars = newsize; 807 } 808 assert( num <= consdata->maxvars ); 809 810 return SCIP_OKAY; 811 } 812 813 814 /** handle new variable */ 815 static 816 SCIP_RETCODE handleNewVariableSOS1( 817 SCIP* scip, /**< SCIP data structure */ 818 SCIP_CONS* cons, /**< constraint */ 819 SCIP_CONSDATA* consdata, /**< constraint data */ 820 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 821 SCIP_VAR* var, /**< variable */ 822 SCIP_Bool transformed /**< whether original variable was transformed */ 823 ) 824 { 825 SCIP_DIGRAPH* conflictgraph; 826 int node; 827 828 assert( scip != NULL ); 829 assert( cons != NULL ); 830 assert( consdata != NULL ); 831 assert( conshdlrdata != NULL ); 832 assert( var != NULL ); 833 834 /* if we are in transformed problem, catch the variable's events */ 835 if ( transformed ) 836 { 837 assert( conshdlrdata->eventhdlr != NULL ); 838 839 /* catch bound change events of variable */ 840 SCIP_CALL( SCIPcatchVarEvent(scip, var, EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr, 841 (SCIP_EVENTDATA*)cons, NULL) ); /*lint !e740*/ 842 843 /* if the variable if fixed to nonzero */ 844 assert( consdata->nfixednonzeros >= 0 ); 845 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(var)) ) 846 ++consdata->nfixednonzeros; 847 } 848 849 /* install the rounding locks for the new variable */ 850 SCIP_CALL( lockVariableSOS1(scip, cons, var) ); 851 852 /* branching on multiaggregated variables does not seem to work well, so avoid it */ 853 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) ); 854 855 /* add the new coefficient to the upper bound LP row, if necessary */ 856 if ( consdata->rowub != NULL && ! SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) && ! SCIPisZero(scip, SCIPvarGetUbGlobal(var)) ) 857 { 858 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rowub, var, 1.0/SCIPvarGetUbGlobal(var)) ); 859 } 860 861 /* add the new coefficient to the lower bound LP row, if necessary */ 862 if ( consdata->rowlb != NULL && ! SCIPisInfinity(scip, SCIPvarGetLbGlobal(var)) && ! SCIPisZero(scip, SCIPvarGetLbGlobal(var)) ) 863 { 864 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rowlb, var, 1.0/SCIPvarGetLbGlobal(var)) ); 865 } 866 867 /* return if the conflict graph has not been created yet */ 868 conflictgraph = conshdlrdata->conflictgraph; 869 if ( conflictgraph == NULL ) 870 return SCIP_OKAY; 871 872 /* get node of variable in the conflict graph (or -1) */ 873 node = varGetNodeSOS1(conshdlrdata, var); 874 assert( node < conshdlrdata->nsos1vars ); 875 876 /* if the variable is not already a node of the conflict graph */ 877 if ( node < 0 ) 878 { 879 /* variable does not appear in the conflict graph: switch to SOS1 branching rule, which does not make use of a conflict graph 880 * @todo: maybe recompute the conflict graph, implication graph and varhash instead */ 881 SCIPdebugMsg(scip, "Switched to SOS1 branching rule, since conflict graph could be infeasible.\n"); 882 conshdlrdata->switchsos1branch = TRUE; 883 return SCIP_OKAY; 884 } 885 886 /* if the constraint is local, then there is no need to act, since local constraints are handled by the local conflict graph in the 887 * function enforceConflictgraph() */ 888 if ( ! consdata->local ) 889 { 890 SCIP_VAR** vars; 891 int nvars; 892 int v; 893 894 vars = consdata->vars; 895 nvars = consdata->nvars; 896 897 for (v = 0; v < nvars; ++v) 898 { 899 int nodev; 900 901 if ( var == vars[v] ) 902 continue; 903 904 /* get node of variable in the conflict graph (or -1) */ 905 nodev = varGetNodeSOS1(conshdlrdata, vars[v]); 906 assert( nodev < conshdlrdata->nsos1vars ); 907 908 /* if the variable is already a node of the conflict graph */ 909 if ( nodev >= 0 ) 910 { 911 int nsucc; 912 int nsuccv; 913 914 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node); 915 nsuccv = SCIPdigraphGetNSuccessors(conflictgraph, nodev); 916 917 /* add arcs if not existent */ 918 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, nodev, node, NULL) ); 919 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, node, nodev, NULL) ); 920 921 /* in case of new arcs: sort successors in ascending order */ 922 if ( nsucc < SCIPdigraphGetNSuccessors(conflictgraph, node) ) 923 { 924 SCIPdebugMsg(scip, "Added new conflict graph arc from variable %s to variable %s.\n", SCIPvarGetName(var), SCIPvarGetName(vars[v])); 925 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, node), SCIPdigraphGetNSuccessors(conflictgraph, node)); 926 } 927 928 if ( nsuccv < SCIPdigraphGetNSuccessors(conflictgraph, nodev) ) 929 { 930 SCIPdebugMsg(scip, "Added new conflict graph arc from variable %s to variable %s.\n", SCIPvarGetName(vars[v]), SCIPvarGetName(var)); 931 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, nodev), SCIPdigraphGetNSuccessors(conflictgraph, nodev)); 932 } 933 } 934 else 935 { 936 /* variable does not appear in the conflict graph: switch to SOS1 branching rule, which does not make use of a conflict graph 937 * @todo: maybe recompute the conflict graph, implication graph and varhash instead */ 938 SCIPdebugMsg(scip, "Switched to SOS1 branching rule, since conflict graph could be infeasible.\n"); 939 conshdlrdata->switchsos1branch = TRUE; 940 return SCIP_OKAY; 941 } 942 } 943 } 944 945 return SCIP_OKAY; 946 } 947 948 949 /** adds a variable to an SOS1 constraint, at position given by weight - ascending order */ 950 static 951 SCIP_RETCODE addVarSOS1( 952 SCIP* scip, /**< SCIP data structure */ 953 SCIP_CONS* cons, /**< constraint */ 954 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 955 SCIP_VAR* var, /**< variable to add to the constraint */ 956 SCIP_Real weight /**< weight to determine position */ 957 ) 958 { 959 SCIP_CONSDATA* consdata; 960 SCIP_Bool transformed; 961 int pos; 962 int j; 963 964 assert( var != NULL ); 965 assert( cons != NULL ); 966 assert( conshdlrdata != NULL ); 967 968 consdata = SCIPconsGetData(cons); 969 assert( consdata != NULL ); 970 971 if ( consdata->weights == NULL && consdata->maxvars > 0 ) 972 { 973 SCIPerrorMessage("cannot add variable to SOS1 constraint <%s> that does not contain weights.\n", SCIPconsGetName(cons)); 974 return SCIP_INVALIDCALL; 975 } 976 977 /* are we in the transformed problem? */ 978 transformed = SCIPconsIsTransformed(cons); 979 980 /* always use transformed variables in transformed constraints */ 981 if ( transformed ) 982 { 983 SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) ); 984 } 985 assert( var != NULL ); 986 assert( transformed == SCIPvarIsTransformed(var) ); 987 988 SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, TRUE) ); 989 assert( consdata->weights != NULL ); 990 assert( consdata->maxvars >= consdata->nvars+1 ); 991 992 /* find variable position */ 993 for (pos = 0; pos < consdata->nvars; ++pos) 994 { 995 if ( consdata->weights[pos] > weight ) 996 break; 997 } 998 assert( 0 <= pos && pos <= consdata->nvars ); 999 1000 /* move other variables, if necessary */ 1001 for (j = consdata->nvars; j > pos; --j) 1002 { 1003 consdata->vars[j] = consdata->vars[j-1]; 1004 consdata->weights[j] = consdata->weights[j-1]; 1005 } 1006 1007 /* insert variable */ 1008 consdata->vars[pos] = var; 1009 consdata->weights[pos] = weight; 1010 ++consdata->nvars; 1011 1012 /* handle the new variable */ 1013 SCIP_CALL( handleNewVariableSOS1(scip, cons, consdata, conshdlrdata, var, transformed) ); 1014 1015 return SCIP_OKAY; 1016 } 1017 1018 1019 /** appends a variable to an SOS1 constraint */ 1020 static 1021 SCIP_RETCODE appendVarSOS1( 1022 SCIP* scip, /**< SCIP data structure */ 1023 SCIP_CONS* cons, /**< constraint */ 1024 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 1025 SCIP_VAR* var /**< variable to add to the constraint */ 1026 ) 1027 { 1028 SCIP_CONSDATA* consdata; 1029 SCIP_Bool transformed; 1030 1031 assert( var != NULL ); 1032 assert( cons != NULL ); 1033 assert( conshdlrdata != NULL ); 1034 1035 consdata = SCIPconsGetData(cons); 1036 assert( consdata != NULL ); 1037 assert( consdata->nvars >= 0 ); 1038 1039 /* are we in the transformed problem? */ 1040 transformed = SCIPconsIsTransformed(cons); 1041 1042 /* always use transformed variables in transformed constraints */ 1043 if ( transformed ) 1044 { 1045 SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) ); 1046 } 1047 assert( var != NULL ); 1048 assert( transformed == SCIPvarIsTransformed(var) ); 1049 1050 if ( consdata->weights != NULL ) 1051 { 1052 SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, TRUE) ); 1053 } 1054 else 1055 { 1056 SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, FALSE) ); 1057 } 1058 1059 /* insert variable */ 1060 consdata->vars[consdata->nvars] = var; 1061 if ( consdata->weights != NULL ) 1062 { 1063 if ( consdata->nvars > 0 ) 1064 consdata->weights[consdata->nvars] = consdata->weights[consdata->nvars-1] + 1.0; 1065 else 1066 consdata->weights[consdata->nvars] = 0.0; 1067 } 1068 ++consdata->nvars; 1069 1070 /* handle the new variable */ 1071 SCIP_CALL( handleNewVariableSOS1(scip, cons, consdata, conshdlrdata, var, transformed) ); 1072 1073 return SCIP_OKAY; 1074 } 1075 1076 1077 /** deletes a variable of an SOS1 constraint */ 1078 static 1079 SCIP_RETCODE deleteVarSOS1( 1080 SCIP* scip, /**< SCIP data structure */ 1081 SCIP_CONS* cons, /**< constraint */ 1082 SCIP_CONSDATA* consdata, /**< constraint data */ 1083 SCIP_EVENTHDLR* eventhdlr, /**< corresponding event handler */ 1084 int pos /**< position of variable in array */ 1085 ) 1086 { 1087 int j; 1088 1089 assert( 0 <= pos && pos < consdata->nvars ); 1090 1091 /* remove lock of variable */ 1092 SCIP_CALL( unlockVariableSOS1(scip, cons, consdata->vars[pos]) ); 1093 1094 /* drop events on variable */ 1095 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos], EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, -1) ); /*lint !e740*/ 1096 1097 /* delete variable - need to copy since order is important */ 1098 for (j = pos; j < consdata->nvars-1; ++j) 1099 { 1100 consdata->vars[j] = consdata->vars[j+1]; /*lint !e679*/ 1101 if ( consdata->weights != NULL ) 1102 consdata->weights[j] = consdata->weights[j+1]; /*lint !e679*/ 1103 } 1104 --consdata->nvars; 1105 1106 return SCIP_OKAY; 1107 } 1108 1109 1110 /* ----------------------------- presolving --------------------------------------*/ 1111 1112 /** extends a given clique of the conflict graph 1113 * 1114 * Implementation of the Bron-Kerbosch Algorithm from the paper: 1115 * Algorithm 457: Finding all Cliques of an Undirected Graph, Bron & Kerbosch, Commun. ACM, 1973 1116 */ 1117 static 1118 SCIP_RETCODE extensionOperatorSOS1( 1119 SCIP* scip, /**< SCIP pointer */ 1120 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 1121 SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of the conflict graph (only lower half filled) */ 1122 SCIP_DIGRAPH* vertexcliquegraph, /**< graph that contains the information which cliques contain a given vertex 1123 * vertices of variables = 0, ..., nsos1vars-1; vertices of cliques = nsos1vars, ..., nsos1vars+ncliques-1*/ 1124 int nsos1vars, /**< number of SOS1 variables */ 1125 int nconss, /**< number of SOS1 constraints */ 1126 SCIP_CONS* cons, /**< constraint to be extended */ 1127 SCIP_VAR** vars, /**< variables of extended clique */ 1128 SCIP_Real* weights, /**< weights of extended clique */ 1129 SCIP_Bool firstcall, /**< whether this is the first call of extension operator */ 1130 SCIP_Bool usebacktrack, /**< whether backtracking is needed for the computation */ 1131 int** cliques, /**< all cliques found so far */ 1132 int* ncliques, /**< number of clique found so far */ 1133 int* cliquesizes, /**< number of variables of current clique */ 1134 int* newclique, /**< clique we want to extended*/ 1135 int* workingset, /**< set of vertices that already served as extension and set of candidates that probably will lead to an extension */ 1136 int nworkingset, /**< length of array workingset */ 1137 int nexts, /**< number of vertices that already served as extension */ 1138 int pos, /**< position of potential candidate */ 1139 int* maxextensions, /**< maximal number of extensions */ 1140 int* naddconss, /**< number of added constraints */ 1141 SCIP_Bool* success /**< pointer to store if at least one new clique was found */ 1142 ) 1143 { 1144 int* workingsetnew = NULL; 1145 int nextsnew; 1146 int nworkingsetnew; 1147 int mincands; 1148 int btriter = 0; /* backtrack iterator */ 1149 int selvertex; 1150 int selpos = -1; 1151 int fixvertex = -1; 1152 int i; 1153 int j; 1154 1155 assert( scip != NULL ); 1156 assert( conshdlrdata != NULL ); 1157 assert( adjacencymatrix != NULL ); 1158 assert( vertexcliquegraph != NULL ); 1159 assert( cons != NULL ); 1160 assert( cliques != NULL ); 1161 assert( cliquesizes != NULL ); 1162 assert( newclique != NULL ); 1163 assert( workingset != NULL ); 1164 assert( maxextensions != NULL ); 1165 assert( naddconss != NULL ); 1166 assert( success != NULL ); 1167 1168 if ( firstcall ) 1169 *success = FALSE; 1170 1171 mincands = nworkingset; 1172 if ( mincands < 1 ) 1173 return SCIP_OKAY; 1174 1175 /* allocate buffer array */ 1176 SCIP_CALL( SCIPallocBufferArray(scip, &workingsetnew, nworkingset) ); 1177 1178 #ifdef SCIP_DEBUG 1179 for (i = 0; i < nexts; ++i) 1180 { 1181 for (j = nexts; j < nworkingset; ++j) 1182 { 1183 assert( isConnectedSOS1(adjacencymatrix, NULL, workingset[i], workingset[j]) ); 1184 } 1185 } 1186 #endif 1187 1188 /* determine candidate with minimum number of disconnections */ 1189 for (i = 0; i < nworkingset; ++i) 1190 { 1191 int vertex; 1192 int cnt = 0; 1193 1194 vertex = workingset[i]; 1195 1196 /* count disconnections */ 1197 for (j = nexts; j < nworkingset && cnt < mincands; ++j) 1198 { 1199 if ( vertex != workingset[j] && ! isConnectedSOS1(adjacencymatrix, NULL, vertex, workingset[j]) ) 1200 { 1201 cnt++; 1202 1203 /* save position of potential candidate */ 1204 pos = j; 1205 } 1206 } 1207 1208 /* check whether a new minimum was found */ 1209 if ( cnt < mincands ) 1210 { 1211 fixvertex = vertex; 1212 mincands = cnt; 1213 if ( i < nexts ) 1214 { 1215 assert( pos >= 0 ); 1216 selpos = pos; 1217 } 1218 else 1219 { 1220 selpos = i; 1221 1222 /* preincrement */ 1223 btriter = 1; 1224 } 1225 } 1226 } 1227 1228 /* If fixed point is initially chosen from candidates then number of disconnections will be preincreased by one. */ 1229 1230 /* backtrackcycle */ 1231 for (btriter = mincands + btriter; btriter >= 1; --btriter) 1232 { 1233 assert( selpos >= 0); 1234 assert( fixvertex >= 0); 1235 1236 /* interchange */ 1237 selvertex = workingset[selpos]; 1238 workingset[selpos] = workingset[nexts]; 1239 workingset[nexts] = selvertex; 1240 1241 /* create new workingset */ 1242 nextsnew = 0; 1243 for (j = 0 ; j < nexts; ++j) 1244 { 1245 if ( isConnectedSOS1(adjacencymatrix, NULL, selvertex, workingset[j]) ) 1246 workingsetnew[nextsnew++] = workingset[j]; 1247 } 1248 nworkingsetnew = nextsnew; 1249 for (j = nexts + 1; j < nworkingset; ++j) 1250 { 1251 if ( isConnectedSOS1(adjacencymatrix, NULL, selvertex, workingset[j]) ) 1252 workingsetnew[nworkingsetnew++] = workingset[j]; 1253 } 1254 1255 newclique[cliquesizes[*ncliques]++] = selvertex; 1256 1257 /* if we found a new clique */ 1258 if ( nworkingsetnew == 0 ) 1259 { 1260 char consname[SCIP_MAXSTRLEN]; 1261 SCIP_CONSDATA* consdata; 1262 SCIP_CONS* newcons; 1263 int cliqueind; 1264 1265 cliqueind = nsos1vars + *ncliques; /* index of clique in the vertex-clique graph */ 1266 1267 /* save new clique */ 1268 assert( cliquesizes[*ncliques] >= 0 && cliquesizes[*ncliques] <= nsos1vars ); 1269 assert( *ncliques < MAX(1, conshdlrdata->maxextensions) * nconss ); 1270 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(cliques[*ncliques]), cliquesizes[*ncliques]) );/*lint !e866*/ 1271 for (j = 0 ; j < cliquesizes[*ncliques]; ++j) 1272 { 1273 vars[j] = SCIPnodeGetVarSOS1(conshdlrdata->conflictgraph, newclique[j]); 1274 weights[j] = j+1; 1275 cliques[*ncliques][j] = newclique[j]; 1276 } 1277 1278 SCIPsortInt(cliques[*ncliques], cliquesizes[*ncliques]); 1279 1280 /* create new constraint */ 1281 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "extsos1_%d", conshdlrdata->cntextsos1); 1282 1283 SCIP_CALL( SCIPcreateConsSOS1(scip, &newcons, consname, cliquesizes[*ncliques], vars, weights, 1284 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), 1285 SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), 1286 SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), 1287 SCIPconsIsDynamic(cons), 1288 SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) ); 1289 1290 consdata = SCIPconsGetData(newcons); 1291 1292 /* add directed edges to the vertex-clique graph */ 1293 for (j = 0; j < consdata->nvars; ++j) 1294 { 1295 /* add arc from clique vertex to clique (needed in presolRoundConssSOS1() to delete redundand cliques) */ 1296 SCIP_CALL( SCIPdigraphAddArcSafe(vertexcliquegraph, cliques[*ncliques][j], cliqueind, NULL) ); 1297 } 1298 1299 SCIP_CALL( SCIPaddCons(scip, newcons) ); 1300 SCIP_CALL( SCIPreleaseCons(scip, &newcons) ); 1301 1302 ++(*naddconss); 1303 ++(conshdlrdata->cntextsos1); 1304 ++(*ncliques); 1305 cliquesizes[*ncliques] = cliquesizes[*ncliques-1]; /* cliquesizes[*ncliques] = size of newclique */ 1306 1307 *success = TRUE; 1308 1309 --(*maxextensions); 1310 1311 if ( *maxextensions <= 0 ) 1312 { 1313 SCIPfreeBufferArray(scip, &workingsetnew); 1314 return SCIP_OKAY; 1315 } 1316 } 1317 else if ( nextsnew < nworkingsetnew ) /* else if the number of of candidates equals zero */ 1318 { 1319 /* if backtracking is used, it is necessary to keep the memory for 'workingsetnew' */ 1320 if ( usebacktrack ) 1321 { 1322 SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, vars, weights, FALSE, usebacktrack, 1323 cliques, ncliques, cliquesizes, newclique, workingsetnew, nworkingsetnew, nextsnew, pos, maxextensions, naddconss, success) ); 1324 if ( *maxextensions <= 0 ) 1325 { 1326 SCIPfreeBufferArrayNull(scip, &workingsetnew); 1327 return SCIP_OKAY; 1328 } 1329 } 1330 else 1331 { 1332 int w; 1333 1334 assert( nworkingset >= nworkingsetnew ); 1335 for (w = 0; w < nworkingsetnew; ++w) 1336 workingset[w] = workingsetnew[w]; 1337 nworkingset = nworkingsetnew; 1338 1339 SCIPfreeBufferArrayNull(scip, &workingsetnew); 1340 1341 SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, vars, weights, FALSE, usebacktrack, 1342 cliques, ncliques, cliquesizes, newclique, workingset, nworkingset, nextsnew, pos, maxextensions, naddconss, success) ); 1343 assert( *maxextensions <= 0 ); 1344 return SCIP_OKAY; 1345 } 1346 } 1347 assert( workingsetnew != NULL ); 1348 assert( workingset != NULL ); 1349 1350 /* remove selvertex from clique */ 1351 --cliquesizes[*ncliques]; 1352 1353 /* add selvertex to the set of vertices that already served as extension */ 1354 ++nexts; 1355 1356 if ( btriter > 1 ) 1357 { 1358 /* select a candidate that is not connected to the fixed vertex */ 1359 for (j = nexts; j < nworkingset; ++j) 1360 { 1361 assert( fixvertex != workingset[j] ); 1362 if ( ! isConnectedSOS1(adjacencymatrix, NULL, fixvertex, workingset[j]) ) 1363 { 1364 selpos = j; 1365 break; 1366 } 1367 } 1368 } 1369 } 1370 1371 SCIPfreeBufferArrayNull(scip, &workingsetnew); 1372 1373 return SCIP_OKAY; 1374 } 1375 1376 1377 /** generates conflict graph that is induced by the variables of a linear constraint */ 1378 static 1379 SCIP_RETCODE genConflictgraphLinearCons( 1380 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 1381 SCIP_DIGRAPH* conflictgraphlin, /**< conflict graph of linear constraint (nodes: 1, ..., nlinvars) */ 1382 SCIP_DIGRAPH* conflictgraphorig, /**< original conflict graph (nodes: 1, ..., nsos1vars) */ 1383 SCIP_VAR** linvars, /**< linear variables in linear constraint */ 1384 int nlinvars, /**< number of linear variables in linear constraint */ 1385 int* posinlinvars /**< posinlinvars[i] = position (index) of SOS1 variable i in linear constraint, 1386 * posinlinvars[i]= -1 if @p i is not a SOS1 variable or not a variable of the linear constraint */ 1387 ) 1388 { 1389 int indexinsosvars; 1390 int indexinlinvars; 1391 int* succ; 1392 int nsucc; 1393 int v; 1394 int s; 1395 1396 assert( conflictgraphlin != NULL ); 1397 assert( conflictgraphorig != NULL ); 1398 assert( linvars != NULL ); 1399 assert( posinlinvars != NULL ); 1400 1401 for (v = 1; v < nlinvars; ++v) /* we start with v = 1, since "indexinlinvars < v" (see below) is never fulfilled for v = 0 */ 1402 { 1403 indexinsosvars = varGetNodeSOS1(conshdlrdata, linvars[v]); 1404 1405 /* if linvars[v] is contained in at least one SOS1 constraint */ 1406 if ( indexinsosvars >= 0 ) 1407 { 1408 succ = SCIPdigraphGetSuccessors(conflictgraphorig, indexinsosvars); 1409 nsucc = SCIPdigraphGetNSuccessors(conflictgraphorig, indexinsosvars); 1410 1411 for (s = 0; s < nsucc; ++s) 1412 { 1413 assert( succ[s] >= 0 ); 1414 indexinlinvars = posinlinvars[succ[s]]; 1415 assert( indexinlinvars < nlinvars ); 1416 1417 if ( indexinlinvars >= 0 && indexinlinvars < v ) 1418 { 1419 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraphlin, v, indexinlinvars, NULL) ); 1420 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraphlin, indexinlinvars, v, NULL) ); 1421 } 1422 } 1423 } 1424 } 1425 1426 return SCIP_OKAY; 1427 } 1428 1429 1430 /** determine the common successors of the vertices from the considered clique */ 1431 static 1432 SCIP_RETCODE cliqueGetCommonSuccessorsSOS1( 1433 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 1434 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 1435 int* clique, /**< current clique */ 1436 SCIP_VAR** vars, /**< clique variables */ 1437 int nvars, /**< number of clique variables */ 1438 int* comsucc, /**< pointer to store common successors of clique vertices (size = nvars) */ 1439 int* ncomsucc /**< pointer to store number common successors of clique vertices */ 1440 ) 1441 { 1442 int nsucc; 1443 int* succ; 1444 int ind; 1445 int k = 0; 1446 int v; 1447 int i; 1448 int j; 1449 1450 assert( conflictgraph != NULL ); 1451 assert( clique != NULL ); 1452 assert( vars != NULL ); 1453 assert( comsucc != NULL ); 1454 assert( ncomsucc != NULL ); 1455 1456 *ncomsucc = 0; 1457 1458 /* determine the common successors of the vertices from the considered clique */ 1459 1460 /* determine successors of variable var[0] that are not in the clique */ 1461 assert(vars[0] != NULL ); 1462 ind = varGetNodeSOS1(conshdlrdata, vars[0]); 1463 1464 if( ind == -1 ) 1465 return SCIP_INVALIDDATA; 1466 1467 assert( ind < SCIPdigraphGetNNodes(conflictgraph) ); 1468 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, ind); 1469 succ = SCIPdigraphGetSuccessors(conflictgraph, ind); 1470 1471 for (j = 0; j < nvars; ++j) 1472 { 1473 for (i = k; i < nsucc; ++i) 1474 { 1475 if ( succ[i] > clique[j] ) 1476 { 1477 k = i; 1478 break; 1479 } 1480 else if ( succ[i] == clique[j] ) 1481 { 1482 k = i + 1; 1483 break; 1484 } 1485 else 1486 comsucc[(*ncomsucc)++] = succ[i]; 1487 } 1488 } 1489 1490 /* for all variables except the first one */ 1491 for (v = 1; v < nvars; ++v) 1492 { 1493 int ncomsuccsave = 0; 1494 k = 0; 1495 1496 assert(vars[v] != NULL ); 1497 ind = varGetNodeSOS1(conshdlrdata, vars[v]); 1498 assert( ind >= 0 && ind < SCIPdigraphGetNNodes(conflictgraph) ); 1499 1500 if ( ind >= 0 ) 1501 { 1502 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, ind); 1503 succ = SCIPdigraphGetSuccessors(conflictgraph, ind); 1504 1505 /* determine successors that are in comsucc */ 1506 for (j = 0; j < *ncomsucc; ++j) 1507 { 1508 for (i = k; i < nsucc; ++i) 1509 { 1510 if ( succ[i] > comsucc[j] ) 1511 { 1512 k = i; 1513 break; 1514 } 1515 else if ( succ[i] == comsucc[j] ) 1516 { 1517 comsucc[ncomsuccsave++] = succ[i]; 1518 k = i + 1; 1519 break; 1520 } 1521 } 1522 } 1523 *ncomsucc = ncomsuccsave; 1524 } 1525 } 1526 1527 return SCIP_OKAY; 1528 } 1529 1530 1531 /** get nodes whose corresponding SOS1 variables are nonzero if an SOS1 variable of a given node is nonzero */ 1532 static 1533 SCIP_RETCODE getSOS1Implications( 1534 SCIP* scip, /**< SCIP pointer */ 1535 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 1536 SCIP_VAR** vars, /**< problem and SOS1 variables */ 1537 SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */ 1538 SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */ 1539 SCIP_Bool* implnodes, /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */ 1540 int node /**< node of the implication graph */ 1541 ) 1542 { 1543 SCIP_SUCCDATA** succdatas; 1544 int sos1node; 1545 int* succ; 1546 int nsucc; 1547 int s; 1548 1549 assert( scip != NULL ); 1550 assert( implgraph != NULL ); 1551 assert( implnodes != NULL ); 1552 assert( node >= 0 ); 1553 assert( vars[node] != NULL ); 1554 assert( SCIPhashmapGetImageInt(implhash, vars[node]) == node ); 1555 1556 /* get node of variable in the conflict graph (-1 if variable is no SOS1 variable) */ 1557 sos1node = varGetNodeSOS1(conshdlrdata, vars[node]); 1558 if ( sos1node < 0 ) 1559 return SCIP_OKAY; 1560 1561 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, node); 1562 nsucc = SCIPdigraphGetNSuccessors(implgraph, node); 1563 succ = SCIPdigraphGetSuccessors(implgraph, node); 1564 1565 for (s = 0; s < nsucc; ++s) 1566 { 1567 SCIP_SUCCDATA* data; 1568 int succnode; 1569 succnode = succ[s]; 1570 data = succdatas[s]; 1571 sos1node = varGetNodeSOS1(conshdlrdata, vars[succnode]); 1572 1573 /* if node is SOS1 and the corresponding variable is implied to be nonzero */ 1574 assert( succdatas[s] != NULL ); 1575 if ( sos1node >= 0 && ! implnodes[sos1node] && ( SCIPisFeasPositive(scip, data->lbimpl) || SCIPisFeasNegative(scip, data->ubimpl) ) ) 1576 { 1577 assert( sos1node == succnode ); 1578 implnodes[sos1node] = TRUE; 1579 SCIP_CALL( getSOS1Implications(scip, conshdlrdata, vars, implgraph, implhash, implnodes, succnode) ); 1580 } 1581 } 1582 1583 return SCIP_OKAY; 1584 } 1585 1586 1587 /** perform one presolving round for a single SOS1 constraint 1588 * 1589 * We perform the following presolving steps. 1590 * 1591 * - If the bounds of some variable force it to be nonzero, we can 1592 * fix all other variables to zero and remove the SOS1 constraints 1593 * that contain it. 1594 * - If a variable is fixed to zero, we can remove the variable. 1595 * - If a variable appears twice, it can be fixed to 0. 1596 * - We substitute appregated variables. 1597 */ 1598 static 1599 SCIP_RETCODE presolRoundConsSOS1( 1600 SCIP* scip, /**< SCIP pointer */ 1601 SCIP_CONS* cons, /**< constraint */ 1602 SCIP_CONSDATA* consdata, /**< constraint data */ 1603 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 1604 SCIP_Bool* substituted, /**< whether a variable was substituted */ 1605 SCIP_Bool* cutoff, /**< whether a cutoff happened */ 1606 SCIP_Bool* success, /**< whether we performed a successful reduction */ 1607 int* ndelconss, /**< number of deleted constraints */ 1608 int* nupgdconss, /**< number of upgraded constraints */ 1609 int* nfixedvars, /**< number of fixed variables */ 1610 int* nremovedvars /**< number of variables removed */ 1611 ) 1612 { 1613 SCIP_VAR** vars; 1614 SCIP_Bool allvarsbinary; 1615 SCIP_Bool infeasible; 1616 SCIP_Bool fixed; 1617 int nfixednonzeros; 1618 int lastFixedNonzero; 1619 int j; 1620 1621 assert( scip != NULL ); 1622 assert( cons != NULL ); 1623 assert( consdata != NULL ); 1624 assert( eventhdlr != NULL ); 1625 assert( cutoff != NULL ); 1626 assert( success != NULL ); 1627 assert( ndelconss != NULL ); 1628 assert( nfixedvars != NULL ); 1629 assert( nremovedvars != NULL ); 1630 1631 *substituted = FALSE; 1632 *cutoff = FALSE; 1633 *success = FALSE; 1634 1635 SCIPdebugMsg(scip, "Presolving SOS1 constraint <%s>.\n", SCIPconsGetName(cons) ); 1636 1637 j = 0; 1638 nfixednonzeros = 0; 1639 lastFixedNonzero = -1; 1640 allvarsbinary = TRUE; 1641 vars = consdata->vars; 1642 1643 /* check for variables fixed to 0 and bounds that fix a variable to be nonzero */ 1644 while ( j < consdata->nvars ) 1645 { 1646 int l; 1647 SCIP_VAR* var; 1648 SCIP_Real lb; 1649 SCIP_Real ub; 1650 SCIP_Real scalar; 1651 SCIP_Real constant; 1652 1653 scalar = 1.0; 1654 constant = 0.0; 1655 1656 /* check for aggregation: if the constant is zero the variable is zero iff the aggregated 1657 * variable is 0 */ 1658 var = vars[j]; 1659 SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) ); 1660 1661 /* if constant is zero and we get a different variable, substitute variable */ 1662 if ( SCIPisZero(scip, constant) && ! SCIPisZero(scip, scalar) && var != vars[j] ) 1663 { 1664 SCIPdebugMsg(scip, "substituted variable <%s> by <%s>.\n", SCIPvarGetName(vars[j]), SCIPvarGetName(var)); 1665 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[j], EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, -1) ); /*lint !e740*/ 1666 SCIP_CALL( SCIPcatchVarEvent(scip, var, EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, NULL) ); /*lint !e740*/ 1667 1668 /* change the rounding locks */ 1669 SCIP_CALL( unlockVariableSOS1(scip, cons, consdata->vars[j]) ); 1670 SCIP_CALL( lockVariableSOS1(scip, cons, var) ); 1671 1672 vars[j] = var; 1673 *substituted = TRUE; 1674 } 1675 1676 /* check whether the variable appears again later */ 1677 for (l = j+1; l < consdata->nvars; ++l) 1678 { 1679 /* if variable appeared before, we can fix it to 0 and remove it */ 1680 if ( vars[j] == vars[l] ) 1681 { 1682 SCIPdebugMsg(scip, "variable <%s> appears twice in constraint, fixing it to 0.\n", SCIPvarGetName(vars[j])); 1683 SCIP_CALL( SCIPfixVar(scip, vars[j], 0.0, &infeasible, &fixed) ); 1684 1685 if ( infeasible ) 1686 { 1687 *cutoff = TRUE; 1688 return SCIP_OKAY; 1689 } 1690 if ( fixed ) 1691 ++(*nfixedvars); 1692 } 1693 } 1694 1695 /* get bounds */ 1696 lb = SCIPvarGetLbLocal(vars[j]); 1697 ub = SCIPvarGetUbLocal(vars[j]); 1698 1699 /* if the variable if fixed to nonzero */ 1700 if ( SCIPisFeasPositive(scip, lb) || SCIPisFeasNegative(scip, ub) ) 1701 { 1702 ++nfixednonzeros; 1703 lastFixedNonzero = j; 1704 } 1705 1706 /* if the variable is fixed to 0 */ 1707 if ( SCIPisFeasZero(scip, lb) && SCIPisFeasZero(scip, ub) ) 1708 { 1709 SCIPdebugMsg(scip, "deleting variable <%s> fixed to 0.\n", SCIPvarGetName(vars[j])); 1710 SCIP_CALL( deleteVarSOS1(scip, cons, consdata, eventhdlr, j) ); 1711 ++(*nremovedvars); 1712 } 1713 else 1714 { 1715 /* check whether all variables are binary */ 1716 if ( ! SCIPvarIsBinary(vars[j]) ) 1717 allvarsbinary = FALSE; 1718 1719 ++j; 1720 } 1721 } 1722 1723 /* if the number of variables is less than 2 */ 1724 if ( consdata->nvars < 2 ) 1725 { 1726 SCIPdebugMsg(scip, "Deleting SOS1 constraint <%s> with < 2 variables.\n", SCIPconsGetName(cons)); 1727 1728 /* delete constraint */ 1729 assert( ! SCIPconsIsModifiable(cons) ); 1730 SCIP_CALL( SCIPdelCons(scip, cons) ); 1731 ++(*ndelconss); 1732 *success = TRUE; 1733 return SCIP_OKAY; 1734 } 1735 1736 /* if more than one variable are fixed to be nonzero, we are infeasible */ 1737 if ( nfixednonzeros > 1 ) 1738 { 1739 SCIPdebugMsg(scip, "The problem is infeasible: more than one variable has bounds that keep it from being 0.\n"); 1740 assert( lastFixedNonzero >= 0 ); 1741 *cutoff = TRUE; 1742 return SCIP_OKAY; 1743 } 1744 1745 /* if there is exactly one fixed nonzero variable */ 1746 if ( nfixednonzeros == 1 ) 1747 { 1748 assert( lastFixedNonzero >= 0 ); 1749 1750 /* fix all other variables to zero */ 1751 for (j = 0; j < consdata->nvars; ++j) 1752 { 1753 if ( j != lastFixedNonzero ) 1754 { 1755 SCIP_CALL( fixVariableZero(scip, vars[j], &infeasible, &fixed) ); 1756 if ( infeasible ) 1757 { 1758 *cutoff = TRUE; 1759 return SCIP_OKAY; 1760 } 1761 if ( fixed ) 1762 ++(*nfixedvars); 1763 } 1764 } 1765 1766 SCIPdebugMsg(scip, "Deleting redundant SOS1 constraint <%s> with one variable.\n", SCIPconsGetName(cons)); 1767 1768 /* delete original constraint */ 1769 assert( ! SCIPconsIsModifiable(cons) ); 1770 SCIP_CALL( SCIPdelCons(scip, cons) ); 1771 ++(*ndelconss); 1772 *success = TRUE; 1773 } 1774 /* note: there is no need to update consdata->nfixednonzeros, since the constraint is deleted as soon nfixednonzeros > 0. */ 1775 else 1776 { 1777 /* if all variables are binary create a set packing constraint */ 1778 if ( allvarsbinary && SCIPfindConshdlr(scip, "setppc") != NULL ) 1779 { 1780 SCIP_CONS* setpackcons; 1781 1782 /* create, add, and release the logicor constraint */ 1783 SCIP_CALL( SCIPcreateConsSetpack(scip, &setpackcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars, 1784 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), 1785 SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), 1786 SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) ); 1787 SCIP_CALL( SCIPaddCons(scip, setpackcons) ); 1788 SCIP_CALL( SCIPreleaseCons(scip, &setpackcons) ); 1789 1790 SCIPdebugMsg(scip, "Upgrading SOS1 constraint <%s> to set packing constraint.\n", SCIPconsGetName(cons)); 1791 1792 /* remove the SOS1 constraint globally */ 1793 assert( ! SCIPconsIsModifiable(cons) ); 1794 SCIP_CALL( SCIPdelCons(scip, cons) ); 1795 ++(*nupgdconss); 1796 *success = TRUE; 1797 } 1798 } 1799 1800 return SCIP_OKAY; 1801 } 1802 1803 1804 1805 /** perform one presolving round for all SOS1 constraints 1806 * 1807 * We perform the following presolving steps. 1808 * 1809 * - If the bounds of some variable force it to be nonzero, we can 1810 * fix all other variables to zero and remove the SOS1 constraints 1811 * that contain it. 1812 * - If a variable is fixed to zero, we can remove the variable. 1813 * - If a variable appears twice, it can be fixed to 0. 1814 * - We substitute appregated variables. 1815 * - Remove redundant SOS1 constraints 1816 * 1817 * If the adjacency matrix of the conflict graph is present, then 1818 * we perform the following additional presolving steps 1819 * 1820 * - Search for larger SOS1 constraints in the conflict graph 1821 * 1822 * @todo Use one long array for storing cliques. 1823 */ 1824 static 1825 SCIP_RETCODE presolRoundConssSOS1( 1826 SCIP* scip, /**< SCIP pointer */ 1827 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 1828 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 1829 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 1830 SCIP_Bool** adjacencymatrix, /**< adjacency matrix of conflict graph (or NULL) */ 1831 SCIP_CONS** conss, /**< SOS1 constraints */ 1832 int nconss, /**< number of SOS1 constraints */ 1833 int nsos1vars, /**< number of SOS1 variables */ 1834 int* naddconss, /**< number of added constraints */ 1835 int* ndelconss, /**< number of deleted constraints */ 1836 int* nupgdconss, /**< number of upgraded constraints */ 1837 int* nfixedvars, /**< number of fixed variables */ 1838 int* nremovedvars, /**< number of variables removed */ 1839 SCIP_RESULT* result /**< result */ 1840 ) 1841 { 1842 SCIP_DIGRAPH* vertexcliquegraph; 1843 SCIP_VAR** consvars; 1844 SCIP_Real* consweights; 1845 int** cliques = NULL; 1846 int ncliques = 0; 1847 int* cliquesizes = NULL; 1848 int* newclique = NULL; 1849 int* indconss = NULL; 1850 int* lengthconss = NULL; 1851 int* comsucc = NULL; 1852 int csize; 1853 int iter; 1854 int c; 1855 1856 assert( scip != NULL ); 1857 assert( eventhdlr != NULL ); 1858 assert( conshdlrdata != NULL ); 1859 assert( conflictgraph != NULL ); 1860 assert( conss != NULL ); 1861 assert( naddconss != NULL ); 1862 assert( ndelconss != NULL ); 1863 assert( nupgdconss != NULL ); 1864 assert( nfixedvars != NULL ); 1865 assert( nremovedvars != NULL ); 1866 assert( result != NULL ); 1867 1868 /* create digraph whose nodes represent variables and cliques in the conflict graph */ 1869 csize = MAX(1, conshdlrdata->maxextensions) * nconss; 1870 SCIP_CALL( SCIPcreateDigraph(scip, &vertexcliquegraph, nsos1vars + csize) ); 1871 1872 /* allocate buffer arrays */ 1873 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nsos1vars) ); 1874 SCIP_CALL( SCIPallocBufferArray(scip, &consweights, nsos1vars) ); 1875 SCIP_CALL( SCIPallocBufferArray(scip, &newclique, nsos1vars) ); 1876 SCIP_CALL( SCIPallocBufferArray(scip, &indconss, csize) ); 1877 SCIP_CALL( SCIPallocBufferArray(scip, &lengthconss, csize) ); 1878 SCIP_CALL( SCIPallocBufferArray(scip, &comsucc, MAX(nsos1vars, csize)) ); 1879 1880 /* Use block memory for cliques, because sizes might be quite different and allocation interfers with workingset. */ 1881 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cliquesizes, csize) ); 1882 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cliques, csize) ); 1883 1884 /* get constraint indices and sort them in descending order of their lengths */ 1885 for (c = 0; c < nconss; ++c) 1886 { 1887 SCIP_CONSDATA* consdata; 1888 1889 consdata = SCIPconsGetData(conss[c]); 1890 assert( consdata != NULL ); 1891 1892 indconss[c] = c; 1893 lengthconss[c] = consdata->nvars; 1894 } 1895 SCIPsortDownIntInt(lengthconss, indconss, nconss); 1896 1897 /* check each constraint */ 1898 for (iter = 0; iter < nconss; ++iter) 1899 { 1900 SCIP_CONSDATA* consdata; 1901 SCIP_CONS* cons; 1902 SCIP_Bool substituted; 1903 SCIP_Bool success; 1904 SCIP_Bool cutoff; 1905 int savennupgdconss; 1906 int savendelconss; 1907 1908 SCIP_VAR** vars; 1909 int nvars; 1910 1911 c = indconss[iter]; 1912 1913 assert( conss != NULL ); 1914 assert( conss[c] != NULL ); 1915 cons = conss[c]; 1916 consdata = SCIPconsGetData(cons); 1917 1918 assert( consdata != NULL ); 1919 assert( consdata->nvars >= 0 ); 1920 assert( consdata->nvars <= consdata->maxvars ); 1921 assert( ! SCIPconsIsModifiable(cons) ); 1922 assert( ncliques < csize ); 1923 1924 savendelconss = *ndelconss; 1925 savennupgdconss = *nupgdconss; 1926 1927 /* perform one presolving round for SOS1 constraint */ 1928 SCIP_CALL( presolRoundConsSOS1(scip, cons, consdata, eventhdlr, &substituted, &cutoff, &success, ndelconss, nupgdconss, nfixedvars, nremovedvars) ); 1929 1930 if ( cutoff ) 1931 { 1932 *result = SCIP_CUTOFF; 1933 break; 1934 } 1935 1936 if ( *ndelconss > savendelconss || *nupgdconss > savennupgdconss || substituted ) 1937 { 1938 *result = SCIP_SUCCESS; 1939 continue; 1940 } 1941 1942 if ( success ) 1943 *result = SCIP_SUCCESS; 1944 1945 /* get number of variables of constraint */ 1946 nvars = consdata->nvars; 1947 1948 /* get variables of constraint */ 1949 vars = consdata->vars; 1950 1951 if ( nvars > 1 && conshdlrdata->maxextensions != 0 ) 1952 { 1953 SCIP_Bool extended = FALSE; 1954 int cliquesize = 0; 1955 int ncomsucc = 0; 1956 int varprobind; 1957 int j; 1958 1959 /* get clique and size of clique */ 1960 for (j = 0; j < nvars; ++j) 1961 { 1962 varprobind = varGetNodeSOS1(conshdlrdata, vars[j]); 1963 1964 if ( varprobind >= 0 ) 1965 newclique[cliquesize++] = varprobind; 1966 } 1967 1968 if ( cliquesize > 1 ) 1969 { 1970 cliquesizes[ncliques] = cliquesize; 1971 1972 /* sort clique vertices */ 1973 SCIPsortInt(newclique, cliquesizes[ncliques]); 1974 1975 /* check if clique is contained in an already known clique */ 1976 if ( ncliques > 0 ) 1977 { 1978 int* succ; 1979 int nsucc; 1980 int v; 1981 1982 varprobind = newclique[0]; 1983 ncomsucc = SCIPdigraphGetNSuccessors(vertexcliquegraph, varprobind); 1984 succ = SCIPdigraphGetSuccessors(vertexcliquegraph, varprobind); 1985 1986 /* get all (already processed) cliques that contain 'varpropind' */ 1987 for (j = 0; j < ncomsucc; ++j) 1988 { 1989 /* successors should have been sorted in a former step of the algorithm */ 1990 assert( j == 0 || succ[j] > succ[j-1] ); 1991 comsucc[j] = succ[j]; 1992 } 1993 1994 /* loop through remaining nodes of clique (case v = 0 already processed) */ 1995 for (v = 1; v < cliquesize && ncomsucc > 0; ++v) 1996 { 1997 varprobind = newclique[v]; 1998 1999 /* get all (already processed) cliques that contain 'varpropind' */ 2000 nsucc = SCIPdigraphGetNSuccessors(vertexcliquegraph, varprobind); 2001 succ = SCIPdigraphGetSuccessors(vertexcliquegraph, varprobind); 2002 assert( succ != NULL || nsucc == 0 ); 2003 2004 if ( nsucc < 1 ) 2005 { 2006 ncomsucc = 0; 2007 break; 2008 } 2009 2010 /* get intersection with comsucc */ 2011 SCIPcomputeArraysIntersectionInt(comsucc, ncomsucc, succ, nsucc, comsucc, &ncomsucc); 2012 } 2013 } 2014 2015 /* if constraint is redundand then delete it */ 2016 if ( ncomsucc > 0 ) 2017 { 2018 assert( ! SCIPconsIsModifiable(cons) ); 2019 SCIP_CALL( SCIPdelCons(scip, cons) ); 2020 ++(*ndelconss); 2021 *result = SCIP_SUCCESS; 2022 continue; 2023 } 2024 2025 if ( conshdlrdata->maxextensions != 0 && adjacencymatrix != NULL ) 2026 { 2027 int maxextensions; 2028 ncomsucc = 0; 2029 2030 /* determine the common successors of the vertices from the considered clique */ 2031 SCIP_CALL( cliqueGetCommonSuccessorsSOS1(conshdlrdata, conflictgraph, newclique, vars, nvars, comsucc, &ncomsucc) ); 2032 2033 /* find extensions for the clique */ 2034 maxextensions = conshdlrdata->maxextensions; 2035 extended = FALSE; 2036 SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, consvars, consweights, 2037 TRUE, (maxextensions <= 1) ? FALSE : TRUE, cliques, &ncliques, cliquesizes, newclique, comsucc, ncomsucc, 0, -1, &maxextensions, 2038 naddconss, &extended) ); 2039 } 2040 2041 /* if an extension was found for the current clique then free the old SOS1 constraint */ 2042 if ( extended ) 2043 { 2044 assert( ! SCIPconsIsModifiable(cons) ); 2045 SCIP_CALL( SCIPdelCons(scip, cons) ); 2046 ++(*ndelconss); 2047 *result = SCIP_SUCCESS; 2048 } 2049 else /* if we keep the constraint */ 2050 { 2051 int cliqueind; 2052 2053 cliqueind = nsos1vars + ncliques; /* index of clique in vertex-clique graph */ 2054 2055 /* add directed edges to the vertex-clique graph */ 2056 assert( cliquesize >= 0 && cliquesize <= nsos1vars ); 2057 assert( ncliques < csize ); 2058 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cliques[ncliques], cliquesize) );/*lint !e866*/ 2059 for (j = 0; j < cliquesize; ++j) 2060 { 2061 cliques[ncliques][j] = newclique[j]; 2062 SCIP_CALL( SCIPdigraphAddArcSafe(vertexcliquegraph, cliques[ncliques][j], cliqueind, NULL) ); 2063 } 2064 2065 /* update number of maximal cliques */ 2066 ++ncliques; 2067 } 2068 } 2069 } 2070 } 2071 2072 /* free buffer arrays */ 2073 for (c = ncliques-1; c >= 0; --c) 2074 SCIPfreeBlockMemoryArray(scip, &cliques[c], cliquesizes[c]); 2075 SCIPfreeBlockMemoryArrayNull(scip, &cliques, csize); 2076 SCIPfreeBlockMemoryArrayNull(scip, &cliquesizes, csize); 2077 2078 SCIPfreeBufferArrayNull(scip, &comsucc); 2079 SCIPfreeBufferArrayNull(scip, &lengthconss); 2080 SCIPfreeBufferArrayNull(scip, &indconss); 2081 SCIPfreeBufferArrayNull(scip, &newclique); 2082 SCIPfreeBufferArrayNull(scip, &consweights); 2083 SCIPfreeBufferArrayNull(scip, &consvars); 2084 SCIPdigraphFree(&vertexcliquegraph); 2085 2086 return SCIP_OKAY; 2087 } 2088 2089 2090 /** performs implication graph analysis 2091 * 2092 * Tentatively fixes a variable to nonzeero and extracts consequences from it: 2093 * - adds (possibly new) complementarity constraints to the problem if variables are implied to be zero 2094 * - returns that the subproblem is infeasible if the domain of a variable turns out to be empty 2095 */ 2096 static 2097 SCIP_RETCODE performImplicationGraphAnalysis( 2098 SCIP* scip, /**< SCIP pointer */ 2099 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 2100 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 2101 SCIP_VAR** totalvars, /**< problem and SOS1 variables */ 2102 SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */ 2103 SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */ 2104 SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of the conflict graph (only lower half filled) */ 2105 int givennode, /**< node of the conflict graph */ 2106 int nonznode, /**< node of the conflict graph that is implied to be nonzero if given node is nonzero */ 2107 SCIP_Real* impllbs, /**< current lower variable bounds if given node is nonzero (update possible) */ 2108 SCIP_Real* implubs, /**< current upper variable bounds if given node is nonzero (update possible) */ 2109 SCIP_Bool* implnodes, /**< indicates which variables are currently implied to be nonzero if given node is nonzero (update possible) */ 2110 int* naddconss, /**< pointer to store number of added SOS1 constraints */ 2111 int* probingdepth, /**< pointer to store current probing depth */ 2112 SCIP_Bool* infeasible /**< pointer to store whether the subproblem gets infeasible if variable to 'nonznode' is nonzero */ 2113 ) 2114 { 2115 SCIP_SUCCDATA** succdatas; 2116 int succnode; 2117 int* succ; 2118 int nsucc; 2119 int s; 2120 2121 assert( nonznode >= 0 && nonznode < SCIPdigraphGetNNodes(conflictgraph) ); 2122 2123 /* check probing depth */ 2124 if ( conshdlrdata->depthimplanalysis >= 0 && *probingdepth >= conshdlrdata->depthimplanalysis ) 2125 return SCIP_OKAY; 2126 ++(*probingdepth); 2127 2128 /* get successors of 'nonznode' in the conflict graph */ 2129 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, nonznode); 2130 succ = SCIPdigraphGetSuccessors(conflictgraph, nonznode); 2131 2132 /* loop through neighbors of 'nonznode' in the conflict graph; these variables are implied to be zero */ 2133 for (s = 0; s < nsucc; ++s) 2134 { 2135 succnode = succ[s]; 2136 2137 /* if the current variable domain of the successor node does not contain the value zero then return that the problem is infeasible 2138 * else if 'succnode' is not already complementary to 'givennode' then add a new complementarity constraint */ 2139 if ( givennode == succnode || SCIPisFeasPositive(scip, impllbs[succnode]) || SCIPisFeasNegative(scip, implubs[succnode]) ) 2140 { 2141 *infeasible = TRUE; 2142 return SCIP_OKAY; 2143 } 2144 else if ( ! isConnectedSOS1(adjacencymatrix, NULL, givennode, succnode) ) 2145 { 2146 char namesos[SCIP_MAXSTRLEN]; 2147 SCIP_CONS* soscons = NULL; 2148 SCIP_VAR* var1; 2149 SCIP_VAR* var2; 2150 2151 /* update implied bounds of succnode */ 2152 impllbs[succnode] = 0; 2153 implubs[succnode] = 0; 2154 2155 /* add arcs to the conflict graph */ 2156 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, givennode, succnode, NULL) ); 2157 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, succnode, givennode, NULL) ); 2158 2159 /* resort successors */ 2160 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, givennode), SCIPdigraphGetNSuccessors(conflictgraph, givennode)); 2161 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, succnode), SCIPdigraphGetNSuccessors(conflictgraph, succnode)); 2162 2163 /* update adjacencymatrix */ 2164 if ( givennode > succnode ) 2165 adjacencymatrix[givennode][succnode] = 1; 2166 else 2167 adjacencymatrix[succnode][givennode] = 1; 2168 2169 var1 = SCIPnodeGetVarSOS1(conflictgraph, givennode); 2170 var2 = SCIPnodeGetVarSOS1(conflictgraph, succnode); 2171 2172 /* create SOS1 constraint */ 2173 assert( SCIPgetDepth(scip) == 0 ); 2174 (void) SCIPsnprintf(namesos, SCIP_MAXSTRLEN, "presolved_sos1_%s_%s", SCIPvarGetName(var1), SCIPvarGetName(var2) ); 2175 SCIP_CALL( SCIPcreateConsSOS1(scip, &soscons, namesos, 0, NULL, NULL, TRUE, TRUE, TRUE, FALSE, TRUE, 2176 FALSE, FALSE, FALSE, FALSE) ); 2177 2178 /* add variables to SOS1 constraint */ 2179 SCIP_CALL( addVarSOS1(scip, soscons, conshdlrdata, var1, 1.0) ); 2180 SCIP_CALL( addVarSOS1(scip, soscons, conshdlrdata, var2, 2.0) ); 2181 2182 /* add constraint */ 2183 SCIP_CALL( SCIPaddCons(scip, soscons) ); 2184 2185 /* release constraint */ 2186 SCIP_CALL( SCIPreleaseCons(scip, &soscons) ); 2187 2188 ++(*naddconss); 2189 } 2190 } 2191 2192 /* by construction: nodes of SOS1 variables are equal for conflict graph and implication graph */ 2193 assert( nonznode == SCIPhashmapGetImageInt(implhash, SCIPnodeGetVarSOS1(conflictgraph, nonznode)) ); 2194 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, nonznode); 2195 nsucc = SCIPdigraphGetNSuccessors(implgraph, nonznode); 2196 succ = SCIPdigraphGetSuccessors(implgraph, nonznode); 2197 2198 /* go further in implication graph */ 2199 for (s = 0; s < nsucc; ++s) 2200 { 2201 SCIP_SUCCDATA* data; 2202 int oldprobingdepth; 2203 2204 succnode = succ[s]; 2205 data = succdatas[s]; 2206 oldprobingdepth = *probingdepth; 2207 2208 /* if current lower bound is smaller than implied lower bound */ 2209 if ( SCIPisFeasLT(scip, impllbs[succnode], data->lbimpl) ) 2210 { 2211 impllbs[succnode] = data->lbimpl; 2212 2213 /* if node is SOS1 and implied to be nonzero for the first time, then this recursively may imply further bound changes */ 2214 if ( varGetNodeSOS1(conshdlrdata, totalvars[succnode]) >= 0 && ! implnodes[succnode] && SCIPisFeasPositive(scip, data->lbimpl) ) 2215 { 2216 /* by construction: nodes of SOS1 variables are equal for conflict graph and implication graph */ 2217 assert( succnode == SCIPhashmapGetImageInt(implhash, SCIPnodeGetVarSOS1(conflictgraph, succnode)) ); 2218 implnodes[succnode] = TRUE; /* in order to avoid cycling */ 2219 SCIP_CALL( performImplicationGraphAnalysis(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, adjacencymatrix, givennode, succnode, impllbs, implubs, implnodes, naddconss, probingdepth, infeasible) ); 2220 *probingdepth = oldprobingdepth; 2221 2222 /* return if the subproblem is known to be infeasible */ 2223 if ( *infeasible ) 2224 return SCIP_OKAY; 2225 } 2226 } 2227 2228 /* if current upper bound is larger than implied upper bound */ 2229 if ( SCIPisFeasGT(scip, implubs[succnode], data->ubimpl) ) 2230 { 2231 implubs[succnode] = data->ubimpl; 2232 2233 /* if node is SOS1 and implied to be nonzero for the first time, then this recursively may imply further bound changes */ 2234 if ( varGetNodeSOS1(conshdlrdata, totalvars[succnode]) >= 0 && ! implnodes[succnode] && SCIPisFeasNegative(scip, data->ubimpl) ) 2235 { 2236 /* by construction: nodes of SOS1 variables are equal for conflict graph and implication graph */ 2237 assert( succnode == SCIPhashmapGetImageInt(implhash, SCIPnodeGetVarSOS1(conflictgraph, succnode)) ); 2238 implnodes[succnode] = TRUE; /* in order to avoid cycling */ 2239 SCIP_CALL( performImplicationGraphAnalysis(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, adjacencymatrix, givennode, succnode, impllbs, implubs, implnodes, naddconss, probingdepth, infeasible) ); 2240 *probingdepth = oldprobingdepth; 2241 2242 /* return if the subproblem is known to be infeasible */ 2243 if ( *infeasible ) 2244 return SCIP_OKAY; 2245 } 2246 } 2247 } 2248 2249 return SCIP_OKAY; 2250 } 2251 2252 2253 /** returns whether node is implied to be zero; this information is taken from the input array 'implnodes' */ 2254 static 2255 SCIP_Bool isImpliedZero( 2256 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 2257 SCIP_Bool* implnodes, /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */ 2258 int node /**< node of the conflict graph (or -1) */ 2259 ) 2260 { 2261 int* succ; 2262 int nsucc; 2263 int s; 2264 2265 if ( node < 0 ) 2266 return FALSE; 2267 2268 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node); 2269 succ = SCIPdigraphGetSuccessors(conflictgraph, node); 2270 2271 /* check whether any successor is implied to be nonzero */ 2272 for (s = 0; s < nsucc; ++s) 2273 { 2274 if ( implnodes[succ[s]] ) 2275 return TRUE; 2276 } 2277 2278 return FALSE; 2279 } 2280 2281 2282 /** updates arc data of implication graph */ 2283 static 2284 SCIP_RETCODE updateArcData( 2285 SCIP* scip, /**< SCIP pointer */ 2286 SCIP_DIGRAPH* implgraph, /**< implication graph */ 2287 SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */ 2288 SCIP_VAR** totalvars, /**< problem and SOS1 variables */ 2289 SCIP_VAR* varv, /**< variable that is assumed to be nonzero */ 2290 SCIP_VAR* varw, /**< implication variable */ 2291 SCIP_Real lb, /**< old lower bound of \f$x_w\f$ */ 2292 SCIP_Real ub, /**< old upper bound of \f$x_w\f$ */ 2293 SCIP_Real newbound, /**< new bound of \f$x_w\f$ */ 2294 SCIP_Bool lower, /**< whether to consider lower bound implication (otherwise upper bound) */ 2295 int* nchgbds, /**< pointer to store number of changed bounds */ 2296 SCIP_Bool* update, /**< pointer to store whether implication graph has been updated */ 2297 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility has been detected */ 2298 ) 2299 { 2300 SCIP_SUCCDATA** succdatas; 2301 SCIP_SUCCDATA* data = NULL; 2302 int nsucc; 2303 int* succ; 2304 int indv; 2305 int indw; 2306 int s; 2307 2308 assert( scip != NULL ); 2309 assert( implgraph != NULL ); 2310 assert( implhash != NULL ); 2311 assert( totalvars != NULL ); 2312 assert( varv != NULL ); 2313 assert( varw != NULL ); 2314 2315 /* if x_v != 0 turns out to be infeasible then fix x_v = 0 */ 2316 if ( ( lower && SCIPisFeasLT(scip, ub, newbound) ) || ( ! lower && SCIPisFeasGT(scip, lb, newbound) ) ) 2317 { 2318 SCIP_Bool infeasible1; 2319 SCIP_Bool infeasible2; 2320 SCIP_Bool tightened1; 2321 SCIP_Bool tightened2; 2322 2323 SCIP_CALL( SCIPtightenVarLb(scip, varv, 0.0, FALSE, &infeasible1, &tightened1) ); 2324 SCIP_CALL( SCIPtightenVarUb(scip, varv, 0.0, FALSE, &infeasible2, &tightened2) ); 2325 2326 if ( infeasible1 || infeasible2 ) 2327 { 2328 SCIPdebugMsg(scip, "detected infeasibility while trying to fix variable <%s> to zero\n", SCIPvarGetName(varv)); 2329 *infeasible = TRUE; 2330 } 2331 2332 if ( tightened1 || tightened2 ) 2333 { 2334 SCIPdebugMsg(scip, "fixed variable %s from lb = %f and ub = %f to 0.0 \n", SCIPvarGetName(varv), lb, ub); 2335 ++(*nchgbds); 2336 } 2337 } 2338 2339 /* get successor information */ 2340 indv = SCIPhashmapGetImageInt(implhash, varv); /* get index of x_v in implication graph */ 2341 assert( SCIPhashmapGetImageInt(implhash, totalvars[indv]) == indv ); 2342 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, indv); 2343 nsucc = SCIPdigraphGetNSuccessors(implgraph, indv); 2344 succ = SCIPdigraphGetSuccessors(implgraph, indv); 2345 2346 /* search for nodew in existing successors. If this is the case then check whether the lower implication bound may be updated ... */ 2347 indw = SCIPhashmapGetImageInt(implhash, varw); 2348 assert( SCIPhashmapGetImageInt(implhash, totalvars[indw]) == indw ); 2349 for (s = 0; s < nsucc; ++s) 2350 { 2351 if ( succ[s] == indw ) 2352 { 2353 data = succdatas[s]; 2354 assert( data != NULL ); 2355 if ( lower && SCIPisFeasLT(scip, data->lbimpl, newbound) ) 2356 { 2357 if ( SCIPvarIsIntegral(varw) ) 2358 data->lbimpl = SCIPceil(scip, newbound); 2359 else 2360 data->lbimpl = newbound; 2361 2362 *update = TRUE; 2363 SCIPdebugMsg(scip, "updated to implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound); 2364 } 2365 else if ( ! lower && SCIPisFeasGT(scip, data->ubimpl, newbound) ) 2366 { 2367 if ( SCIPvarIsIntegral(varw) ) 2368 data->ubimpl = SCIPfloor(scip, newbound); 2369 else 2370 data->ubimpl = newbound; 2371 2372 *update = TRUE; 2373 SCIPdebugMsg(scip, "updated to implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound); 2374 } 2375 break; 2376 } 2377 } 2378 2379 /* ..., otherwise if there does not exist an arc between indv and indw already, then create one and add implication */ 2380 if ( s == nsucc ) 2381 { 2382 assert( data == NULL ); 2383 SCIP_CALL( SCIPallocBlockMemory(scip, &data) ); 2384 if ( lower ) 2385 { 2386 data->lbimpl = newbound; 2387 data->ubimpl = ub; 2388 SCIPdebugMsg(scip, "add implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound); 2389 } 2390 else 2391 { 2392 data->lbimpl = lb; 2393 data->ubimpl = newbound; 2394 SCIPdebugMsg(scip, "add implication %s != 0 -> %s <= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound); 2395 } 2396 SCIP_CALL( SCIPdigraphAddArc(implgraph, indv, indw, (void*)data) ); 2397 *update = TRUE; 2398 } 2399 2400 return SCIP_OKAY; 2401 } 2402 2403 2404 /** updates implication graph 2405 * 2406 * Assume the variable from the input is nonzero. If this implies that some other variable is also nonzero, then 2407 * store this information in an implication graph 2408 */ 2409 static 2410 SCIP_RETCODE updateImplicationGraphSOS1( 2411 SCIP* scip, /**< SCIP pointer */ 2412 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 2413 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 2414 SCIP_Bool** adjacencymatrix, /**< adjacency matrix of conflict graph (lower half) */ 2415 SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */ 2416 SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */ 2417 SCIP_Bool* implnodes, /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */ 2418 SCIP_VAR** totalvars, /**< problem and SOS1 variables */ 2419 int** cliquecovers, /**< clique covers of linear constraint */ 2420 int* cliquecoversizes, /**< size of clique covers */ 2421 int* varincover, /**< array with varincover[i] = cover of SOS1 index @p i */ 2422 SCIP_VAR** vars, /**< variables to be checked */ 2423 SCIP_Real* coefs, /**< coefficients of variables in linear constraint */ 2424 int nvars, /**< number of variables to be checked */ 2425 SCIP_Real* bounds, /**< bounds of variables */ 2426 SCIP_VAR* var, /**< variable that is assumed to be nonzero */ 2427 SCIP_Real bound, /**< bound of variable */ 2428 SCIP_Real boundnonzero, /**< bound of variable if it is known to be nonzero if infinity values are not summarized */ 2429 int ninftynonzero, /**< number of times infinity/-infinity has to be summarized to boundnonzero */ 2430 SCIP_Bool lower, /**< TRUE if lower bounds are consideres; FALSE for upper bounds */ 2431 int* nchgbds, /**< pointer to store number of changed bounds */ 2432 SCIP_Bool* update, /**< pointer to store whether implication graph has been updated */ 2433 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility has been detected */ 2434 ) 2435 { 2436 int nodev; 2437 int w; 2438 2439 assert( update != NULL ); 2440 2441 /* update implication graph if possible */ 2442 *update = FALSE; 2443 *infeasible = FALSE; 2444 nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */ 2445 2446 /* if nodev is an index of an SOS1 variable and at least one lower bound of a variable that is not x_v is infinity */ 2447 if ( nodev < 0 || SCIPisInfinity(scip, REALABS(bound)) || ninftynonzero > 1 ) 2448 return SCIP_OKAY; 2449 2450 /* for every variable x_w: compute upper bound of a_w * x_w if x_v is known to be nonzero */ 2451 for (w = 0; w < nvars; ++w) 2452 { 2453 int newninftynonzero; 2454 SCIP_Bool implinfty = FALSE; 2455 int nodew; 2456 2457 /* get node of x_w in conflict graph: nodew = -1 if it is no SOS1 variable */ 2458 nodew = varGetNodeSOS1(conshdlrdata, vars[w]); 2459 2460 newninftynonzero = ninftynonzero; 2461 2462 /* variable should not be fixed to be already zero (note x_v is fixed to be nonzero by assumption) */ 2463 if ( nodew < 0 || ( nodev != nodew && ! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodew) && ! isImpliedZero(conflictgraph, implnodes, nodew) ) ) 2464 { 2465 SCIP_Real implbound; 2466 SCIP_Bool implcoverw; 2467 int nodecliq; 2468 int indcliq; 2469 int ind; 2470 int j; 2471 2472 /* boundnonzero is the bound of x_v if x_v is nonzero we use this information to get a bound of x_w if x_v is 2473 * nonzero; therefore, we have to perform some recomputations */ 2474 implbound = boundnonzero - bound; 2475 ind = varincover[w]; 2476 assert( cliquecoversizes[ind] > 0 ); 2477 2478 implcoverw = FALSE; 2479 for (j = 0; j < cliquecoversizes[ind]; ++j) 2480 { 2481 indcliq = cliquecovers[ind][j]; 2482 assert( 0 <= indcliq && indcliq < nvars ); 2483 2484 nodecliq = varGetNodeSOS1(conshdlrdata, vars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */ 2485 2486 /* if nodecliq is not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0 */ 2487 if ( nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) ) 2488 { 2489 if ( indcliq == w ) 2490 { 2491 if ( !SCIPisInfinity(scip, REALABS(bounds[w])) && !SCIPisInfinity(scip, REALABS(implbound + bounds[w])) ) 2492 implbound += bounds[w]; 2493 else 2494 --newninftynonzero; 2495 implcoverw = TRUE; 2496 } 2497 else if ( implcoverw ) 2498 { 2499 if ( SCIPisInfinity(scip, REALABS(bounds[indcliq])) || SCIPisInfinity(scip, REALABS(implbound - bounds[indcliq])) ) 2500 implinfty = TRUE; 2501 else 2502 implbound -= bounds[indcliq]; 2503 break; 2504 } 2505 else 2506 { 2507 if ( SCIPisInfinity(scip, REALABS(bounds[indcliq])) ) 2508 implinfty = TRUE; 2509 break; 2510 } 2511 } 2512 } 2513 2514 /* check whether x_v != 0 implies a bound change of x_w */ 2515 if ( ! implinfty && newninftynonzero == 0 ) 2516 { 2517 SCIP_Real newbound; 2518 SCIP_Real coef; 2519 SCIP_Real lb; 2520 SCIP_Real ub; 2521 2522 lb = SCIPvarGetLbLocal(vars[w]); 2523 ub = SCIPvarGetUbLocal(vars[w]); 2524 coef = coefs[w]; 2525 2526 if ( SCIPisFeasZero(scip, coef) ) 2527 continue; 2528 2529 newbound = implbound / coef; 2530 2531 if ( SCIPisInfinity(scip, newbound) ) 2532 continue; 2533 2534 /* check if an implication can be added/updated or assumption x_v != 0 is infeasible */ 2535 if ( lower ) 2536 { 2537 if ( SCIPisFeasPositive(scip, coef) && SCIPisFeasLT(scip, lb, newbound) ) 2538 { 2539 SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, TRUE, nchgbds, update, infeasible) ); 2540 } 2541 else if ( SCIPisFeasNegative(scip, coef) && SCIPisFeasGT(scip, ub, newbound) ) 2542 { 2543 SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, FALSE, nchgbds, update, infeasible) ); 2544 } 2545 } 2546 else 2547 { 2548 if ( SCIPisFeasPositive(scip, coef) && SCIPisFeasGT(scip, ub, newbound) ) 2549 { 2550 SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, FALSE, nchgbds, update, infeasible) ); 2551 } 2552 else if ( SCIPisFeasNegative(scip, coef) && SCIPisFeasLT(scip, lb, newbound) ) 2553 { 2554 SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, TRUE, nchgbds, update, infeasible) ); 2555 } 2556 } 2557 } 2558 } 2559 } 2560 2561 return SCIP_OKAY; 2562 } 2563 2564 2565 /** search new disjoint clique that covers given node 2566 * 2567 * For a given vertex @p v search for a clique of the conflict graph induced by the variables of a linear constraint that 2568 * - covers @p v and 2569 * - has an an empty intersection with already computed clique cover. 2570 */ 2571 static 2572 SCIP_RETCODE computeVarsCoverSOS1( 2573 SCIP* scip, /**< SCIP pointer */ 2574 SCIP_DIGRAPH* conflictgraphroot, /**< conflict graph of the root node (nodes: 1, ..., @p nsos1vars) */ 2575 SCIP_DIGRAPH* conflictgraphlin, /**< conflict graph of linear constraint (nodes: 1, ..., @p nlinvars) */ 2576 SCIP_VAR** linvars, /**< variables in linear constraint */ 2577 SCIP_Bool* coveredvars, /**< states which variables of the linear constraint are currently covered by a clique */ 2578 int* clique, /**< array to store new clique in cover */ 2579 int* cliquesize, /**< pointer to store the size of @p clique */ 2580 int v, /**< position of variable in linear constraint that should be covered */ 2581 SCIP_Bool considersolvals /**< TRUE if largest auxiliary bigM values of variables should be prefered */ 2582 ) 2583 { 2584 int nsucc; 2585 int s; 2586 2587 assert( conflictgraphlin != NULL ); 2588 assert( linvars != NULL ); 2589 assert( coveredvars != NULL ); 2590 assert( clique != NULL ); 2591 assert( cliquesize != NULL ); 2592 2593 assert( ! coveredvars[v] ); /* we should produce a new clique */ 2594 2595 /* add index 'v' to the clique cover */ 2596 clique[0] = v; 2597 *cliquesize = 1; 2598 2599 nsucc = SCIPdigraphGetNSuccessors(conflictgraphlin, v); 2600 if ( nsucc > 0 ) 2601 { 2602 int* extensions; 2603 int nextensions = 0; 2604 int nextensionsnew; 2605 int succnode; 2606 int* succ; 2607 2608 /* allocate buffer array */ 2609 SCIP_CALL( SCIPallocBufferArray(scip, &extensions, nsucc) ); 2610 2611 succ = SCIPdigraphGetSuccessors(conflictgraphlin, v); 2612 2613 /* compute possible extensions for the clique cover */ 2614 for (s = 0; s < nsucc; ++s) 2615 { 2616 succnode = succ[s]; 2617 if ( ! coveredvars[succnode] ) 2618 extensions[nextensions++] = succ[s]; 2619 } 2620 2621 /* while there exist possible extensions for the clique cover */ 2622 while ( nextensions > 0 ) 2623 { 2624 int bestindex = -1; 2625 2626 if ( considersolvals ) 2627 { 2628 SCIP_Real bestbigMval; 2629 SCIP_Real bigMval; 2630 2631 bestbigMval = -SCIPinfinity(scip); 2632 2633 /* search for the extension with the largest absolute value of its LP relaxation solution value */ 2634 for (s = 0; s < nextensions; ++s) 2635 { 2636 bigMval = nodeGetSolvalBinaryBigMSOS1(scip, conflictgraphroot, NULL, extensions[s]); 2637 if ( SCIPisFeasLT(scip, bestbigMval, bigMval) ) 2638 { 2639 bestbigMval = bigMval; 2640 bestindex = extensions[s]; 2641 } 2642 } 2643 } 2644 else 2645 bestindex = extensions[0]; 2646 2647 assert( bestindex != -1 ); 2648 2649 /* add bestindex to the clique cover */ 2650 clique[(*cliquesize)++] = bestindex; 2651 2652 /* compute new 'extensions' array */ 2653 nextensionsnew = 0; 2654 for (s = 0; s < nextensions; ++s) 2655 { 2656 if ( s != bestindex && isConnectedSOS1(NULL, conflictgraphlin, bestindex, extensions[s]) ) 2657 extensions[nextensionsnew++] = extensions[s]; 2658 } 2659 nextensions = nextensionsnew; 2660 } 2661 2662 /* free buffer array */ 2663 SCIPfreeBufferArray(scip, &extensions); 2664 } 2665 2666 /* mark covered indices */ 2667 for (s = 0; s < *cliquesize; ++s) 2668 { 2669 int ind; 2670 2671 ind = clique[s]; 2672 assert( 0 <= ind ); 2673 assert( ! coveredvars[ind] ); 2674 coveredvars[ind] = TRUE; 2675 } 2676 2677 return SCIP_OKAY; 2678 } 2679 2680 2681 /** try to tighten upper and lower bounds for variables */ 2682 static 2683 SCIP_RETCODE tightenVarsBoundsSOS1( 2684 SCIP* scip, /**< SCIP pointer */ 2685 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 2686 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 2687 SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \f$ implies a new lower/upper bound for \f$ x_j\f$) */ 2688 SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */ 2689 SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of conflict graph */ 2690 SCIP_VAR** totalvars, /**< problem and SOS1 vars */ 2691 int ntotalvars, /**< number of problem and SOS1 variables*/ 2692 int nsos1vars, /**< number of SOS1 variables */ 2693 int* nchgbds, /**< pointer to store number of changed bounds */ 2694 SCIP_Bool* implupdate, /**< pointer to store whether the implication graph has been updated in this function call */ 2695 SCIP_Bool* cutoff /**< pointer to store if current nodes LP is infeasible */ 2696 ) 2697 { 2698 SCIP_CONSHDLR* conshdlrlinear; 2699 SCIP_CONS** linearconss; 2700 int nlinearconss; 2701 2702 SCIP_Bool* implnodes = NULL; /* implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */ 2703 SCIP_Bool* coveredvars = NULL; /* coveredvars[i] = TRUE if variable with index i is covered by the clique cover */ 2704 int* varindincons = NULL; /* varindincons[i] = position of SOS1 index i in linear constraint (-1 if x_i is not involved in linear constraint) */ 2705 2706 SCIP_VAR** trafolinvars = NULL; /* variables of transformed linear constraints without (multi)aggregated variables */ 2707 int ntrafolinvars = 0; 2708 SCIP_Real* trafolinvals = NULL; 2709 SCIP_Real* trafoubs = NULL; 2710 SCIP_Real* trafolbs = NULL; 2711 SCIP_Real traforhs; 2712 SCIP_Real trafolhs; 2713 2714 SCIP_VAR** sos1linvars = NULL; /* variables that are not contained in linear constraint, but are in conflict with a variable from the linear constraint */ 2715 int nsos1linvars; 2716 int c; 2717 2718 assert( scip != NULL ); 2719 assert( conflictgraph != NULL ); 2720 assert( adjacencymatrix != NULL ); 2721 assert( nchgbds != NULL ); 2722 assert( cutoff != NULL ); 2723 2724 *cutoff = FALSE; 2725 *implupdate = FALSE; 2726 2727 /* get constraint handler data of linear constraints */ 2728 conshdlrlinear = SCIPfindConshdlr(scip, "linear"); 2729 if ( conshdlrlinear == NULL ) 2730 return SCIP_OKAY; 2731 2732 /* get linear constraints and number of linear constraints */ 2733 nlinearconss = SCIPconshdlrGetNConss(conshdlrlinear); 2734 linearconss = SCIPconshdlrGetConss(conshdlrlinear); 2735 2736 /* allocate buffer arrays */ 2737 SCIP_CALL( SCIPallocBufferArray(scip, &sos1linvars, nsos1vars) ); 2738 SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) ); 2739 SCIP_CALL( SCIPallocBufferArray(scip, &varindincons, nsos1vars) ); 2740 SCIP_CALL( SCIPallocBufferArray(scip, &coveredvars, ntotalvars) ); 2741 SCIP_CALL( SCIPallocBufferArray(scip, &trafoubs, ntotalvars) ); 2742 SCIP_CALL( SCIPallocBufferArray(scip, &trafolbs, ntotalvars) ); 2743 2744 /* for every linear constraint and every SOS1 variable */ 2745 for (c = 0; c < nlinearconss + nsos1vars && ! (*cutoff); ++c) 2746 { 2747 SCIP_DIGRAPH* conflictgraphlin; 2748 int** cliquecovers = NULL; /* clique covers of indices of variables in linear constraint */ 2749 int* cliquecoversizes = NULL; /* size of each cover */ 2750 SCIP_VAR* sosvar = NULL; 2751 SCIP_Real* cliquecovervals = NULL; 2752 SCIP_Real constant; 2753 int* varincover = NULL; /* varincover[i] = cover of SOS1 index i */ 2754 int ncliquecovers; 2755 int requiredsize; 2756 2757 int v; 2758 int i; 2759 int j; 2760 2761 /* get transformed linear constraints (without aggregated variables) */ 2762 if ( c < nlinearconss ) 2763 { 2764 SCIP_VAR** origlinvars; 2765 SCIP_Real* origlinvals; 2766 2767 /* get data of linear constraint */ 2768 ntrafolinvars = SCIPgetNVarsLinear(scip, linearconss[c]); 2769 if ( ntrafolinvars < 1 ) 2770 continue; 2771 2772 origlinvars = SCIPgetVarsLinear(scip, linearconss[c]); 2773 origlinvals = SCIPgetValsLinear(scip, linearconss[c]); 2774 assert( origlinvars != NULL ); 2775 assert( origlinvals != NULL ); 2776 2777 /* copy variables and coefficients of linear constraint */ 2778 SCIP_CALL( SCIPduplicateBufferArray(scip, &trafolinvars, origlinvars, ntrafolinvars) ); 2779 SCIP_CALL( SCIPduplicateBufferArray(scip, &trafolinvals, origlinvals, ntrafolinvars) ); 2780 2781 trafolhs = SCIPgetLhsLinear(scip, linearconss[c]); 2782 traforhs = SCIPgetRhsLinear(scip, linearconss[c]); 2783 } 2784 else 2785 { 2786 sosvar = SCIPnodeGetVarSOS1(conflictgraph, c - nlinearconss); 2787 2788 if ( SCIPvarGetStatus(sosvar) != SCIP_VARSTATUS_AGGREGATED 2789 && SCIPvarGetStatus(sosvar) != SCIP_VARSTATUS_MULTAGGR 2790 && SCIPvarGetStatus(sosvar) != SCIP_VARSTATUS_NEGATED ) 2791 continue; 2792 2793 /* store variable so it will be transformed to active variables below */ 2794 ntrafolinvars = 1; 2795 SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvars, ntrafolinvars + 1) ); 2796 SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvals, ntrafolinvars + 1) ); 2797 2798 trafolinvars[0] = sosvar; 2799 trafolinvals[0] = 1.0; 2800 2801 trafolhs = 0.0; 2802 traforhs = 0.0; 2803 } 2804 assert( ntrafolinvars >= 1 ); 2805 2806 /* transform linear constraint */ 2807 constant = 0.0; 2808 SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, ntrafolinvars, &constant, &requiredsize, TRUE) ); 2809 if( requiredsize > ntrafolinvars ) 2810 { 2811 SCIP_CALL( SCIPreallocBufferArray(scip, &trafolinvars, requiredsize + 1) ); 2812 SCIP_CALL( SCIPreallocBufferArray(scip, &trafolinvals, requiredsize + 1) ); 2813 2814 SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, requiredsize, &constant, &requiredsize, TRUE) ); 2815 assert( requiredsize <= ntrafolinvars ); 2816 } 2817 if( !SCIPisInfinity(scip, -trafolhs) ) 2818 trafolhs -= constant; 2819 if( !SCIPisInfinity(scip, traforhs) ) 2820 traforhs -= constant; 2821 2822 if ( ntrafolinvars == 0 ) 2823 { 2824 SCIPfreeBufferArray(scip, &trafolinvals); 2825 SCIPfreeBufferArray(scip, &trafolinvars); 2826 continue; 2827 } 2828 2829 /* possibly add sos1 variable to create aggregation/multiaggregation/negation equality */ 2830 if ( sosvar != NULL ) 2831 { 2832 trafolinvals[ntrafolinvars] = -1.0; 2833 trafolinvars[ntrafolinvars] = sosvar; 2834 ++ntrafolinvars; 2835 } 2836 2837 /* compute lower and upper bounds of each term a_i * x_i of transformed constraint */ 2838 for (v = 0; v < ntrafolinvars; ++v) 2839 { 2840 SCIP_Real lb; 2841 SCIP_Real ub; 2842 2843 lb = SCIPvarGetLbLocal(trafolinvars[v]); 2844 ub = SCIPvarGetUbLocal(trafolinvars[v]); 2845 2846 if ( trafolinvals[v] < 0.0 ) 2847 SCIPswapReals(&lb, &ub); 2848 2849 assert( ! SCIPisInfinity(scip, REALABS(trafolinvals[v])) ); 2850 2851 if ( SCIPisInfinity(scip, REALABS(lb)) || SCIPisInfinity(scip, REALABS(lb * trafolinvals[v])) ) 2852 trafolbs[v] = -SCIPinfinity(scip); 2853 else 2854 trafolbs[v] = lb * trafolinvals[v]; 2855 2856 if ( SCIPisInfinity(scip, REALABS(ub)) || SCIPisInfinity(scip, REALABS(ub * trafolinvals[v])) ) 2857 trafoubs[v] = SCIPinfinity(scip); 2858 else 2859 trafoubs[v] = ub * trafolinvals[v]; 2860 } 2861 2862 /* initialization: mark all the SOS1 variables as 'not a member of the linear constraint' */ 2863 for (v = 0; v < nsos1vars; ++v) 2864 varindincons[v] = -1; 2865 2866 /* save position of SOS1 variables in linear constraint */ 2867 for (v = 0; v < ntrafolinvars; ++v) 2868 { 2869 int node; 2870 2871 node = varGetNodeSOS1(conshdlrdata, trafolinvars[v]); 2872 2873 if ( node >= 0 ) 2874 varindincons[node] = v; 2875 } 2876 2877 /* create conflict graph of linear constraint */ 2878 SCIP_CALL( SCIPcreateDigraph(scip, &conflictgraphlin, ntrafolinvars) ); 2879 SCIP_CALL( genConflictgraphLinearCons(conshdlrdata, conflictgraphlin, conflictgraph, trafolinvars, ntrafolinvars, varindincons) ); 2880 2881 /* mark all the variables as 'not covered by some clique cover' */ 2882 for (i = 0; i < ntrafolinvars; ++i) 2883 coveredvars[i] = FALSE; 2884 2885 /* allocate buffer array */ 2886 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecovervals, ntrafolinvars) ); 2887 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecoversizes, ntrafolinvars) ); 2888 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecovers, ntrafolinvars) ); 2889 2890 /* compute distinct cliques that cover all the variables of the linear constraint */ 2891 ncliquecovers = 0; 2892 for (v = 0; v < ntrafolinvars; ++v) 2893 { 2894 /* if variable is not already covered by an already known clique cover */ 2895 if ( ! coveredvars[v] ) 2896 { 2897 SCIP_CALL( SCIPallocBufferArray(scip, &(cliquecovers[ncliquecovers]), ntrafolinvars) ); /*lint !e866*/ 2898 SCIP_CALL( computeVarsCoverSOS1(scip, conflictgraph, conflictgraphlin, trafolinvars, coveredvars, cliquecovers[ncliquecovers], &(cliquecoversizes[ncliquecovers]), v, FALSE) ); 2899 ++ncliquecovers; 2900 } 2901 } 2902 2903 /* free conflictgraph */ 2904 SCIPdigraphFree(&conflictgraphlin); 2905 2906 /* compute variables that are not contained in transformed linear constraint, but are in conflict with a variable from the transformed linear constraint */ 2907 nsos1linvars = 0; 2908 for (v = 0; v < ntrafolinvars; ++v) 2909 { 2910 int nodev; 2911 2912 nodev = varGetNodeSOS1(conshdlrdata, trafolinvars[v]); 2913 2914 /* if variable is an SOS1 variable */ 2915 if ( nodev >= 0 ) 2916 { 2917 int succnode; 2918 int nsucc; 2919 int* succ; 2920 int s; 2921 2922 succ = SCIPdigraphGetSuccessors(conflictgraph, nodev); 2923 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, nodev); 2924 2925 for (s = 0; s < nsucc; ++s) 2926 { 2927 succnode = succ[s]; 2928 2929 /* if variable is not a member of linear constraint and not already listed in the array sos1linvars */ 2930 if ( varindincons[succnode] == -1 ) 2931 { 2932 sos1linvars[nsos1linvars] = SCIPnodeGetVarSOS1(conflictgraph, succnode); 2933 varindincons[succnode] = -2; /* mark variable as listed in array sos1linvars */ 2934 ++nsos1linvars; 2935 } 2936 } 2937 } 2938 } 2939 2940 /* try to tighten lower bounds */ 2941 2942 /* sort each cliquecover array in ascending order of the lower bounds of a_i * x_i; fill vector varincover */ 2943 SCIP_CALL( SCIPallocBufferArray(scip, &varincover, ntrafolinvars) ); 2944 for (i = 0; i < ncliquecovers; ++i) 2945 { 2946 for (j = 0; j < cliquecoversizes[i]; ++j) 2947 { 2948 int ind = cliquecovers[i][j]; 2949 2950 varincover[ind] = i; 2951 cliquecovervals[j] = trafoubs[ind]; 2952 } 2953 SCIPsortDownRealInt(cliquecovervals, cliquecovers[i], cliquecoversizes[i]); 2954 } 2955 2956 /* for every variable in transformed constraint: try lower bound tightening */ 2957 for (v = 0; v < ntrafolinvars + nsos1linvars; ++v) 2958 { 2959 SCIP_Real newboundnonzero; /* new bound of a_v * x_v if we assume that x_v != 0 */ 2960 SCIP_Real newboundnores; /* new bound of a_v * x_v if we assume that x_v = 0 is possible */ 2961 SCIP_Real newbound; /* resulting new bound of x_v */ 2962 SCIP_VAR* var; 2963 SCIP_Real trafoubv; 2964 SCIP_Real linval; 2965 SCIP_Real ub; 2966 SCIP_Real lb; 2967 SCIP_Bool tightened; 2968 SCIP_Bool infeasible; 2969 SCIP_Bool inftynores = FALSE; 2970 SCIP_Bool update; 2971 int ninftynonzero = 0; 2972 int nodev; 2973 int w; 2974 2975 if ( v < ntrafolinvars ) 2976 { 2977 var = trafolinvars[v]; 2978 trafoubv = trafoubs[v]; 2979 } 2980 else 2981 { 2982 assert( v >= ntrafolinvars ); 2983 var = sos1linvars[v-ntrafolinvars];/*lint !e679*/ 2984 trafoubv = 0.0; 2985 } 2986 2987 ub = SCIPvarGetUbLocal(var); 2988 lb = SCIPvarGetLbLocal(var); 2989 2990 if ( SCIPisInfinity(scip, -trafolhs) || SCIPisZero(scip, ub - lb) ) 2991 continue; 2992 2993 newboundnonzero = trafolhs; 2994 newboundnores = trafolhs; 2995 nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */ 2996 assert( nodev < nsos1vars ); 2997 2998 /* determine incidence vector of implication variables */ 2999 for (w = 0; w < nsos1vars; ++w) 3000 implnodes[w] = FALSE; 3001 SCIP_CALL( getSOS1Implications(scip, conshdlrdata, totalvars, implgraph, implhash, implnodes, SCIPhashmapGetImageInt(implhash, var)) ); 3002 3003 /* compute new bound */ 3004 for (i = 0; i < ncliquecovers; ++i) 3005 { 3006 int indcliq; 3007 int nodecliq; 3008 3009 assert( cliquecoversizes[i] > 0 ); 3010 3011 indcliq = cliquecovers[i][0]; 3012 assert( 0 <= indcliq && indcliq < ntrafolinvars ); 3013 3014 /* determine maximum without index v (note that the array 'cliquecovers' is sorted by the values of trafoub in non-increasing order) */ 3015 if ( v != indcliq ) 3016 { 3017 if ( SCIPisInfinity(scip, trafoubs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnores - trafoubs[indcliq])) ) 3018 inftynores = TRUE; 3019 else 3020 newboundnores -= trafoubs[indcliq]; 3021 } 3022 else if ( cliquecoversizes[i] > 1 ) 3023 { 3024 assert( 0 <= cliquecovers[i][1] && cliquecovers[i][1] < ntrafolinvars ); 3025 if ( SCIPisInfinity(scip, trafoubs[cliquecovers[i][1]]) || SCIPisInfinity(scip, REALABS(newboundnores - trafoubs[cliquecovers[i][1]])) ) 3026 inftynores = TRUE; 3027 else 3028 newboundnores -= trafoubs[cliquecovers[i][1]];/*lint --e{679}*/ 3029 } 3030 3031 /* determine maximum without index v and if x_v is nonzero (note that the array 'cliquecovers' is sorted by the values of trafoub in non-increasing order) */ 3032 for (j = 0; j < cliquecoversizes[i]; ++j) 3033 { 3034 indcliq = cliquecovers[i][j]; 3035 assert( 0 <= indcliq && indcliq < ntrafolinvars ); 3036 3037 nodecliq = varGetNodeSOS1(conshdlrdata, trafolinvars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */ 3038 assert( nodecliq < nsos1vars ); 3039 3040 if ( v != indcliq ) 3041 { 3042 /* if nodev or nodecliq are not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0 */ 3043 if ( nodev < 0 || nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) ) 3044 { 3045 if ( SCIPisInfinity(scip, trafoubs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnonzero - trafoubs[indcliq])) ) 3046 ++ninftynonzero; 3047 else 3048 newboundnonzero -= trafoubs[indcliq]; 3049 break; /* break since we are only interested in the maximum upper bound among the variables in the clique cover; 3050 * the variables in the clique cover form an SOS1 constraint, thus only one of them can be nonzero */ 3051 } 3052 } 3053 } 3054 } 3055 assert( ninftynonzero == 0 || inftynores ); 3056 3057 /* if computed upper bound is not infinity and variable is contained in linear constraint */ 3058 if ( ninftynonzero == 0 && v < ntrafolinvars ) 3059 { 3060 linval = trafolinvals[v]; 3061 3062 if ( SCIPisFeasZero(scip, linval) ) 3063 continue; 3064 3065 /* compute new bound */ 3066 if ( SCIPisFeasPositive(scip, newboundnores) && ! inftynores ) 3067 newbound = newboundnonzero; 3068 else 3069 newbound = MIN(0, newboundnonzero); 3070 newbound /= linval; 3071 3072 if ( SCIPisInfinity(scip, newbound) ) 3073 continue; 3074 3075 /* check if new bound is tighter than the old one or problem is infeasible */ 3076 if ( SCIPisFeasPositive(scip, linval) && SCIPisFeasLT(scip, lb, newbound) ) 3077 { 3078 if ( SCIPisFeasLT(scip, ub, newbound) ) 3079 { 3080 *cutoff = TRUE; 3081 break; 3082 } 3083 3084 if ( SCIPvarIsIntegral(var) ) 3085 newbound = SCIPceil(scip, newbound); 3086 3087 SCIP_CALL( SCIPtightenVarLb(scip, var, newbound, FALSE, &infeasible, &tightened) ); 3088 assert( ! infeasible ); 3089 3090 if ( tightened ) 3091 { 3092 SCIPdebugMsg(scip, "changed lower bound of variable %s from %f to %f \n", SCIPvarGetName(var), lb, newbound); 3093 ++(*nchgbds); 3094 } 3095 } 3096 else if ( SCIPisFeasNegative(scip, linval) && SCIPisFeasGT(scip, ub, newbound) ) 3097 { 3098 /* if assumption a_i * x_i != 0 was not correct */ 3099 if ( SCIPisFeasGT(scip, SCIPvarGetLbLocal(var), newbound) ) 3100 { 3101 *cutoff = TRUE; 3102 break; 3103 } 3104 3105 if ( SCIPvarIsIntegral(var) ) 3106 newbound = SCIPfloor(scip, newbound); 3107 3108 SCIP_CALL( SCIPtightenVarUb(scip, var, newbound, FALSE, &infeasible, &tightened) ); 3109 assert( ! infeasible ); 3110 3111 if ( tightened ) 3112 { 3113 SCIPdebugMsg(scip, "changed upper bound of variable %s from %f to %f \n", SCIPvarGetName(var), ub, newbound); 3114 ++(*nchgbds); 3115 } 3116 } 3117 } 3118 3119 /* update implication graph if possible */ 3120 SCIP_CALL( updateImplicationGraphSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, implgraph, implhash, implnodes, totalvars, cliquecovers, cliquecoversizes, varincover, 3121 trafolinvars, trafolinvals, ntrafolinvars, trafoubs, var, trafoubv, newboundnonzero, ninftynonzero, TRUE, nchgbds, &update, &infeasible) ); 3122 if ( infeasible ) 3123 *cutoff = TRUE; 3124 else if ( update ) 3125 *implupdate = TRUE; 3126 } 3127 3128 if ( *cutoff == TRUE ) 3129 { 3130 /* free memory */ 3131 SCIPfreeBufferArrayNull(scip, &varincover); 3132 for (j = ncliquecovers-1; j >= 0; --j) 3133 SCIPfreeBufferArrayNull(scip, &cliquecovers[j]); 3134 SCIPfreeBufferArrayNull(scip, &cliquecovers); 3135 SCIPfreeBufferArrayNull(scip, &cliquecoversizes); 3136 SCIPfreeBufferArrayNull(scip, &cliquecovervals); 3137 SCIPfreeBufferArrayNull(scip, &trafolinvals); 3138 SCIPfreeBufferArrayNull(scip, &trafolinvars); 3139 break; 3140 } 3141 3142 /* try to tighten upper bounds */ 3143 3144 /* sort each cliquecover array in ascending order of the lower bounds of a_i * x_i; fill vector varincover */ 3145 for (i = 0; i < ncliquecovers; ++i) 3146 { 3147 for (j = 0; j < cliquecoversizes[i]; ++j) 3148 { 3149 int ind = cliquecovers[i][j]; 3150 3151 varincover[ind] = i; 3152 cliquecovervals[j] = trafolbs[ind]; 3153 } 3154 SCIPsortRealInt(cliquecovervals, cliquecovers[i], cliquecoversizes[i]); 3155 } 3156 3157 /* for every variable that is in transformed constraint or every variable that is in conflict with some variable from trans. cons.: 3158 try upper bound tightening */ 3159 for (v = 0; v < ntrafolinvars + nsos1linvars; ++v) 3160 { 3161 SCIP_Real newboundnonzero; /* new bound of a_v*x_v if we assume that x_v != 0 */ 3162 SCIP_Real newboundnores; /* new bound of a_v*x_v if there are no restrictions */ 3163 SCIP_Real newbound; /* resulting new bound of x_v */ 3164 SCIP_VAR* var; 3165 SCIP_Real linval; 3166 SCIP_Real trafolbv; 3167 SCIP_Real lb; 3168 SCIP_Real ub; 3169 SCIP_Bool tightened; 3170 SCIP_Bool infeasible; 3171 SCIP_Bool inftynores = FALSE; 3172 SCIP_Bool update; 3173 int ninftynonzero = 0; 3174 int nodev; 3175 int w; 3176 3177 if ( v < ntrafolinvars ) 3178 { 3179 var = trafolinvars[v]; 3180 trafolbv = trafolbs[v]; 3181 } 3182 else 3183 { 3184 assert( v-ntrafolinvars >= 0 ); 3185 var = sos1linvars[v-ntrafolinvars];/*lint !e679*/ 3186 trafolbv = 0.0; /* since variable is not a member of linear constraint */ 3187 } 3188 lb = SCIPvarGetLbLocal(var); 3189 ub = SCIPvarGetUbLocal(var); 3190 if ( SCIPisInfinity(scip, traforhs) || SCIPisEQ(scip, lb, ub) ) 3191 continue; 3192 3193 newboundnonzero = traforhs; 3194 newboundnores = traforhs; 3195 nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */ 3196 assert( nodev < nsos1vars ); 3197 3198 /* determine incidence vector of implication variables (i.e., which SOS1 variables are nonzero if x_v is nonzero) */ 3199 for (w = 0; w < nsos1vars; ++w) 3200 implnodes[w] = FALSE; 3201 SCIP_CALL( getSOS1Implications(scip, conshdlrdata, totalvars, implgraph, implhash, implnodes, SCIPhashmapGetImageInt(implhash, var)) ); 3202 3203 /* compute new bound */ 3204 for (i = 0; i < ncliquecovers; ++i) 3205 { 3206 int indcliq; 3207 int nodecliq; 3208 3209 assert( cliquecoversizes[i] > 0 ); 3210 3211 indcliq = cliquecovers[i][0]; 3212 assert( 0 <= indcliq && indcliq < ntrafolinvars ); 3213 3214 /* determine minimum without index v (note that the array 'cliquecovers' is sorted by the values of trafolb in increasing order) */ 3215 if ( v != indcliq ) 3216 { 3217 /* if bound would be infinity */ 3218 if ( SCIPisInfinity(scip, -trafolbs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnores - trafolbs[indcliq])) ) 3219 inftynores = TRUE; 3220 else 3221 newboundnores -= trafolbs[indcliq]; 3222 } 3223 else if ( cliquecoversizes[i] > 1 ) 3224 { 3225 assert( 0 <= cliquecovers[i][1] && cliquecovers[i][1] < ntrafolinvars ); 3226 if ( SCIPisInfinity(scip, -trafolbs[cliquecovers[i][1]]) || SCIPisInfinity(scip, REALABS(newboundnores - trafolbs[cliquecovers[i][1]])) ) 3227 inftynores = TRUE; 3228 else 3229 newboundnores -= trafolbs[cliquecovers[i][1]]; /*lint --e{679}*/ 3230 } 3231 3232 /* determine minimum without index v and if x_v is nonzero (note that the array 'cliquecovers' is sorted by the values of trafolb in increasing order) */ 3233 for (j = 0; j < cliquecoversizes[i]; ++j) 3234 { 3235 indcliq = cliquecovers[i][j]; 3236 assert( 0 <= indcliq && indcliq < ntrafolinvars ); 3237 3238 nodecliq = varGetNodeSOS1(conshdlrdata, trafolinvars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */ 3239 assert( nodecliq < nsos1vars ); 3240 3241 if ( v != indcliq ) 3242 { 3243 /* if nodev or nodecliq are not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0 */ 3244 if ( nodev < 0 || nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) ) 3245 { 3246 /* if bound would be infinity */ 3247 if ( SCIPisInfinity(scip, -trafolbs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnonzero - trafolbs[indcliq])) ) 3248 ++ninftynonzero; 3249 else 3250 newboundnonzero -= trafolbs[indcliq]; 3251 break; /* break since we are only interested in the minimum lower bound among the variables in the clique cover; 3252 * the variables in the clique cover form an SOS1 constraint, thus only one of them can be nonzero */ 3253 } 3254 } 3255 } 3256 } 3257 assert( ninftynonzero == 0 || inftynores ); 3258 3259 /* if computed bound is not infinity and variable is contained in linear constraint */ 3260 if ( ninftynonzero == 0 && v < ntrafolinvars ) 3261 { 3262 linval = trafolinvals[v]; 3263 3264 if ( SCIPisFeasZero(scip, linval) ) 3265 continue; 3266 3267 /* compute new bound */ 3268 if ( SCIPisFeasNegative(scip, newboundnores) && ! inftynores ) 3269 newbound = newboundnonzero; 3270 else 3271 newbound = MAX(0, newboundnonzero); 3272 newbound /= linval; 3273 3274 if ( SCIPisInfinity(scip, newbound) ) 3275 continue; 3276 3277 /* check if new bound is tighter than the old one or problem is infeasible */ 3278 if ( SCIPisFeasPositive(scip, linval) && SCIPisFeasGT(scip, ub, newbound) ) 3279 { 3280 /* if new upper bound is smaller than the lower bound, we are infeasible */ 3281 if ( SCIPisFeasGT(scip, lb, newbound) ) 3282 { 3283 *cutoff = TRUE; 3284 break; 3285 } 3286 3287 if ( SCIPvarIsIntegral(var) ) 3288 newbound = SCIPfloor(scip, newbound); 3289 3290 SCIP_CALL( SCIPtightenVarUb(scip, var, newbound, FALSE, &infeasible, &tightened) ); 3291 assert( ! infeasible ); 3292 3293 if ( tightened ) 3294 { 3295 SCIPdebugMsg(scip, "changed upper bound of variable %s from %f to %f \n", SCIPvarGetName(var), ub, newbound); 3296 ++(*nchgbds); 3297 } 3298 } 3299 else if ( SCIPisFeasNegative(scip, linval) && SCIPisFeasLT(scip, lb, newbound) ) 3300 { 3301 /* if assumption a_i * x_i != 0 was not correct */ 3302 if ( SCIPisFeasLT(scip, ub, newbound) ) 3303 { 3304 *cutoff = TRUE; 3305 break; 3306 } 3307 3308 if ( SCIPvarIsIntegral(var) ) 3309 newbound = SCIPceil(scip, newbound); 3310 3311 SCIP_CALL( SCIPtightenVarLb(scip, var, newbound, FALSE, &infeasible, &tightened) ); 3312 assert( ! infeasible ); 3313 3314 if ( tightened ) 3315 { 3316 SCIPdebugMsg(scip, "changed lower bound of variable %s from %f to %f \n", SCIPvarGetName(var), lb, newbound); 3317 ++(*nchgbds); 3318 } 3319 } 3320 } 3321 3322 /* update implication graph if possible */ 3323 SCIP_CALL( updateImplicationGraphSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, implgraph, implhash, implnodes, totalvars, cliquecovers, cliquecoversizes, varincover, 3324 trafolinvars, trafolinvals, ntrafolinvars, trafolbs, var, trafolbv, newboundnonzero, ninftynonzero, FALSE, nchgbds, &update, &infeasible) ); 3325 if ( infeasible ) 3326 *cutoff = TRUE; 3327 else if ( update ) 3328 *implupdate = TRUE; 3329 } 3330 3331 /* free memory */ 3332 SCIPfreeBufferArrayNull(scip, &varincover); 3333 for (j = ncliquecovers-1; j >= 0; --j) 3334 SCIPfreeBufferArrayNull(scip, &cliquecovers[j]); 3335 SCIPfreeBufferArrayNull(scip, &cliquecovers); 3336 SCIPfreeBufferArrayNull(scip, &cliquecoversizes); 3337 SCIPfreeBufferArrayNull(scip, &cliquecovervals); 3338 SCIPfreeBufferArrayNull(scip, &trafolinvals); 3339 SCIPfreeBufferArrayNull(scip, &trafolinvars); 3340 3341 if ( *cutoff == TRUE ) 3342 break; 3343 } /* end for every linear constraint */ 3344 3345 /* free buffer arrays */ 3346 SCIPfreeBufferArrayNull(scip, &trafolbs); 3347 SCIPfreeBufferArrayNull(scip, &trafoubs); 3348 SCIPfreeBufferArrayNull(scip, &coveredvars); 3349 SCIPfreeBufferArrayNull(scip, &varindincons); 3350 SCIPfreeBufferArrayNull(scip, &implnodes); 3351 SCIPfreeBufferArrayNull(scip, &sos1linvars); 3352 3353 return SCIP_OKAY; 3354 } 3355 3356 3357 /** perform one presolving round for variables 3358 * 3359 * We perform the following presolving steps: 3360 * - Tighten the bounds of the variables 3361 * - Update conflict graph based on bound implications of the variables 3362 */ 3363 static 3364 SCIP_RETCODE presolRoundVarsSOS1( 3365 SCIP* scip, /**< SCIP pointer */ 3366 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 3367 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 3368 SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of conflict graph */ 3369 int nsos1vars, /**< number of SOS1 variables */ 3370 int* nfixedvars, /**< pointer to store number of fixed variables */ 3371 int* nchgbds, /**< pointer to store number of changed bounds */ 3372 int* naddconss, /**< pointer to store number of addded constraints */ 3373 SCIP_RESULT* result /**< result */ 3374 ) 3375 { 3376 SCIP_DIGRAPH* implgraph; 3377 SCIP_HASHMAP* implhash; 3378 3379 SCIP_Bool cutoff = FALSE; 3380 SCIP_Bool updateconfl; 3381 3382 SCIP_VAR** totalvars; 3383 SCIP_VAR** probvars; 3384 int ntotalvars = 0; 3385 int nprobvars; 3386 int i; 3387 int j; 3388 3389 /* determine totalvars (union of SOS1 and problem variables) */ 3390 probvars = SCIPgetVars(scip); 3391 nprobvars = SCIPgetNVars(scip); 3392 SCIP_CALL( SCIPhashmapCreate(&implhash, SCIPblkmem(scip), nsos1vars + nprobvars) ); 3393 SCIP_CALL( SCIPallocBufferArray(scip, &totalvars, nsos1vars + nprobvars) ); 3394 3395 for (i = 0; i < nsos1vars; ++i) 3396 { 3397 SCIP_VAR* var; 3398 var = SCIPnodeGetVarSOS1(conflictgraph, i); 3399 3400 /* insert node number to hash map */ 3401 assert( ! SCIPhashmapExists(implhash, var) ); 3402 SCIP_CALL( SCIPhashmapInsertInt(implhash, var, ntotalvars) ); 3403 assert( ntotalvars == SCIPhashmapGetImageInt(implhash, var) ); 3404 totalvars[ntotalvars++] = var; 3405 } 3406 3407 for (i = 0; i < nprobvars; ++i) 3408 { 3409 SCIP_VAR* var; 3410 var = probvars[i]; 3411 3412 /* insert node number to hash map if not existent */ 3413 if ( ! SCIPhashmapExists(implhash, var) ) 3414 { 3415 SCIP_CALL( SCIPhashmapInsertInt(implhash, var, ntotalvars) ); 3416 assert( ntotalvars == SCIPhashmapGetImageInt(implhash, var) ); 3417 totalvars[ntotalvars++] = var; 3418 } 3419 } 3420 3421 /* create implication graph */ 3422 SCIP_CALL( SCIPcreateDigraph(scip, &implgraph, ntotalvars) ); 3423 3424 /* try to tighten the lower and upper bounds of the variables */ 3425 updateconfl = FALSE; 3426 for (j = 0; (j < conshdlrdata->maxtightenbds || conshdlrdata->maxtightenbds == -1 ) && ! cutoff; ++j) 3427 { 3428 SCIP_Bool implupdate; 3429 int nchgbdssave; 3430 3431 nchgbdssave = *nchgbds; 3432 3433 assert( ntotalvars > 0 ); 3434 SCIP_CALL( tightenVarsBoundsSOS1(scip, conshdlrdata, conflictgraph, implgraph, implhash, adjacencymatrix, totalvars, ntotalvars, nsos1vars, nchgbds, &implupdate, &cutoff) ); 3435 if ( *nchgbds > nchgbdssave ) 3436 { 3437 *result = SCIP_SUCCESS; 3438 if ( implupdate ) 3439 updateconfl = TRUE; 3440 } 3441 else if ( implupdate ) 3442 updateconfl = TRUE; 3443 else 3444 break; 3445 } 3446 3447 /* perform implication graph analysis */ 3448 if ( updateconfl && conshdlrdata->perfimplanalysis && ! cutoff ) 3449 { 3450 SCIP_Real* implubs; 3451 SCIP_Real* impllbs; 3452 SCIP_Bool* implnodes; 3453 SCIP_Bool infeasible; 3454 SCIP_Bool fixed; 3455 int naddconsssave; 3456 int probingdepth; 3457 3458 /* allocate buffer arrays */ 3459 SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) ); 3460 SCIP_CALL( SCIPallocBufferArray(scip, &impllbs, ntotalvars) ); 3461 SCIP_CALL( SCIPallocBufferArray(scip, &implubs, ntotalvars) ); 3462 3463 naddconsssave = *naddconss; 3464 for (i = 0; i < nsos1vars; ++i) 3465 { 3466 /* initialize data for implication graph analysis */ 3467 infeasible = FALSE; 3468 probingdepth = 0; 3469 for (j = 0; j < nsos1vars; ++j) 3470 implnodes[j] = FALSE; 3471 for (j = 0; j < ntotalvars; ++j) 3472 { 3473 impllbs[j] = SCIPvarGetLbLocal(totalvars[j]); 3474 implubs[j] = SCIPvarGetUbLocal(totalvars[j]); 3475 } 3476 3477 /* try to update the conflict graph based on the information of the implication graph */ 3478 SCIP_CALL( performImplicationGraphAnalysis(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, adjacencymatrix, i, i, impllbs, implubs, implnodes, naddconss, &probingdepth, &infeasible) ); 3479 3480 /* if the subproblem turned out to be infeasible then fix variable to zero */ 3481 if ( infeasible ) 3482 { 3483 SCIP_CALL( SCIPfixVar(scip, totalvars[i], 0.0, &infeasible, &fixed) ); 3484 3485 if ( fixed ) 3486 { 3487 SCIPdebugMsg(scip, "fixed variable %s with lower bound %f and upper bound %f to zero\n", 3488 SCIPvarGetName(totalvars[i]), SCIPvarGetLbLocal(totalvars[i]), SCIPvarGetUbLocal(totalvars[i])); 3489 ++(*nfixedvars); 3490 } 3491 3492 if ( infeasible ) 3493 cutoff = TRUE; 3494 } 3495 } 3496 3497 if ( *naddconss > naddconsssave ) 3498 *result = SCIP_SUCCESS; 3499 3500 /* free buffer arrays */ 3501 SCIPfreeBufferArrayNull(scip, &implubs); 3502 SCIPfreeBufferArrayNull(scip, &impllbs); 3503 SCIPfreeBufferArrayNull(scip, &implnodes); 3504 } 3505 3506 /* if an infeasibility has been detected */ 3507 if ( cutoff ) 3508 { 3509 SCIPdebugMsg(scip, "cutoff \n"); 3510 *result = SCIP_CUTOFF; 3511 } 3512 3513 /* free memory */; 3514 for (j = ntotalvars-1; j >= 0; --j) 3515 { 3516 SCIP_SUCCDATA** succdatas; 3517 int nsucc; 3518 int s; 3519 3520 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, j); 3521 nsucc = SCIPdigraphGetNSuccessors(implgraph, j); 3522 3523 for (s = nsucc-1; s >= 0; --s) 3524 SCIPfreeBlockMemory(scip, &succdatas[s]);/*lint !e866*/ 3525 } 3526 SCIPdigraphFree(&implgraph); 3527 SCIPfreeBufferArrayNull(scip, &totalvars); 3528 SCIPhashmapFree(&implhash); 3529 3530 return SCIP_OKAY; 3531 } 3532 3533 3534 /* ----------------------------- propagation -------------------------------------*/ 3535 3536 /** propagate variables of SOS1 constraint */ 3537 static 3538 SCIP_RETCODE propConsSOS1( 3539 SCIP* scip, /**< SCIP pointer */ 3540 SCIP_CONS* cons, /**< constraint */ 3541 SCIP_CONSDATA* consdata, /**< constraint data */ 3542 SCIP_Bool* cutoff, /**< whether a cutoff happened */ 3543 int* ngen /**< number of domain changes */ 3544 ) 3545 { 3546 assert( scip != NULL ); 3547 assert( cons != NULL ); 3548 assert( consdata != NULL ); 3549 assert( cutoff != NULL ); 3550 assert( ngen != NULL ); 3551 3552 *cutoff = FALSE; 3553 3554 /* if more than one variable is fixed to be nonzero */ 3555 if ( consdata->nfixednonzeros > 1 ) 3556 { 3557 SCIPdebugMsg(scip, "the node is infeasible, more than 1 variable is fixed to be nonzero.\n"); 3558 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 3559 *cutoff = TRUE; 3560 return SCIP_OKAY; 3561 } 3562 3563 /* if exactly one variable is fixed to be nonzero */ 3564 if ( consdata->nfixednonzeros == 1 ) 3565 { 3566 SCIP_VAR** vars; 3567 SCIP_Bool infeasible; 3568 SCIP_Bool tightened; 3569 SCIP_Bool success; 3570 SCIP_Bool allVarFixed; 3571 int firstFixedNonzero; 3572 int nvars; 3573 int j; 3574 3575 firstFixedNonzero = -1; 3576 nvars = consdata->nvars; 3577 vars = consdata->vars; 3578 assert( vars != NULL ); 3579 3580 /* search nonzero variable - is needed for propinfo */ 3581 for (j = 0; j < nvars; ++j) 3582 { 3583 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(vars[j])) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(vars[j])) ) 3584 { 3585 firstFixedNonzero = j; 3586 break; 3587 } 3588 } 3589 assert( firstFixedNonzero >= 0 ); 3590 3591 SCIPdebugMsg(scip, "variable <%s> is fixed nonzero, fixing other variables to 0.\n", SCIPvarGetName(vars[firstFixedNonzero])); 3592 3593 /* fix variables before firstFixedNonzero to 0 */ 3594 allVarFixed = TRUE; 3595 for (j = 0; j < firstFixedNonzero; ++j) 3596 { 3597 /* fix variable */ 3598 SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) ); 3599 assert( ! infeasible ); 3600 allVarFixed = allVarFixed && success; 3601 if ( tightened ) 3602 ++(*ngen); 3603 } 3604 3605 /* fix variables after firstFixedNonzero to 0 */ 3606 for (j = firstFixedNonzero+1; j < nvars; ++j) 3607 { 3608 /* fix variable */ 3609 SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) ); 3610 assert( ! infeasible ); /* there should be no variables after firstFixedNonzero that are fixed to be nonzero */ 3611 allVarFixed = allVarFixed && success; 3612 if ( tightened ) 3613 ++(*ngen); 3614 } 3615 3616 /* reset constraint age counter */ 3617 if ( *ngen > 0 ) 3618 { 3619 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 3620 } 3621 3622 /* delete constraint locally */ 3623 if ( allVarFixed ) 3624 { 3625 assert( !SCIPconsIsModifiable(cons) ); 3626 SCIP_CALL( SCIPdelConsLocal(scip, cons) ); 3627 } 3628 } 3629 3630 return SCIP_OKAY; 3631 } 3632 3633 3634 /** propagate a variable that is known to be nonzero */ 3635 static 3636 SCIP_RETCODE propVariableNonzero( 3637 SCIP* scip, /**< SCIP pointer */ 3638 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 3639 SCIP_DIGRAPH* implgraph, /**< implication graph */ 3640 SCIP_CONS* cons, /**< some arbitrary SOS1 constraint */ 3641 int node, /**< conflict graph node of variable that is known to be nonzero */ 3642 SCIP_Bool implprop, /**< whether implication graph propagation shall be applied */ 3643 SCIP_Bool* cutoff, /**< whether a cutoff happened */ 3644 int* ngen /**< number of domain changes */ 3645 ) 3646 { 3647 int inferinfo; 3648 int* succ; 3649 int nsucc; 3650 int s; 3651 3652 assert( scip != NULL ); 3653 assert( conflictgraph != NULL ); 3654 assert( cutoff != NULL ); 3655 assert( ngen != NULL ); 3656 assert( node >= 0 ); 3657 3658 *cutoff = FALSE; 3659 inferinfo = -node - 1; 3660 3661 /* by assumption zero is outside the domain of variable */ 3662 assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(SCIPnodeGetVarSOS1(conflictgraph, node))) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(SCIPnodeGetVarSOS1(conflictgraph, node))) ); 3663 3664 /* apply conflict graph propagation (fix all neighbors in the conflict graph to zero) */ 3665 succ = SCIPdigraphGetSuccessors(conflictgraph, node); 3666 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node); 3667 for (s = 0; s < nsucc; ++s) 3668 { 3669 SCIP_VAR* succvar; 3670 SCIP_Real lb; 3671 SCIP_Real ub; 3672 3673 succvar = SCIPnodeGetVarSOS1(conflictgraph, succ[s]); 3674 lb = SCIPvarGetLbLocal(succvar); 3675 ub = SCIPvarGetUbLocal(succvar); 3676 3677 if ( ! SCIPisFeasZero(scip, lb) || ! SCIPisFeasZero(scip, ub) ) 3678 { 3679 SCIP_Bool infeasible; 3680 SCIP_Bool tightened; 3681 SCIP_Bool success; 3682 3683 /* fix variable if it is not multi-aggregated */ 3684 SCIP_CALL( inferVariableZero(scip, succvar, cons, inferinfo, &infeasible, &tightened, &success) ); 3685 3686 if ( infeasible ) 3687 { 3688 /* variable cannot be nonzero */ 3689 *cutoff = TRUE; 3690 return SCIP_OKAY; 3691 } 3692 if ( tightened ) 3693 ++(*ngen); 3694 assert( success || SCIPvarGetStatus(succvar) == SCIP_VARSTATUS_MULTAGGR ); 3695 } 3696 } 3697 3698 /* apply implication graph propagation */ 3699 if ( implprop && implgraph != NULL ) 3700 { 3701 SCIP_SUCCDATA** succdatas; 3702 3703 #ifndef NDEBUG 3704 SCIP_NODEDATA* nodedbgdata; 3705 nodedbgdata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, node); 3706 assert( SCIPvarCompare(nodedbgdata->var, SCIPnodeGetVarSOS1(conflictgraph, node)) == 0 ); 3707 #endif 3708 3709 /* get successor datas */ 3710 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, node); 3711 3712 if ( succdatas != NULL ) 3713 { 3714 succ = SCIPdigraphGetSuccessors(implgraph, node); 3715 nsucc = SCIPdigraphGetNSuccessors(implgraph, node); 3716 for (s = 0; s < nsucc; ++s) 3717 { 3718 SCIP_SUCCDATA* succdata; 3719 SCIP_NODEDATA* nodedata; 3720 SCIP_VAR* var; 3721 3722 nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, succ[s]); 3723 assert( nodedata != NULL ); 3724 succdata = succdatas[s]; 3725 assert( succdata != NULL ); 3726 var = nodedata->var; 3727 assert( var != NULL ); 3728 3729 /* tighten variable if it is not multi-aggregated */ 3730 if ( SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR ) 3731 { 3732 /* check for lower bound implication */ 3733 if ( SCIPisFeasLT(scip, SCIPvarGetLbLocal(var), succdata->lbimpl) ) 3734 { 3735 SCIP_Bool infeasible; 3736 SCIP_Bool tightened; 3737 3738 SCIP_CALL( SCIPinferVarLbCons(scip, var, succdata->lbimpl, cons, inferinfo, FALSE, &infeasible, &tightened) ); 3739 if ( infeasible ) 3740 { 3741 *cutoff = TRUE; 3742 return SCIP_OKAY; 3743 } 3744 if ( tightened ) 3745 ++(*ngen); 3746 } 3747 3748 /* check for upper bound implication */ 3749 if ( SCIPisFeasGT(scip, SCIPvarGetUbLocal(var), succdata->ubimpl) ) 3750 { 3751 SCIP_Bool infeasible; 3752 SCIP_Bool tightened; 3753 3754 SCIP_CALL( SCIPinferVarUbCons(scip, var, succdata->ubimpl, cons, inferinfo, FALSE, &infeasible, &tightened) ); 3755 if ( infeasible ) 3756 { 3757 *cutoff = TRUE; 3758 return SCIP_OKAY; 3759 } 3760 if ( tightened ) 3761 ++(*ngen); 3762 } 3763 } 3764 } 3765 } 3766 } 3767 3768 return SCIP_OKAY; 3769 } 3770 3771 3772 /** initialize implication graph 3773 * 3774 * @p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$ 3775 * 3776 * @note By construction the implication graph is globally valid. 3777 */ 3778 static 3779 SCIP_RETCODE initImplGraphSOS1( 3780 SCIP* scip, /**< SCIP pointer */ 3781 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 3782 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 3783 int nsos1vars, /**< number of SOS1 variables */ 3784 int maxrounds, /**< maximal number of propagation rounds for generating implications */ 3785 int* nchgbds, /**< pointer to store number of bound changes */ 3786 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff occurred */ 3787 SCIP_Bool* success /**< whether initialization was successful */ 3788 ) 3789 { 3790 SCIP_HASHMAP* implhash = NULL; 3791 SCIP_Bool** adjacencymatrix = NULL; 3792 SCIP_Bool* implnodes = NULL; 3793 SCIP_VAR** implvars = NULL; 3794 SCIP_VAR** probvars; 3795 int nimplnodes; 3796 int nprobvars; 3797 int i; 3798 int j; 3799 3800 assert( scip != NULL ); 3801 assert( conshdlrdata != NULL ); 3802 assert( conflictgraph != NULL ); 3803 assert( conshdlrdata->implgraph == NULL ); 3804 assert( conshdlrdata->nimplnodes == 0 ); 3805 assert( cutoff != NULL ); 3806 assert( nchgbds != NULL ); 3807 3808 *nchgbds = 0; 3809 *cutoff = FALSE; 3810 3811 /* we do not create the adjacency matrix of the conflict graph if the number of SOS1 variables is larger than a predefined value */ 3812 if ( conshdlrdata->maxsosadjacency != -1 && nsos1vars > conshdlrdata->maxsosadjacency ) 3813 { 3814 *success = FALSE; 3815 SCIPdebugMsg(scip, "Implication graph was not created since number of SOS1 variables (%d) is larger than %d.\n", nsos1vars, conshdlrdata->maxsosadjacency); 3816 3817 return SCIP_OKAY; 3818 } 3819 *success = TRUE; 3820 3821 /* only add globally valid implications to implication graph */ 3822 assert ( SCIPgetDepth(scip) == 0 ); 3823 3824 probvars = SCIPgetVars(scip); 3825 nprobvars = SCIPgetNVars(scip); 3826 nimplnodes = 0; 3827 3828 /* create implication graph */ 3829 SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->implgraph, nsos1vars + nprobvars) ); 3830 3831 /* create hashmap */ 3832 SCIP_CALL( SCIPhashmapCreate(&implhash, SCIPblkmem(scip), nsos1vars + nprobvars) ); 3833 3834 /* determine implvars (union of SOS1 and problem variables) 3835 * Note: For separation of implied bound cuts it is important that SOS1 variables are enumerated first 3836 */ 3837 SCIP_CALL( SCIPallocBufferArray(scip, &implvars, nsos1vars + nprobvars) ); 3838 for (i = 0; i < nsos1vars; ++i) 3839 { 3840 SCIP_VAR* var; 3841 var = SCIPnodeGetVarSOS1(conflictgraph, i); 3842 3843 /* insert node number to hash map */ 3844 assert( ! SCIPhashmapExists(implhash, var) ); 3845 SCIP_CALL( SCIPhashmapInsertInt(implhash, var, nimplnodes) ); 3846 assert( nimplnodes == SCIPhashmapGetImageInt(implhash, var) ); 3847 implvars[nimplnodes++] = var; 3848 } 3849 3850 for (i = 0; i < nprobvars; ++i) 3851 { 3852 SCIP_VAR* var; 3853 var = probvars[i]; 3854 3855 /* insert node number to hash map if not existent */ 3856 if ( ! SCIPhashmapExists(implhash, var) ) 3857 { 3858 SCIP_CALL( SCIPhashmapInsertInt(implhash, var, nimplnodes) ); 3859 assert( nimplnodes == SCIPhashmapGetImageInt(implhash, var) ); 3860 implvars[nimplnodes++] = var; 3861 } 3862 } 3863 conshdlrdata->nimplnodes = nimplnodes; 3864 3865 /* add variables to nodes of implication graph */ 3866 for (i = 0; i < nimplnodes; ++i) 3867 { 3868 SCIP_NODEDATA* nodedata = NULL; 3869 3870 /* create node data */ 3871 SCIP_CALL( SCIPallocBlockMemory(scip, &nodedata) ); 3872 nodedata->var = implvars[i]; 3873 3874 /* set node data */ 3875 SCIPdigraphSetNodeData(conshdlrdata->implgraph, (void*) nodedata, i); 3876 } 3877 3878 /* allocate buffer arrays */ 3879 SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) ); 3880 SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix, nsos1vars) ); 3881 3882 for (i = 0; i < nsos1vars; ++i) 3883 SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix[i], i+1) ); /*lint !e866*/ 3884 3885 /* create adjacency matrix */ 3886 for (i = 0; i < nsos1vars; ++i) 3887 { 3888 for (j = 0; j < i+1; ++j) 3889 adjacencymatrix[i][j] = 0; 3890 } 3891 3892 for (i = 0; i < nsos1vars; ++i) 3893 { 3894 int* succ; 3895 int nsucc; 3896 succ = SCIPdigraphGetSuccessors(conflictgraph, i); 3897 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i); 3898 3899 for (j = 0; j < nsucc; ++j) 3900 { 3901 if ( i > succ[j] ) 3902 adjacencymatrix[i][succ[j]] = 1; 3903 } 3904 } 3905 3906 assert( SCIPgetDepth(scip) == 0 ); 3907 3908 /* compute SOS1 implications from linear constraints and tighten bounds of variables */ 3909 for (j = 0; (j < maxrounds || maxrounds == -1 ); ++j) 3910 { 3911 SCIP_Bool implupdate; 3912 int nchgbdssave; 3913 3914 nchgbdssave = *nchgbds; 3915 3916 assert( nimplnodes > 0 ); 3917 SCIP_CALL( tightenVarsBoundsSOS1(scip, conshdlrdata, conflictgraph, conshdlrdata->implgraph, implhash, adjacencymatrix, implvars, nimplnodes, nsos1vars, nchgbds, &implupdate, cutoff) ); 3918 if ( *cutoff || ( ! implupdate && ! ( *nchgbds > nchgbdssave ) ) ) 3919 break; 3920 } 3921 3922 /* free memory */ 3923 for (i = nsos1vars-1; i >= 0; --i) 3924 SCIPfreeBufferArrayNull(scip, &adjacencymatrix[i]); 3925 SCIPfreeBufferArrayNull(scip, &adjacencymatrix); 3926 SCIPfreeBufferArrayNull(scip, &implnodes); 3927 SCIPfreeBufferArrayNull(scip, &implvars); 3928 SCIPhashmapFree(&implhash); 3929 3930 #ifdef SCIP_DEBUG 3931 /* evaluate results */ 3932 if ( cutoff ) 3933 { 3934 SCIPdebugMsg(scip, "cutoff \n"); 3935 } 3936 else if ( *nchgbds > 0 ) 3937 { 3938 SCIPdebugMsg(scip, "found %d bound changes\n", *nchgbds); 3939 } 3940 #endif 3941 3942 assert( conshdlrdata->implgraph != NULL ); 3943 3944 return SCIP_OKAY; 3945 } 3946 3947 3948 /** deinitialize implication graph */ 3949 static 3950 SCIP_RETCODE freeImplGraphSOS1( 3951 SCIP* scip, /**< SCIP pointer */ 3952 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */ 3953 ) 3954 { 3955 int j; 3956 3957 assert( scip != NULL ); 3958 assert( conshdlrdata != NULL ); 3959 3960 /* free whole memory of implication graph */ 3961 if ( conshdlrdata->implgraph == NULL ) 3962 { 3963 assert( conshdlrdata->nimplnodes == 0 ); 3964 return SCIP_OKAY; 3965 } 3966 3967 /* free arc data */ 3968 for (j = conshdlrdata->nimplnodes-1; j >= 0; --j) 3969 { 3970 SCIP_SUCCDATA** succdatas; 3971 int nsucc; 3972 int s; 3973 3974 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(conshdlrdata->implgraph, j); 3975 nsucc = SCIPdigraphGetNSuccessors(conshdlrdata->implgraph, j); 3976 3977 for (s = nsucc-1; s >= 0; --s) 3978 { 3979 assert( succdatas[s] != NULL ); 3980 SCIPfreeBlockMemory(scip, &succdatas[s]);/*lint !e866*/ 3981 } 3982 } 3983 3984 /* free node data */ 3985 for (j = conshdlrdata->nimplnodes-1; j >= 0; --j) 3986 { 3987 SCIP_NODEDATA* nodedata; 3988 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->implgraph, j); 3989 assert( nodedata != NULL ); 3990 SCIPfreeBlockMemory(scip, &nodedata); 3991 SCIPdigraphSetNodeData(conshdlrdata->implgraph, NULL, j); 3992 } 3993 3994 /* free implication graph */ 3995 SCIPdigraphFree(&conshdlrdata->implgraph); 3996 conshdlrdata->nimplnodes = 0; 3997 3998 return SCIP_OKAY; 3999 } 4000 4001 4002 /* ----------------------------- branching -------------------------------------*/ 4003 4004 /** get the vertices whose neighbor set covers a subset of the neighbor set of a given other vertex. 4005 * 4006 * This function can be used to compute sets of variables to branch on. 4007 */ 4008 static 4009 SCIP_RETCODE getCoverVertices( 4010 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 4011 SCIP_Bool* verticesarefixed, /**< array that indicates which variables are currently fixed to zero */ 4012 int vertex, /**< vertex (-1 if not needed) */ 4013 int* neightocover, /**< neighbors of given vertex to be covered (or NULL if all neighbors shall be covered) */ 4014 int nneightocover, /**< number of entries of neightocover (or 0 if all neighbors shall be covered )*/ 4015 int* coververtices, /**< array to store the vertices whose neighbor set covers the neighbor set of the given vertex */ 4016 int* ncoververtices /**< pointer to store size of coververtices */ 4017 ) 4018 { 4019 int* succ1; 4020 int nsucc1; 4021 int s; 4022 4023 assert( conflictgraph != NULL ); 4024 assert( verticesarefixed != NULL ); 4025 assert( coververtices != NULL ); 4026 assert( ncoververtices != NULL ); 4027 4028 *ncoververtices = 0; 4029 4030 /* if all the neighbors shall be covered */ 4031 if ( neightocover == NULL ) 4032 { 4033 assert( nneightocover == 0 ); 4034 nsucc1 = SCIPdigraphGetNSuccessors(conflictgraph, vertex); 4035 succ1 = SCIPdigraphGetSuccessors(conflictgraph, vertex); 4036 } 4037 else 4038 { 4039 nsucc1 = nneightocover; 4040 succ1 = neightocover; 4041 } 4042 4043 /* determine all the successors of the first unfixed successor */ 4044 for (s = 0; s < nsucc1; ++s) 4045 { 4046 int succvertex1 = succ1[s]; 4047 4048 if ( ! verticesarefixed[succvertex1] ) 4049 { 4050 int succvertex2; 4051 int* succ2; 4052 int nsucc2; 4053 int j; 4054 4055 nsucc2 = SCIPdigraphGetNSuccessors(conflictgraph, succvertex1); 4056 succ2 = SCIPdigraphGetSuccessors(conflictgraph, succvertex1); 4057 4058 /* for the first unfixed vertex */ 4059 if ( *ncoververtices == 0 ) 4060 { 4061 for (j = 0; j < nsucc2; ++j) 4062 { 4063 succvertex2 = succ2[j]; 4064 if ( ! verticesarefixed[succvertex2] ) 4065 coververtices[(*ncoververtices)++] = succvertex2; 4066 } 4067 } 4068 else 4069 { 4070 int vv = 0; 4071 int k = 0; 4072 int v; 4073 4074 /* determine all the successors that are in the set "coververtices" */ 4075 for (v = 0; v < *ncoververtices; ++v) 4076 { 4077 assert( vv <= v ); 4078 for (j = k; j < nsucc2; ++j) 4079 { 4080 succvertex2 = succ2[j]; 4081 if ( succvertex2 > coververtices[v] ) 4082 { 4083 /* coververtices[v] does not appear in succ2 list, go to next vertex in coververtices */ 4084 k = j; 4085 break; 4086 } 4087 else if ( succvertex2 == coververtices[v] ) 4088 { 4089 /* vertices are equal, copy to free position vv */ 4090 coververtices[vv++] = succvertex2; 4091 k = j + 1; 4092 break; 4093 } 4094 } 4095 } 4096 /* store new size of coververtices */ 4097 *ncoververtices = vv; 4098 } 4099 } 4100 } 4101 4102 #ifdef SCIP_DEBUG 4103 /* check sorting */ 4104 for (s = 0; s < *ncoververtices; ++s) 4105 { 4106 assert( *ncoververtices <= 1 || coververtices[*ncoververtices - 1] > coververtices[*ncoververtices - 2] ); 4107 } 4108 #endif 4109 4110 return SCIP_OKAY; 4111 } 4112 4113 4114 /** get vertices of variables that will be fixed to zero for each node */ 4115 static 4116 SCIP_RETCODE getBranchingVerticesSOS1( 4117 SCIP* scip, /**< SCIP pointer */ 4118 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 4119 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */ 4120 SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zero */ 4121 SCIP_Bool bipbranch, /**< TRUE if bipartite branching method should be used */ 4122 int branchvertex, /**< branching vertex */ 4123 int* fixingsnode1, /**< vertices of variables that will be fixed to zero for the first node */ 4124 int* nfixingsnode1, /**< pointer to store number of fixed variables for the first node */ 4125 int* fixingsnode2, /**< vertices of variables that will be fixed to zero for the second node */ 4126 int* nfixingsnode2 /**< pointer to store number of fixed variables for the second node */ 4127 ) 4128 { 4129 SCIP_Bool takeallsucc; /* whether to set fixingsnode1 = neighbors of 'branchvertex' in the conflict graph */ 4130 int* succ; 4131 int nsucc; 4132 int j; 4133 4134 assert( scip != NULL ); 4135 assert( conflictgraph != NULL ); 4136 assert( verticesarefixed != NULL ); 4137 assert( ! verticesarefixed[branchvertex] ); 4138 assert( fixingsnode1 != NULL ); 4139 assert( fixingsnode2 != NULL ); 4140 assert( nfixingsnode1 != NULL ); 4141 assert( nfixingsnode2 != NULL ); 4142 4143 *nfixingsnode1 = 0; 4144 *nfixingsnode2 = 0; 4145 takeallsucc = TRUE; 4146 4147 /* get successors and number of successors of branching vertex */ 4148 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, branchvertex); 4149 succ = SCIPdigraphGetSuccessors(conflictgraph, branchvertex); 4150 4151 /* if bipartite branching method is turned on */ 4152 if ( bipbranch ) 4153 { 4154 SCIP_Real solval; 4155 int cnt = 0; 4156 4157 /* get all the neighbors of the variable with index 'branchvertex' whose solution value is nonzero */ 4158 for (j = 0; j < nsucc; ++j) 4159 { 4160 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, succ[j]))) ) 4161 { 4162 assert( ! verticesarefixed[succ[j]] ); 4163 fixingsnode1[(*nfixingsnode1)++] = succ[j]; 4164 } 4165 } 4166 4167 /* if one of the sets fixingsnode1 or fixingsnode2 contains only one variable with a nonzero LP value we perform standard neighborhood branching */ 4168 if ( *nfixingsnode1 > 0 ) 4169 { 4170 /* get the vertices whose neighbor set cover the selected subset of the neighbors of the given branching vertex */ 4171 SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode1, *nfixingsnode1, fixingsnode2, nfixingsnode2) ); 4172 4173 /* determine the intersection of the neighbors of branchvertex with the intersection of all the neighbors of fixingsnode2 */ 4174 SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode2, *nfixingsnode2, fixingsnode1, nfixingsnode1) ); 4175 4176 for (j = 0; j < *nfixingsnode2; ++j) 4177 { 4178 solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j])); 4179 if( ! SCIPisFeasZero(scip, solval) ) 4180 ++cnt; 4181 } 4182 4183 /* we decide whether to use all successors if one partition of complete bipartite subgraph has only one node */ 4184 if ( cnt >= 2 ) 4185 { 4186 cnt = 0; 4187 for (j = 0; j < *nfixingsnode1; ++j) 4188 { 4189 solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j])); 4190 if( ! SCIPisFeasZero(scip, solval) ) 4191 ++cnt; 4192 } 4193 4194 if ( cnt >= 2 ) 4195 takeallsucc = FALSE; 4196 } 4197 } 4198 } 4199 4200 if ( takeallsucc ) 4201 { 4202 /* get all the unfixed neighbors of the branching vertex */ 4203 *nfixingsnode1 = 0; 4204 for (j = 0; j < nsucc; ++j) 4205 { 4206 if ( ! verticesarefixed[succ[j]] ) 4207 fixingsnode1[(*nfixingsnode1)++] = succ[j]; 4208 } 4209 4210 if ( bipbranch ) 4211 { 4212 /* get the vertices whose neighbor set covers the neighbor set of a given branching vertex */ 4213 SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode1, *nfixingsnode1, fixingsnode2, nfixingsnode2) ); 4214 } 4215 else 4216 { 4217 /* use neighborhood branching, i.e, for the second node only the branching vertex can be fixed */ 4218 fixingsnode2[0] = branchvertex; 4219 *nfixingsnode2 = 1; 4220 } 4221 } 4222 4223 return SCIP_OKAY; 4224 } 4225 4226 4227 /** gets branching priorities for SOS1 variables and applies 'most infeasible selection' rule to determine a vertex for the next branching decision */ 4228 static 4229 SCIP_RETCODE getBranchingPrioritiesSOS1( 4230 SCIP* scip, /**< SCIP pointer */ 4231 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 4232 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 4233 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */ 4234 int nsos1vars, /**< number of SOS1 variables */ 4235 SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zero */ 4236 SCIP_Bool bipbranch, /**< TRUE if bipartite branching method should be used */ 4237 int* fixingsnode1, /**< vertices of variables that will be fixed to zero for the first node (size = nsos1vars) */ 4238 int* fixingsnode2, /**< vertices of variables that will be fixed to zero for the second node (size = nsos1vars) */ 4239 SCIP_Real* branchpriors, /**< pointer to store branching priorities (size = nsos1vars) or NULL if not needed */ 4240 int* vertexbestprior, /**< pointer to store vertex with the best branching priority or NULL if not needed */ 4241 SCIP_Bool* relsolfeas /**< pointer to store if LP relaxation solution is feasible */ 4242 ) 4243 { 4244 SCIP_Real bestprior; 4245 int i; 4246 4247 assert( scip != NULL ); 4248 assert( conshdlrdata != NULL ); 4249 assert( conflictgraph != NULL ); 4250 assert( verticesarefixed != NULL ); 4251 assert( fixingsnode1 != NULL ); 4252 assert( fixingsnode2 != NULL ); 4253 assert( relsolfeas != NULL ); 4254 4255 bestprior = -SCIPinfinity(scip); 4256 4257 /* make sure data is initialized */ 4258 if ( vertexbestprior != NULL ) 4259 *vertexbestprior = -1; 4260 4261 for (i = 0; i < nsos1vars; ++i) 4262 { 4263 SCIP_Real prior; 4264 SCIP_Real solval; 4265 int nfixingsnode1; 4266 int nfixingsnode2; 4267 int nsucc; 4268 int j; 4269 4270 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i); 4271 4272 if ( nsucc == 0 || SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, i))) || verticesarefixed[i] ) 4273 prior = -SCIPinfinity(scip); 4274 else 4275 { 4276 SCIP_Bool iszero1 = TRUE; 4277 SCIP_Bool iszero2 = TRUE; 4278 SCIP_Real sum1 = 0.0; 4279 SCIP_Real sum2 = 0.0; 4280 4281 /* get vertices of variables that will be fixed to zero for each strong branching execution */ 4282 assert( ! verticesarefixed[i] ); 4283 SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, sol, verticesarefixed, bipbranch, i, fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) ); 4284 4285 for (j = 0; j < nfixingsnode1; ++j) 4286 { 4287 solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j])); 4288 if ( ! SCIPisFeasZero(scip, solval) ) 4289 { 4290 sum1 += REALABS( solval ); 4291 iszero1 = FALSE; 4292 } 4293 } 4294 4295 for (j = 0; j < nfixingsnode2; ++j) 4296 { 4297 solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j])); 4298 if ( ! SCIPisFeasZero(scip, solval) ) 4299 { 4300 sum2 += REALABS( solval ); 4301 iszero2 = FALSE; 4302 } 4303 } 4304 4305 if ( iszero1 || iszero2 ) 4306 prior = -SCIPinfinity(scip); 4307 else 4308 prior = sum1 * sum2; 4309 } 4310 4311 if ( branchpriors != NULL ) 4312 branchpriors[i] = prior; 4313 if ( bestprior < prior ) 4314 { 4315 bestprior = prior; 4316 4317 if ( vertexbestprior != NULL ) 4318 *vertexbestprior = i; 4319 } 4320 } 4321 4322 if ( SCIPisInfinity(scip, -bestprior) ) 4323 *relsolfeas = TRUE; 4324 else 4325 *relsolfeas = FALSE; 4326 4327 return SCIP_OKAY; 4328 } 4329 4330 4331 /** performs strong branching with given domain fixings */ 4332 static 4333 SCIP_RETCODE performStrongbranchSOS1( 4334 SCIP* scip, /**< SCIP pointer */ 4335 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 4336 int* fixingsexec, /**< vertices of variables to be fixed to zero for this strong branching execution */ 4337 int nfixingsexec, /**< number of vertices of variables to be fixed to zero for this strong branching execution */ 4338 int* fixingsop, /**< vertices of variables to be fixed to zero for the opposite strong branching execution */ 4339 int nfixingsop, /**< number of vertices of variables to be fixed to zero for the opposite strong branching execution */ 4340 int inititer, /**< maximal number of LP iterations to perform */ 4341 SCIP_Bool fixnonzero, /**< shall opposite variable (if positive in sign) fixed to the feasibility tolerance 4342 * (only possible if nfixingsop = 1) */ 4343 int* domainfixings, /**< vertices that can be used to reduce the domain (should have size equal to number of variables) */ 4344 int* ndomainfixings, /**< pointer to store number of vertices that can be used to reduce the domain, could be filled by earlier calls */ 4345 SCIP_Bool* infeasible, /**< pointer to store whether branch is infeasible */ 4346 SCIP_Real* objval, /**< pointer to store objective value of LP with fixed variables (SCIP_INVALID if reddomain = TRUE or lperror = TRUE) */ 4347 SCIP_Bool* lperror /**< pointer to store whether an unresolved LP error or a strange solution status occurred */ 4348 ) 4349 { 4350 SCIP_LPSOLSTAT solstat; 4351 int i; 4352 4353 assert( scip != NULL ); 4354 assert( conflictgraph != NULL ); 4355 assert( fixingsexec != NULL ); 4356 assert( nfixingsop > 0 ); 4357 assert( fixingsop != NULL ); 4358 assert( nfixingsop > 0 ); 4359 assert( inititer >= -1 ); 4360 assert( domainfixings != NULL ); 4361 assert( ndomainfixings != NULL ); 4362 assert( *ndomainfixings >= 0 ); 4363 assert( infeasible != NULL ); 4364 assert( objval != NULL ); 4365 assert( lperror != NULL ); 4366 4367 *objval = SCIP_INVALID; /* for debugging */ 4368 *lperror = FALSE; 4369 *infeasible = FALSE; 4370 4371 /* start probing */ 4372 SCIP_CALL( SCIPstartProbing(scip) ); 4373 4374 /* perform domain fixings */ 4375 if ( fixnonzero && nfixingsop == 1 ) 4376 { 4377 SCIP_VAR* var; 4378 SCIP_Real lb; 4379 SCIP_Real ub; 4380 4381 var = SCIPnodeGetVarSOS1(conflictgraph, fixingsop[0]); 4382 lb = SCIPvarGetLbLocal(var); 4383 ub = SCIPvarGetUbLocal(var); 4384 4385 if ( SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR ) 4386 { 4387 if ( SCIPisZero(scip, lb) ) 4388 { 4389 /* fix variable to some very small, but positive number or to 1.0 if variable is integral */ 4390 if (SCIPvarIsIntegral(var) ) 4391 { 4392 SCIP_CALL( SCIPchgVarLbProbing(scip, var, 1.0) ); 4393 } 4394 else 4395 { 4396 SCIP_CALL( SCIPchgVarLbProbing(scip, var, 1.5 * SCIPfeastol(scip)) ); 4397 } 4398 } 4399 else if ( SCIPisZero(scip, ub) ) 4400 { 4401 /* fix variable to some negative number with small absolute value or to -1.0 if variable is integral */ 4402 if (SCIPvarIsIntegral(var) ) 4403 { 4404 SCIP_CALL( SCIPchgVarUbProbing(scip, var, -1.0) ); 4405 } 4406 else 4407 { 4408 SCIP_CALL( SCIPchgVarUbProbing(scip, var, -1.5 * SCIPfeastol(scip)) ); 4409 } 4410 } 4411 } 4412 } 4413 4414 /* injects variable fixings into current probing node */ 4415 for (i = 0; i < nfixingsexec && ! *infeasible; ++i) 4416 { 4417 SCIP_VAR* var; 4418 4419 var = SCIPnodeGetVarSOS1(conflictgraph, fixingsexec[i]); 4420 if ( SCIPisFeasGT(scip, SCIPvarGetLbLocal(var), 0.0) || SCIPisFeasLT(scip, SCIPvarGetUbLocal(var), 0.0) ) 4421 *infeasible = TRUE; 4422 else 4423 { 4424 SCIP_CALL( SCIPfixVarProbing(scip, var, 0.0) ); 4425 } 4426 } 4427 4428 /* apply domain propagation */ 4429 if ( ! *infeasible ) 4430 { 4431 SCIP_CALL( SCIPpropagateProbing(scip, 0, infeasible, NULL) ); 4432 } 4433 4434 if ( *infeasible ) 4435 solstat = SCIP_LPSOLSTAT_INFEASIBLE; 4436 else 4437 { 4438 /* solve the probing LP */ 4439 SCIP_CALL( SCIPsolveProbingLP(scip, inititer, lperror, NULL) ); 4440 if ( *lperror ) 4441 { 4442 SCIP_CALL( SCIPendProbing(scip) ); 4443 return SCIP_OKAY; 4444 } 4445 4446 /* get solution status */ 4447 solstat = SCIPgetLPSolstat(scip); 4448 } 4449 4450 /* if objective limit was reached, then the domain can be reduced */ 4451 if ( solstat == SCIP_LPSOLSTAT_OBJLIMIT || solstat == SCIP_LPSOLSTAT_INFEASIBLE ) 4452 { 4453 *infeasible = TRUE; 4454 4455 for (i = 0; i < nfixingsop; ++i) 4456 domainfixings[(*ndomainfixings)++] = fixingsop[i]; 4457 } 4458 else if ( solstat == SCIP_LPSOLSTAT_OPTIMAL || solstat == SCIP_LPSOLSTAT_TIMELIMIT || solstat == SCIP_LPSOLSTAT_ITERLIMIT ) 4459 { 4460 /* get objective value of probing LP */ 4461 *objval = SCIPgetLPObjval(scip); 4462 } 4463 else 4464 *lperror = TRUE; 4465 4466 /* end probing */ 4467 SCIP_CALL( SCIPendProbing(scip) ); 4468 4469 return SCIP_OKAY; 4470 } 4471 4472 4473 /** apply strong branching to determine the vertex for the next branching decision */ 4474 static 4475 SCIP_RETCODE getBranchingDecisionStrongbranchSOS1( 4476 SCIP* scip, /**< SCIP pointer */ 4477 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */ 4478 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 4479 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */ 4480 int nsos1vars, /**< number of SOS1 variables */ 4481 SCIP_Real lpobjval, /**< current LP relaxation solution */ 4482 SCIP_Bool bipbranch, /**< TRUE if bipartite branching method should be used */ 4483 int nstrongrounds, /**< number of strong branching rounds */ 4484 SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zero */ 4485 int* fixingsnode1, /**< pointer to store vertices of variables that will be fixed to zero for the first node (size = nsos1vars) */ 4486 int* fixingsnode2, /**< pointer to store vertices of variables that will be fixed to zero for the second node (size = nsos1vars) */ 4487 int* vertexbestprior, /**< pointer to store vertex with the best strong branching priority */ 4488 SCIP_Real* bestobjval1, /**< pointer to store LP objective for left child node of branching decision with best priority */ 4489 SCIP_Real* bestobjval2, /**< pointer to store LP objective for right child node of branching decision with best priority */ 4490 SCIP_RESULT* result /**< pointer to store result of strong branching */ 4491 ) 4492 { 4493 SCIP_Real* branchpriors = NULL; 4494 int* indsos1vars = NULL; 4495 int* domainfixings = NULL; 4496 int ndomainfixings; 4497 int nfixingsnode1; 4498 int nfixingsnode2; 4499 4500 SCIP_Bool relsolfeas; 4501 SCIP_Real bestscore; 4502 int lastscorechange; 4503 int maxfailures; 4504 4505 SCIP_Longint nlpiterations; 4506 SCIP_Longint nlps; 4507 int inititer; 4508 int j; 4509 int i; 4510 4511 assert( scip != NULL ); 4512 assert( conshdlrdata != NULL ); 4513 assert( conflictgraph != NULL ); 4514 assert( verticesarefixed != NULL ); 4515 assert( fixingsnode1 != NULL ); 4516 assert( fixingsnode2 != NULL ); 4517 assert( vertexbestprior != NULL ); 4518 assert( result != NULL ); 4519 4520 /* allocate buffer arrays */ 4521 SCIP_CALL( SCIPallocBufferArray(scip, &branchpriors, nsos1vars) ); 4522 4523 /* get branching priorities */ 4524 SCIP_CALL( getBranchingPrioritiesSOS1(scip, conshdlrdata, conflictgraph, sol, nsos1vars, verticesarefixed, 4525 bipbranch, fixingsnode1, fixingsnode2, branchpriors, NULL, &relsolfeas) ); 4526 4527 /* if LP relaxation solution is feasible */ 4528 if ( relsolfeas ) 4529 { 4530 SCIPdebugMsg(scip, "all the SOS1 constraints are feasible.\n"); 4531 *vertexbestprior = -1; 4532 *result = SCIP_FEASIBLE; 4533 4534 /* free memory */ 4535 SCIPfreeBufferArrayNull(scip, &branchpriors); 4536 4537 return SCIP_OKAY; 4538 } 4539 4540 /* allocate buffer arrays */ 4541 SCIP_CALL( SCIPallocBufferArray(scip, &indsos1vars, nsos1vars) ); 4542 SCIP_CALL( SCIPallocBufferArray(scip, &domainfixings, nsos1vars) ); 4543 4544 /* sort branching priorities (descending order) */ 4545 for (j = 0; j < nsos1vars; ++j) 4546 indsos1vars[j] = j; 4547 SCIPsortDownRealInt(branchpriors, indsos1vars, nsos1vars); 4548 4549 /* determine the number of LP iterations to perform in each strong branch */ 4550 nlpiterations = SCIPgetNDualResolveLPIterations(scip); 4551 nlps = SCIPgetNDualResolveLPs(scip); 4552 if ( nlps == 0 ) 4553 { 4554 nlpiterations = SCIPgetNNodeInitLPIterations(scip); 4555 nlps = SCIPgetNNodeInitLPs(scip); 4556 if ( nlps == 0 ) 4557 { 4558 nlpiterations = 1000; 4559 nlps = 1; 4560 } 4561 } 4562 assert(nlps >= 1); 4563 4564 /* compute number of LP iterations performed per strong branching iteration */ 4565 if ( conshdlrdata->nstrongiter == -2 ) 4566 { 4567 inititer = (int)(2*nlpiterations / nlps); 4568 inititer = (int)((SCIP_Real)inititer * (1.0 + 20.0/SCIPgetNNodes(scip))); 4569 inititer = MAX(inititer, 10); 4570 inititer = MIN(inititer, 500); 4571 } 4572 else 4573 inititer = conshdlrdata->nstrongiter; 4574 4575 /* get current LP relaxation solution */ 4576 lpobjval = SCIPgetLPObjval(scip); 4577 4578 /* determine branching variable by strong branching or reduce domain */ 4579 ndomainfixings = 0; 4580 lastscorechange = -1; 4581 assert( nsos1vars > 0 ); 4582 *vertexbestprior = indsos1vars[0]; /* for the case that nstrongrounds = 0 */ 4583 bestscore = -SCIPinfinity(scip); 4584 *bestobjval1 = -SCIPinfinity(scip); 4585 *bestobjval2 = -SCIPinfinity(scip); 4586 maxfailures = nstrongrounds; 4587 4588 /* for each strong branching round */ 4589 for (j = 0; j < nstrongrounds; ++j) 4590 { 4591 int testvertex; 4592 4593 /* get branching vertex for the current strong branching iteration */ 4594 testvertex = indsos1vars[j]; 4595 4596 /* if variable with index 'vertex' does not violate any complementarity in its neighborhood for the current LP relaxation solution */ 4597 if ( SCIPisPositive(scip, branchpriors[j]) ) 4598 { 4599 SCIP_Bool infeasible1; 4600 SCIP_Bool infeasible2; 4601 SCIP_Bool lperror; 4602 SCIP_Real objval1; 4603 SCIP_Real objval2; 4604 SCIP_Real score; 4605 4606 /* get vertices of variables that will be fixed to zero for each strong branching execution */ 4607 assert( ! verticesarefixed[testvertex] ); 4608 SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, sol, verticesarefixed, bipbranch, testvertex, 4609 fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) ); 4610 4611 /* get information for first strong branching execution */ 4612 SCIP_CALL( performStrongbranchSOS1(scip, conflictgraph, fixingsnode1, nfixingsnode1, fixingsnode2, nfixingsnode2, 4613 inititer, conshdlrdata->fixnonzero, domainfixings, &ndomainfixings, &infeasible1, &objval1, &lperror) ); 4614 if ( lperror ) 4615 continue; 4616 4617 /* get information for second strong branching execution */ 4618 SCIP_CALL( performStrongbranchSOS1(scip, conflictgraph, fixingsnode2, nfixingsnode2, fixingsnode1, nfixingsnode1, 4619 inititer, FALSE, domainfixings, &ndomainfixings, &infeasible2, &objval2, &lperror) ); 4620 if ( lperror ) 4621 continue; 4622 4623 /* if both subproblems are infeasible */ 4624 if ( infeasible1 && infeasible2 ) 4625 { 4626 SCIPdebugMsg(scip, "detected cutoff.\n"); 4627 4628 /* update result */ 4629 *result = SCIP_CUTOFF; 4630 4631 /* free memory */ 4632 SCIPfreeBufferArrayNull(scip, &domainfixings); 4633 SCIPfreeBufferArrayNull(scip, &indsos1vars); 4634 SCIPfreeBufferArrayNull(scip, &branchpriors); 4635 4636 return SCIP_OKAY; 4637 } 4638 else if ( ! infeasible1 && ! infeasible2 ) /* both subproblems are feasible */ 4639 { 4640 /* if domain has not been reduced in this for-loop */ 4641 if ( ndomainfixings == 0 ) 4642 { 4643 score = MAX( REALABS(objval1 - lpobjval), SCIPfeastol(scip) ) * MAX( REALABS(objval2 - lpobjval), SCIPfeastol(scip) );/*lint !e666*/ 4644 4645 if ( SCIPisPositive(scip, score - bestscore) ) 4646 { 4647 bestscore = score; 4648 *vertexbestprior = testvertex; 4649 *bestobjval1 = objval1; 4650 *bestobjval2 = objval2; 4651 4652 lastscorechange = j; 4653 } 4654 else if ( j - lastscorechange > maxfailures ) 4655 break; 4656 } 4657 } 4658 } 4659 } 4660 4661 /* if variable fixings have been detected by probing, then reduce domain */ 4662 if ( ndomainfixings > 0 ) 4663 { 4664 SCIP_NODE* node = SCIPgetCurrentNode(scip); 4665 SCIP_Bool infeasible; 4666 4667 for (i = 0; i < ndomainfixings; ++i) 4668 { 4669 SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, domainfixings[i]), node, &infeasible) ); 4670 assert( ! infeasible ); 4671 } 4672 4673 SCIPdebugMsg(scip, "found %d domain fixings.\n", ndomainfixings); 4674 4675 /* update result */ 4676 *result = SCIP_REDUCEDDOM; 4677 } 4678 4679 /* free buffer arrays */ 4680 SCIPfreeBufferArrayNull(scip, &domainfixings); 4681 SCIPfreeBufferArrayNull(scip, &indsos1vars); 4682 SCIPfreeBufferArrayNull(scip, &branchpriors); 4683 4684 return SCIP_OKAY; 4685 } 4686 4687 4688 /** for two given vertices @p v1 and @p v2 search for a clique in the conflict graph that contains these vertices. From 4689 * this clique, we create a bound constraint. 4690 */ 4691 static 4692 SCIP_RETCODE getBoundConsFromVertices( 4693 SCIP* scip, /**< SCIP pointer */ 4694 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 4695 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */ 4696 int v1, /**< first vertex that shall be contained in bound constraint */ 4697 int v2, /**< second vertex that shall be contained in bound constraint */ 4698 SCIP_VAR* boundvar, /**< bound variable of @p v1 and @p v2 (or NULL if not existent) */ 4699 SCIP_Bool extend, /**< should @p v1 and @p v2 be greedily extended to a clique of larger size */ 4700 SCIP_CONS* cons, /**< bound constraint */ 4701 SCIP_Real* feas /**< feasibility value of bound constraint */ 4702 ) 4703 { 4704 SCIP_NODEDATA* nodedata; 4705 SCIP_Bool addv2 = TRUE; 4706 SCIP_Real solval; 4707 SCIP_VAR* var; 4708 SCIP_Real coef = 0.0; 4709 int nsucc; 4710 int s; 4711 4712 int* extensions = NULL; 4713 int nextensions = 0; 4714 int nextensionsnew; 4715 int* succ; 4716 4717 assert( scip != NULL ); 4718 assert( conflictgraph != NULL ); 4719 assert( cons != NULL ); 4720 assert( feas != NULL ); 4721 4722 *feas = 0.0; 4723 4724 /* add index 'v1' to the clique */ 4725 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, v1); 4726 var = nodedata->var; 4727 assert( boundvar == NULL || SCIPvarCompare(boundvar, nodedata->ubboundvar) == 0 ); 4728 solval = SCIPgetSolVal(scip, sol, var); 4729 4730 /* if 'v1' and 'v2' have the same bound variable then the bound cut can be strengthened */ 4731 if ( boundvar == NULL ) 4732 { 4733 if ( SCIPisFeasPositive(scip, solval) ) 4734 { 4735 SCIP_Real ub; 4736 ub = SCIPvarGetUbLocal(var); 4737 assert( SCIPisFeasPositive(scip, ub)); 4738 4739 if ( ! SCIPisInfinity(scip, ub) ) 4740 coef = 1.0/ub; 4741 } 4742 else if ( SCIPisFeasNegative(scip, solval) ) 4743 { 4744 SCIP_Real lb; 4745 lb = SCIPvarGetLbLocal(var); 4746 assert( SCIPisFeasNegative(scip, lb) ); 4747 if ( ! SCIPisInfinity(scip, -lb) ) 4748 coef = 1.0/lb; 4749 } 4750 } 4751 else if ( boundvar == nodedata->ubboundvar ) 4752 { 4753 if ( SCIPisFeasPositive(scip, solval) ) 4754 { 4755 SCIP_Real ub; 4756 4757 ub = nodedata->ubboundcoef; 4758 assert( SCIPisFeasPositive(scip, ub) ); 4759 if ( ! SCIPisInfinity(scip, ub) ) 4760 coef = 1.0/ub; 4761 } 4762 else if ( SCIPisFeasNegative(scip, solval) ) 4763 { 4764 SCIP_Real lb; 4765 4766 lb = nodedata->lbboundcoef; 4767 assert( SCIPisFeasPositive(scip, lb) ); 4768 if ( ! SCIPisInfinity(scip, lb) ) 4769 coef = 1.0/lb; 4770 } 4771 } 4772 4773 if ( ! SCIPisZero(scip, coef) ) 4774 { 4775 *feas += coef * solval; 4776 SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, coef) ); 4777 } 4778 4779 /* if clique shall be greedily extended to a clique of larger size */ 4780 if ( extend ) 4781 { 4782 /* get successors */ 4783 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, v1); 4784 succ = SCIPdigraphGetSuccessors(conflictgraph, v1); 4785 assert( nsucc > 0 ); 4786 4787 /* allocate buffer array */ 4788 SCIP_CALL( SCIPallocBufferArray(scip, &extensions, nsucc) ); 4789 4790 /* get possible extensions for the clique cover */ 4791 for (s = 0; s < nsucc; ++s) 4792 extensions[s] = succ[s]; 4793 nextensions = nsucc; 4794 } 4795 else 4796 nextensions = 1; 4797 4798 /* while there exist possible extensions for the clique cover */ 4799 while ( nextensions > 0 ) 4800 { 4801 SCIP_Real bestbigMval; 4802 SCIP_Real bigMval; 4803 int bestindex = -1; 4804 int ext; 4805 4806 bestbigMval = -SCIPinfinity(scip); 4807 4808 /* if v2 has not been added to clique already */ 4809 if ( addv2 ) 4810 { 4811 bestindex = v2; 4812 addv2 = FALSE; 4813 } 4814 else /* search for the extension with the largest absolute value of its LP relaxation solution value */ 4815 { 4816 assert( extensions != NULL ); 4817 for (s = 0; s < nextensions; ++s) 4818 { 4819 ext = extensions[s]; 4820 bigMval = nodeGetSolvalBinaryBigMSOS1(scip, conflictgraph, sol, ext); 4821 if ( SCIPisFeasLT(scip, bestbigMval, bigMval) ) 4822 { 4823 bestbigMval = bigMval; 4824 bestindex = ext; 4825 } 4826 } 4827 } 4828 assert( bestindex != -1 ); 4829 4830 /* add bestindex variable to the constraint */ 4831 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, bestindex); 4832 var = nodedata->var; 4833 solval = SCIPgetSolVal(scip, sol, var); 4834 coef = 0.0; 4835 if ( boundvar == NULL ) 4836 { 4837 if ( SCIPisFeasPositive(scip, solval) ) 4838 { 4839 SCIP_Real ub; 4840 ub = SCIPvarGetUbLocal(var); 4841 assert( SCIPisFeasPositive(scip, ub)); 4842 4843 if ( ! SCIPisInfinity(scip, ub) ) 4844 coef = 1.0/ub; 4845 } 4846 else if ( SCIPisFeasNegative(scip, solval) ) 4847 { 4848 SCIP_Real lb; 4849 lb = SCIPvarGetLbLocal(var); 4850 assert( SCIPisFeasNegative(scip, lb) ); 4851 if ( ! SCIPisInfinity(scip, -lb) ) 4852 coef = 1.0/lb; 4853 } 4854 } 4855 else if ( boundvar == nodedata->ubboundvar ) 4856 { 4857 if ( SCIPisFeasPositive(scip, solval) ) 4858 { 4859 SCIP_Real ub; 4860 4861 ub = nodedata->ubboundcoef; 4862 assert( SCIPisFeasPositive(scip, ub) ); 4863 if ( ! SCIPisInfinity(scip, ub) ) 4864 coef = 1.0/ub; 4865 } 4866 else if ( SCIPisFeasNegative(scip, solval) ) 4867 { 4868 SCIP_Real lb; 4869 4870 lb = nodedata->lbboundcoef; 4871 assert( SCIPisFeasPositive(scip, lb) ); 4872 if ( ! SCIPisInfinity(scip, -lb) ) 4873 coef = 1.0/lb; 4874 } 4875 } 4876 if ( ! SCIPisZero(scip, coef) ) 4877 { 4878 *feas += coef * solval; 4879 SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, coef) ); 4880 } 4881 4882 if ( extend ) 4883 { 4884 assert( extensions != NULL ); 4885 /* compute new 'extensions' array */ 4886 nextensionsnew = 0; 4887 for (s = 0; s < nextensions; ++s) 4888 { 4889 if ( s != bestindex && isConnectedSOS1(NULL, conflictgraph, bestindex, extensions[s]) ) 4890 extensions[nextensionsnew++] = extensions[s]; 4891 } 4892 nextensions = nextensionsnew; 4893 } 4894 else 4895 nextensions = 0; 4896 } 4897 4898 /* free buffer array */ 4899 if ( extend ) 4900 SCIPfreeBufferArray(scip, &extensions); 4901 4902 /* subtract rhs of constraint from feasibility value or add bound variable if existent */ 4903 if ( boundvar == NULL ) 4904 *feas -= 1.0; 4905 else 4906 { 4907 SCIP_CALL( SCIPaddCoefLinear(scip, cons, boundvar, -1.0) ); 4908 *feas -= SCIPgetSolVal(scip, sol, boundvar); 4909 } 4910 4911 return SCIP_OKAY; 4912 } 4913 4914 4915 /** tries to add feasible complementarity constraints to a given child branching node. 4916 * 4917 * @note In this function the conflict graph is updated to the conflict graph of the considered child branching node. 4918 */ 4919 static 4920 SCIP_RETCODE addBranchingComplementaritiesSOS1( 4921 SCIP* scip, /**< SCIP pointer */ 4922 SCIP_NODE* node, /**< branching node */ 4923 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 4924 SCIP_DIGRAPH* conflictgraph, /**< conflict graph of the current node */ 4925 SCIP_DIGRAPH* localconflicts, /**< local conflicts (updates to local conflicts of child node) */ 4926 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */ 4927 int nsos1vars, /**< number of SOS1 variables */ 4928 SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zerox */ 4929 int* fixingsnode1, /**< vertices of variables that will be fixed to zero for the branching node in the input of this function */ 4930 int nfixingsnode1, /**< number of entries of array nfixingsnode1 */ 4931 int* fixingsnode2, /**< vertices of variables that will be fixed to zero for the other branching node */ 4932 int nfixingsnode2, /**< number of entries of array nfixingsnode2 */ 4933 int* naddedconss, /**< pointer to store the number of added SOS1 constraints */ 4934 SCIP_Bool onlyviolsos1 /**< should only SOS1 constraints be added that are violated by the LP solution */ 4935 ) 4936 { 4937 assert( scip != NULL ); 4938 assert( node != NULL ); 4939 assert( conshdlrdata != NULL ); 4940 assert( conflictgraph != NULL ); 4941 assert( verticesarefixed != NULL ); 4942 assert( fixingsnode1 != NULL ); 4943 assert( fixingsnode2 != NULL ); 4944 assert( naddedconss != NULL ); 4945 4946 *naddedconss = 0; 4947 4948 if ( nfixingsnode2 > 1 ) 4949 { 4950 int* fixingsnode21; /* first partition of fixingsnode2 */ 4951 int* fixingsnode22; /* second partition of fixingsnode2 */ 4952 int nfixingsnode21; 4953 int nfixingsnode22; 4954 4955 int* coverarray; /* vertices, not in fixingsnode1 that cover all the vertices in array fixingsnode22 */ 4956 int ncoverarray; 4957 4958 SCIP_Bool* mark; 4959 int* succarray; 4960 int nsuccarray; 4961 int* succ; 4962 int nsucc; 4963 4964 int i; 4965 int s; 4966 4967 /* allocate buffer arrays */ 4968 SCIP_CALL( SCIPallocBufferArray(scip, &succarray, nsos1vars) ); 4969 SCIP_CALL( SCIPallocBufferArray(scip, &mark, nsos1vars) ); 4970 SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode21, nfixingsnode2) ); 4971 SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode22, nfixingsnode2) ); 4972 4973 /* mark all the unfixed vertices with FALSE */ 4974 for (i = 0; i < nsos1vars; ++i) 4975 mark[i] = (verticesarefixed[i]); 4976 4977 /* mark all the vertices that are in the set fixingsnode1 */ 4978 for (i = 0; i < nfixingsnode1; ++i) 4979 { 4980 assert( nfixingsnode1 <= 1 || (fixingsnode1[nfixingsnode1 - 1] > fixingsnode1[nfixingsnode1 - 2]) ); /* test: vertices are sorted */ 4981 mark[fixingsnode1[i]] = TRUE; 4982 } 4983 4984 /* mark all the vertices that are in the set fixingsnode2 */ 4985 for (i = 0; i < nfixingsnode2; ++i) 4986 { 4987 assert( nfixingsnode2 <= 1 || (fixingsnode2[nfixingsnode2 - 1] > fixingsnode2[nfixingsnode2 - 2]) ); /* test: vertices are sorted */ 4988 mark[fixingsnode2[i]] = TRUE; 4989 } 4990 4991 /* compute the set of vertices that have a neighbor in the set fixingsnode2, but are not in the set fixingsnode1 or fixingsnode2 and are not already fixed */ 4992 nsuccarray = 0; 4993 for (i = 0; i < nfixingsnode2; ++i) 4994 { 4995 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, fixingsnode2[i]); 4996 succ = SCIPdigraphGetSuccessors(conflictgraph, fixingsnode2[i]); 4997 4998 for (s = 0; s < nsucc; ++s) 4999 { 5000 int succnode = succ[s]; 5001 5002 if ( ! mark[succnode] ) 5003 { 5004 mark[succnode] = TRUE; 5005 succarray[nsuccarray++] = succnode; 5006 } 5007 } 5008 } 5009 5010 /* allocate buffer array */ 5011 SCIP_CALL( SCIPallocBufferArray(scip, &coverarray, nsos1vars) ); 5012 5013 /* mark all the vertices with FALSE */ 5014 for (i = 0; i < nsos1vars; ++i) 5015 mark[i] = FALSE; 5016 5017 /* mark all the vertices that are in the set fixingsnode2 */ 5018 for (i = 0; i < nfixingsnode2; ++i) 5019 mark[fixingsnode2[i]] = TRUE; 5020 5021 /* for every node in succarray */ 5022 for (i = 0; i < nsuccarray; ++i) 5023 { 5024 SCIP_Real solval1; 5025 SCIP_VAR* var1; 5026 int vertex1; 5027 int j; 5028 5029 vertex1 = succarray[i]; 5030 var1 = SCIPnodeGetVarSOS1(conflictgraph, vertex1); 5031 solval1 = SCIPgetSolVal(scip, sol, var1); 5032 5033 /* we only add complementarity constraints if they are violated by the current LP solution */ 5034 if ( ! onlyviolsos1 || ! SCIPisFeasZero(scip, solval1) ) 5035 { 5036 /* compute first partition of fixingsnode2 that is the intersection of the neighbors of 'vertex1' with the set fixingsnode2 */ 5037 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, vertex1); 5038 succ = SCIPdigraphGetSuccessors(conflictgraph, vertex1); 5039 nfixingsnode21 = 0; 5040 5041 for (s = 0; s < nsucc; ++s) 5042 { 5043 if ( mark[succ[s]] ) 5044 { 5045 fixingsnode21[nfixingsnode21++] = succ[s]; 5046 assert( nfixingsnode21 == 1 || (fixingsnode21[nfixingsnode21 - 1] > fixingsnode21[nfixingsnode21 - 2]) ); /* test: successor vertices are sorted */ 5047 } 5048 } 5049 5050 /* if variable can be fixed to zero */ 5051 if ( nfixingsnode21 == nfixingsnode2 ) 5052 { 5053 SCIP_Bool infeasible; 5054 5055 SCIP_CALL( fixVariableZeroNode(scip, var1, node, &infeasible) ); 5056 assert( ! infeasible ); 5057 continue; 5058 } 5059 5060 /* compute second partition of fixingsnode2 (that is fixingsnode2 \setminus fixingsnode21 ) */ 5061 SCIPcomputeArraysSetminusInt(fixingsnode2, nfixingsnode2, fixingsnode21, nfixingsnode21, fixingsnode22, &nfixingsnode22); 5062 assert ( nfixingsnode22 + nfixingsnode21 == nfixingsnode2 ); 5063 5064 /* compute cover set (that are all the vertices not in fixingsnode1 and fixingsnode21, whose neighborhood covers all the vertices of fixingsnode22) */ 5065 SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, -1, fixingsnode22, nfixingsnode22, coverarray, &ncoverarray) ); 5066 SCIPcomputeArraysSetminusInt(coverarray, ncoverarray, fixingsnode1, nfixingsnode1, coverarray, &ncoverarray); 5067 SCIPcomputeArraysSetminusInt(coverarray, ncoverarray, fixingsnode21, nfixingsnode21, coverarray, &ncoverarray); 5068 5069 for (j = 0; j < ncoverarray; ++j) 5070 { 5071 int vertex2; 5072 5073 vertex2 = coverarray[j]; 5074 assert( vertex2 != vertex1 ); 5075 5076 /* prevent double enumeration */ 5077 if ( vertex2 < vertex1 ) 5078 { 5079 SCIP_VAR* var2; 5080 SCIP_Real solval2; 5081 5082 var2 = SCIPnodeGetVarSOS1(conflictgraph, vertex2); 5083 solval2 = SCIPgetSolVal(scip, sol, var2); 5084 5085 if ( onlyviolsos1 && ( SCIPisFeasZero(scip, solval1) || SCIPisFeasZero(scip, solval2) ) ) 5086 continue; 5087 5088 if ( ! isConnectedSOS1(NULL, conflictgraph, vertex1, vertex2) ) 5089 { 5090 char name[SCIP_MAXSTRLEN]; 5091 SCIP_CONS* conssos1 = NULL; 5092 SCIP_Bool takebound = FALSE; 5093 SCIP_Real feas; 5094 5095 SCIP_NODEDATA* nodedata; 5096 SCIP_Real lbboundcoef1; 5097 SCIP_Real lbboundcoef2; 5098 SCIP_Real ubboundcoef1; 5099 SCIP_Real ubboundcoef2; 5100 SCIP_VAR* boundvar1; 5101 SCIP_VAR* boundvar2; 5102 5103 /* get bound variables if available */ 5104 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, vertex1); 5105 assert( nodedata != NULL ); 5106 boundvar1 = nodedata->ubboundvar; 5107 lbboundcoef1 = nodedata->lbboundcoef; 5108 ubboundcoef1 = nodedata->ubboundcoef; 5109 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, vertex2); 5110 assert( nodedata != NULL ); 5111 boundvar2 = nodedata->ubboundvar; 5112 lbboundcoef2 = nodedata->lbboundcoef; 5113 ubboundcoef2 = nodedata->ubboundcoef; 5114 5115 if ( boundvar1 != NULL && boundvar2 != NULL && SCIPvarCompare(boundvar1, boundvar2) == 0 ) 5116 takebound = TRUE; 5117 5118 /* add new arc to local conflicts in order to generate tighter bound inequalities */ 5119 if ( conshdlrdata->addextendedbds ) 5120 { 5121 if ( localconflicts == NULL ) 5122 { 5123 SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->localconflicts, nsos1vars) ); 5124 localconflicts = conshdlrdata->localconflicts; 5125 } 5126 SCIP_CALL( SCIPdigraphAddArc(localconflicts, vertex1, vertex2, NULL) ); 5127 SCIP_CALL( SCIPdigraphAddArc(localconflicts, vertex2, vertex1, NULL) ); 5128 SCIP_CALL( SCIPdigraphAddArc(conflictgraph, vertex1, vertex2, NULL) ); 5129 SCIP_CALL( SCIPdigraphAddArc(conflictgraph, vertex2, vertex1, NULL) ); 5130 5131 /* can sort successors in place - do not use arcdata */ 5132 SCIPsortInt(SCIPdigraphGetSuccessors(localconflicts, vertex1), SCIPdigraphGetNSuccessors(localconflicts, vertex1)); 5133 SCIPsortInt(SCIPdigraphGetSuccessors(localconflicts, vertex2), SCIPdigraphGetNSuccessors(localconflicts, vertex2)); 5134 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, vertex1), SCIPdigraphGetNSuccessors(conflictgraph, vertex1)); 5135 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, vertex2), SCIPdigraphGetNSuccessors(conflictgraph, vertex2)); 5136 5137 /* mark conflictgraph as not local such that the new arcs are deleted after currents node processing */ 5138 conshdlrdata->isconflocal = TRUE; 5139 } 5140 5141 /* measure feasibility of complementarity between var1 and var2 */ 5142 if ( ! takebound ) 5143 { 5144 feas = -1.0; 5145 if ( SCIPisFeasPositive(scip, solval1) ) 5146 { 5147 assert( SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var1))); 5148 if ( ! SCIPisInfinity(scip, SCIPvarGetUbLocal(var1)) ) 5149 feas += solval1/SCIPvarGetUbLocal(var1); 5150 } 5151 else if ( SCIPisFeasNegative(scip, solval1) ) 5152 { 5153 assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var1))); 5154 if ( ! SCIPisInfinity(scip, -SCIPvarGetLbLocal(var1)) ) 5155 feas += solval1/SCIPvarGetLbLocal(var1); 5156 } 5157 5158 if ( SCIPisFeasPositive(scip, solval2) ) 5159 { 5160 assert( SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var2))); 5161 if ( ! SCIPisInfinity(scip, SCIPvarGetUbLocal(var2)) ) 5162 feas += solval2/SCIPvarGetUbLocal(var2); 5163 } 5164 else if ( SCIPisFeasNegative(scip, solval2) ) 5165 { 5166 assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var2))); 5167 if ( ! SCIPisInfinity(scip, -SCIPvarGetLbLocal(var2)) ) 5168 feas += solval2/SCIPvarGetLbLocal(var2); 5169 } 5170 } 5171 else 5172 { 5173 feas = -SCIPgetSolVal(scip, sol, boundvar1); 5174 if ( SCIPisFeasPositive(scip, solval1) ) 5175 { 5176 assert( SCIPisFeasPositive(scip, ubboundcoef1)); 5177 if ( ! SCIPisInfinity(scip, ubboundcoef1) ) 5178 feas += solval1/ubboundcoef1; 5179 } 5180 else if ( SCIPisFeasNegative(scip, solval1) ) 5181 { 5182 assert( SCIPisFeasPositive(scip, lbboundcoef1)); 5183 if ( ! SCIPisInfinity(scip, -lbboundcoef1) ) 5184 feas += solval1/lbboundcoef1; 5185 } 5186 5187 if ( SCIPisFeasPositive(scip, solval2) ) 5188 { 5189 assert( SCIPisFeasPositive(scip, ubboundcoef2)); 5190 if ( ! SCIPisInfinity(scip, ubboundcoef2) ) 5191 feas += solval2/ubboundcoef2; 5192 } 5193 else if ( SCIPisFeasNegative(scip, solval2) ) 5194 { 5195 assert( SCIPisFeasPositive(scip, lbboundcoef2)); 5196 if ( ! SCIPisInfinity(scip, -lbboundcoef2) ) 5197 feas += solval2/lbboundcoef2; 5198 } 5199 assert( ! SCIPisFeasNegative(scip, solval2) ); 5200 } 5201 5202 if ( SCIPisGT(scip, feas, conshdlrdata->addcompsfeas) ) 5203 { 5204 /* create SOS1 constraint */ 5205 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sos1_branchnode_%" SCIP_LONGINT_FORMAT "_no_%i", SCIPnodeGetNumber(node), *naddedconss); 5206 SCIP_CALL( SCIPcreateConsSOS1(scip, &conssos1, name, 0, NULL, NULL, TRUE, TRUE, TRUE, FALSE, TRUE, 5207 TRUE, FALSE, FALSE, FALSE) ); 5208 5209 /* add variables to SOS1 constraint */ 5210 SCIP_CALL( addVarSOS1(scip, conssos1, conshdlrdata, var1, 1.0) ); 5211 SCIP_CALL( addVarSOS1(scip, conssos1, conshdlrdata, var2, 2.0) ); 5212 5213 /* add SOS1 constraint to the branching node */ 5214 SCIP_CALL( SCIPaddConsNode(scip, node, conssos1, NULL) ); 5215 ++(*naddedconss); 5216 5217 /* release constraint */ 5218 SCIP_CALL( SCIPreleaseCons(scip, &conssos1) ); 5219 } 5220 5221 /* add bound inequality*/ 5222 if ( ! SCIPisFeasZero(scip, solval1) && ! SCIPisFeasZero(scip, solval2) ) 5223 { 5224 /* possibly create linear constraint of the form x_i/u_i + x_j/u_j <= t if a bound variable t with x_i <= u_i * t and x_j <= u_j * t exists. 5225 * Otherwise try to create a constraint of the form x_i/u_i + x_j/u_j <= 1. Try the same for the lower bounds. */ 5226 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "boundcons_branchnode_%" SCIP_LONGINT_FORMAT "_no_%i", SCIPnodeGetNumber(node), *naddedconss); 5227 if ( takebound ) 5228 { 5229 /* create constraint with right hand side = 0.0 */ 5230 SCIP_CALL( SCIPcreateConsLinear(scip, &conssos1, name, 0, NULL, NULL, -SCIPinfinity(scip), 0.0, TRUE, FALSE, TRUE, FALSE, FALSE, 5231 TRUE, FALSE, FALSE, FALSE, FALSE) ); 5232 5233 /* add variables */ 5234 SCIP_CALL( getBoundConsFromVertices(scip, conflictgraph, sol, vertex1, vertex2, boundvar1, conshdlrdata->addextendedbds, conssos1, &feas) ); 5235 } 5236 else 5237 { 5238 /* create constraint with right hand side = 1.0 */ 5239 SCIP_CALL( SCIPcreateConsLinear(scip, &conssos1, name, 0, NULL, NULL, -SCIPinfinity(scip), 1.0, TRUE, FALSE, TRUE, FALSE, FALSE, 5240 TRUE, FALSE, FALSE, FALSE, FALSE) ); 5241 5242 /* add variables */ 5243 SCIP_CALL( getBoundConsFromVertices(scip, conflictgraph, sol, vertex1, vertex2, NULL, conshdlrdata->addextendedbds, conssos1, &feas) ); 5244 } 5245 5246 /* add linear constraint to the branching node if usefull */ 5247 if ( SCIPisGT(scip, feas, conshdlrdata->addbdsfeas ) ) 5248 { 5249 SCIP_CALL( SCIPaddConsNode(scip, node, conssos1, NULL) ); 5250 ++(*naddedconss); 5251 } 5252 5253 /* release constraint */ 5254 SCIP_CALL( SCIPreleaseCons(scip, &conssos1) ); 5255 } 5256 5257 /* break if number of added constraints exceeds a predefined value */ 5258 if ( conshdlrdata->maxaddcomps >= 0 && *naddedconss > conshdlrdata->maxaddcomps ) 5259 break; 5260 } 5261 } 5262 } 5263 } 5264 5265 /* break if number of added constraints exceeds a predefined value */ 5266 if ( conshdlrdata->maxaddcomps >= 0 && *naddedconss > conshdlrdata->maxaddcomps ) 5267 break; 5268 } 5269 5270 /* free buffer array */ 5271 SCIPfreeBufferArray(scip, &coverarray); 5272 SCIPfreeBufferArray(scip, &fixingsnode22); 5273 SCIPfreeBufferArray(scip, &fixingsnode21); 5274 SCIPfreeBufferArray(scip, &mark); 5275 SCIPfreeBufferArray(scip, &succarray); 5276 } 5277 5278 return SCIP_OKAY; 5279 } 5280 5281 5282 /** resets local conflict graph to the conflict graph of the root node */ 5283 static 5284 SCIP_RETCODE resetConflictgraphSOS1( 5285 SCIP_DIGRAPH* conflictgraph, /**< conflict graph of root node */ 5286 SCIP_DIGRAPH* localconflicts, /**< local conflicts that should be removed from conflict graph */ 5287 int nsos1vars /**< number of SOS1 variables */ 5288 ) 5289 { 5290 int j; 5291 5292 for (j = 0; j < nsos1vars; ++j) 5293 { 5294 int nsuccloc; 5295 5296 nsuccloc = SCIPdigraphGetNSuccessors(localconflicts, j); 5297 if ( nsuccloc > 0 ) 5298 { 5299 int* succloc; 5300 int* succ; 5301 int nsucc; 5302 int k = 0; 5303 5304 succloc = SCIPdigraphGetSuccessors(localconflicts, j); 5305 succ = SCIPdigraphGetSuccessors(conflictgraph, j); 5306 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j); 5307 5308 /* reset number of successors */ 5309 SCIPcomputeArraysSetminusInt(succ, nsucc, succloc, nsuccloc, succ, &k); 5310 SCIP_CALL( SCIPdigraphSetNSuccessors(conflictgraph, j, k) ); 5311 SCIP_CALL( SCIPdigraphSetNSuccessors(localconflicts, j, 0) ); 5312 } 5313 } 5314 5315 return SCIP_OKAY; 5316 } 5317 5318 5319 /** Conflict graph enforcement method 5320 * 5321 * The conflict graph can be enforced by different branching rules: 5322 * 5323 * - Branch on the neighborhood of a single variable @p i, i.e., in one branch \f$x_i\f$ is fixed to zero and in the 5324 * other its neighbors from the conflict graph. 5325 * 5326 * - Branch on complete bipartite subgraphs of the conflict graph, i.e., in one branch fix the variables from the first 5327 * bipartite partition and the variables from the second bipartite partition in the other. 5328 * 5329 * - In addition to variable domain fixings, it is sometimes also possible to add new SOS1 constraints to the branching 5330 * nodes. This results in a nonstatic conflict graph, which may change dynamically with every branching node. 5331 * 5332 * We make use of different selection rules that define on which system of SOS1 variables to branch next: 5333 * 5334 * - Most infeasible branching: Branch on the system of SOS1 variables with largest violation. 5335 * 5336 * - Strong branching: Here, the LP-relaxation is partially solved for each branching decision among a candidate list. 5337 * Then the decision with best progress is chosen. 5338 */ 5339 static 5340 SCIP_RETCODE enforceConflictgraph( 5341 SCIP* scip, /**< SCIP pointer */ 5342 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 5343 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 5344 int nconss, /**< number of constraints */ 5345 SCIP_CONS** conss, /**< SOS1 constraints */ 5346 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */ 5347 SCIP_RESULT* result /**< result */ 5348 ) 5349 { 5350 SCIP_DIGRAPH* conflictgraph; 5351 int nsos1vars; 5352 5353 SCIP_Bool* verticesarefixed = NULL; 5354 int* fixingsnode1 = NULL; 5355 int* fixingsnode2 = NULL; 5356 int nfixingsnode1; 5357 int nfixingsnode2; 5358 5359 SCIP_Real bestobjval1 = -SCIPinfinity(scip); 5360 SCIP_Real bestobjval2 = -SCIPinfinity(scip); 5361 SCIP_Real lpobjval = -SCIPinfinity(scip); 5362 5363 SCIP_Bool infeasible; 5364 SCIP_Bool bipbranch = FALSE; 5365 int nstrongrounds; 5366 5367 int branchvertex; 5368 SCIP_NODE* node1; 5369 SCIP_NODE* node2; 5370 SCIP_Real nodeselest; 5371 SCIP_Real objest; 5372 5373 int i; 5374 int j; 5375 int c; 5376 5377 assert( scip != NULL ); 5378 assert( conshdlrdata != NULL ); 5379 assert( conshdlr != NULL ); 5380 assert( conss != NULL ); 5381 assert( result != NULL ); 5382 5383 SCIPdebugMsg(scip, "Enforcing SOS1 conflict graph <%s>.\n", SCIPconshdlrGetName(conshdlr) ); 5384 *result = SCIP_DIDNOTRUN; 5385 5386 /* get number of SOS1 variables */ 5387 nsos1vars = conshdlrdata->nsos1vars; 5388 5389 /* exit for trivial cases */ 5390 if ( nsos1vars == 0 || nconss == 0 ) 5391 { 5392 *result = SCIP_FEASIBLE; 5393 return SCIP_OKAY; 5394 } 5395 5396 /* get conflict graph */ 5397 conflictgraph = conshdlrdata->conflictgraph; 5398 assert( ! conshdlrdata->isconflocal ); /* conflictgraph should be the one of the root node */ 5399 5400 /* check each constraint and update conflict graph if necessary */ 5401 for (c = 0; c < nconss; ++c) 5402 { 5403 SCIP_CONSDATA* consdata; 5404 SCIP_CONS* cons; 5405 SCIP_Bool cutoff; 5406 int ngen = 0; 5407 5408 cons = conss[c]; 5409 assert( cons != NULL ); 5410 consdata = SCIPconsGetData(cons); 5411 assert( consdata != NULL ); 5412 5413 /* do nothing if there are not enough variables - this is usually eliminated by preprocessing */ 5414 if ( consdata->nvars < 2 ) 5415 continue; 5416 5417 /* first perform propagation (it might happen that standard propagation is turned off) */ 5418 SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) ); 5419 SCIPdebugMsg(scip, "propagating <%s> in enforcing (cutoff: %u, domain reductions: %d).\n", SCIPconsGetName(cons), cutoff, ngen); 5420 if ( cutoff ) 5421 { 5422 *result = SCIP_CUTOFF; 5423 break; 5424 } 5425 if ( ngen > 0 ) 5426 { 5427 *result = SCIP_REDUCEDDOM; 5428 break; 5429 } 5430 assert( ngen == 0 ); 5431 5432 /* add local conflicts to conflict graph and save them in 'localconflicts' */ 5433 if ( consdata->local ) 5434 { 5435 SCIP_VAR** vars; 5436 int nvars; 5437 int indi; 5438 int indj; 5439 5440 if ( conshdlrdata->localconflicts == NULL ) 5441 { 5442 SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->localconflicts, nsos1vars) ); 5443 } 5444 5445 vars = consdata->vars; 5446 nvars = consdata->nvars; 5447 for (i = 0; i < nvars-1; ++i) 5448 { 5449 SCIP_VAR* var; 5450 5451 var = vars[i]; 5452 indi = varGetNodeSOS1(conshdlrdata, var); 5453 5454 if( indi == -1 ) 5455 return SCIP_INVALIDDATA; 5456 5457 if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) ) 5458 { 5459 for (j = i+1; j < nvars; ++j) 5460 { 5461 var = vars[j]; 5462 indj = varGetNodeSOS1(conshdlrdata, var); 5463 5464 if( indj == -1 ) 5465 return SCIP_INVALIDDATA; 5466 5467 if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) ) 5468 { 5469 if ( ! isConnectedSOS1(NULL, conflictgraph, indi, indj) ) 5470 { 5471 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, indi, indj, NULL) ); 5472 SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, indj, indi, NULL) ); 5473 5474 SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->localconflicts, indi, indj, NULL) ); 5475 SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->localconflicts, indj, indi, NULL) ); 5476 5477 conshdlrdata->isconflocal = TRUE; 5478 } 5479 } 5480 } 5481 } 5482 } 5483 } 5484 } 5485 5486 /* sort successor list of conflict graph if necessary */ 5487 if ( conshdlrdata->isconflocal ) 5488 { 5489 for (j = 0; j < nsos1vars; ++j) 5490 { 5491 int nsuccloc; 5492 5493 nsuccloc = SCIPdigraphGetNSuccessors(conshdlrdata->localconflicts, j); 5494 if ( nsuccloc > 0 ) 5495 { 5496 SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, j), SCIPdigraphGetNSuccessors(conflictgraph, j)); 5497 SCIPsortInt(SCIPdigraphGetSuccessors(conshdlrdata->localconflicts, j), nsuccloc); 5498 } 5499 } 5500 } 5501 5502 if ( *result == SCIP_CUTOFF || *result == SCIP_REDUCEDDOM ) 5503 { 5504 /* remove local conflicts from conflict graph */ 5505 if ( conshdlrdata->isconflocal ) 5506 { 5507 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) ); 5508 conshdlrdata->isconflocal = FALSE; 5509 } 5510 return SCIP_OKAY; 5511 } 5512 5513 /* detect fixed variables */ 5514 SCIP_CALL( SCIPallocBufferArray(scip, &verticesarefixed, nsos1vars) ); 5515 for (j = 0; j < nsos1vars; ++j) 5516 { 5517 SCIP_VAR* var; 5518 SCIP_Real ub; 5519 SCIP_Real lb; 5520 5521 var = SCIPnodeGetVarSOS1(conflictgraph, j); 5522 ub = SCIPvarGetUbLocal(var); 5523 lb = SCIPvarGetLbLocal(var); 5524 if ( SCIPisFeasZero(scip, ub) && SCIPisFeasZero(scip, lb) ) 5525 verticesarefixed[j] = TRUE; 5526 else 5527 verticesarefixed[j] = FALSE; 5528 } 5529 5530 /* should bipartite branching be used? */ 5531 if ( conshdlrdata->branchingrule == 'b' ) 5532 bipbranch = TRUE; 5533 5534 /* determine number of strong branching iterations */ 5535 if ( conshdlrdata->nstrongrounds >= 0 ) 5536 nstrongrounds = MIN(conshdlrdata->nstrongrounds, nsos1vars); 5537 else 5538 { 5539 /* determine number depending on depth, based on heuristical considerations */ 5540 if ( SCIPgetDepth(scip) <= 10 ) 5541 nstrongrounds = MAX(10, (int)SCIPfloor(scip, pow(log((SCIP_Real)nsos1vars), 1.0)));/*lint !e666*/ 5542 else if ( SCIPgetDepth(scip) <= 20 ) 5543 nstrongrounds = MAX(5, (int)SCIPfloor(scip, pow(log((SCIP_Real)nsos1vars), 0.7)));/*lint !e666*/ 5544 else 5545 nstrongrounds = 0; 5546 nstrongrounds = MIN(nsos1vars, nstrongrounds); 5547 } 5548 5549 /* allocate buffer arrays */ 5550 SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode1, nsos1vars) ); 5551 if ( bipbranch ) 5552 SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode2, nsos1vars) ); 5553 else 5554 SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode2, 1) ); 5555 5556 /* if strongbranching is turned off: use most infeasible branching */ 5557 if ( nstrongrounds == 0 ) 5558 { 5559 SCIP_Bool relsolfeas; 5560 5561 /* get branching vertex using most infeasible branching */ 5562 SCIP_CALL( getBranchingPrioritiesSOS1(scip, conshdlrdata, conflictgraph, sol, nsos1vars, verticesarefixed, 5563 bipbranch, fixingsnode1, fixingsnode2, NULL, &branchvertex, &relsolfeas) ); 5564 5565 /* if LP relaxation solution is feasible */ 5566 if ( relsolfeas ) 5567 { 5568 SCIPdebugMsg(scip, "all the SOS1 constraints are feasible.\n"); 5569 5570 /* update result */ 5571 *result = SCIP_FEASIBLE; 5572 5573 /* remove local conflicts from conflict graph */ 5574 if ( conshdlrdata->isconflocal ) 5575 { 5576 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) ); 5577 conshdlrdata->isconflocal = FALSE; 5578 } 5579 5580 /* free memory */ 5581 SCIPfreeBufferArrayNull(scip, &fixingsnode2); 5582 SCIPfreeBufferArrayNull(scip, &fixingsnode1); 5583 SCIPfreeBufferArrayNull(scip, &verticesarefixed); 5584 5585 return SCIP_OKAY; 5586 } 5587 } 5588 else 5589 { 5590 /* get branching vertex using strong branching */ 5591 SCIP_CALL( getBranchingDecisionStrongbranchSOS1(scip, conshdlrdata, conflictgraph, sol, nsos1vars, lpobjval, 5592 bipbranch, nstrongrounds, verticesarefixed, fixingsnode1, fixingsnode2, &branchvertex, &bestobjval1, 5593 &bestobjval2, result) ); 5594 5595 if ( *result == SCIP_CUTOFF || *result == SCIP_FEASIBLE || *result == SCIP_REDUCEDDOM ) 5596 { 5597 /* remove local conflicts from conflict graph */ 5598 if ( conshdlrdata->isconflocal ) 5599 { 5600 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) ); 5601 conshdlrdata->isconflocal = FALSE; 5602 } 5603 5604 /* free memory */ 5605 SCIPfreeBufferArrayNull(scip, &fixingsnode2); 5606 SCIPfreeBufferArrayNull(scip, &fixingsnode1); 5607 SCIPfreeBufferArrayNull(scip, &verticesarefixed); 5608 5609 return SCIP_OKAY; 5610 } 5611 } 5612 5613 /* if we should leave branching decision to branching rules */ 5614 if ( ! conshdlrdata->branchsos ) 5615 { 5616 /* remove local conflicts from conflict graph */ 5617 if ( conshdlrdata->isconflocal ) 5618 { 5619 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) ); 5620 conshdlrdata->isconflocal = FALSE; 5621 } 5622 5623 /* free memory */ 5624 SCIPfreeBufferArrayNull(scip, &fixingsnode2); 5625 SCIPfreeBufferArrayNull(scip, &fixingsnode1); 5626 SCIPfreeBufferArrayNull(scip, &verticesarefixed); 5627 5628 assert( branchvertex >= 0 && branchvertex < nsos1vars ); 5629 if ( SCIPvarIsBinary(SCIPnodeGetVarSOS1(conflictgraph, branchvertex)) ) 5630 { 5631 *result = SCIP_INFEASIBLE; 5632 return SCIP_OKAY; 5633 } 5634 else 5635 { 5636 SCIPerrorMessage("Incompatible parameter setting: branchsos can only be set to false if all SOS1 variables are binary.\n"); 5637 return SCIP_PARAMETERWRONGVAL; 5638 } 5639 } 5640 5641 /* create branching nodes */ 5642 5643 /* get vertices of variables that will be fixed to zero for each node */ 5644 assert( branchvertex >= 0 && branchvertex < nsos1vars ); 5645 assert( ! verticesarefixed[branchvertex] ); 5646 SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, sol, verticesarefixed, bipbranch, branchvertex, 5647 fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) ); 5648 5649 /* calculate node selection and objective estimate for node 1 */ 5650 nodeselest = 0.0; 5651 objest = SCIPgetLocalTransEstimate(scip); 5652 for (j = 0; j < nfixingsnode1; ++j) 5653 { 5654 SCIP_VAR* var; 5655 5656 var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]); 5657 objest += SCIPcalcChildEstimateIncrease(scip, var, SCIPgetSolVal(scip, sol, var), 0.0); 5658 nodeselest += SCIPcalcNodeselPriority(scip, var, SCIP_BRANCHDIR_DOWNWARDS, 0.0); 5659 } 5660 assert( objest >= SCIPgetLocalTransEstimate(scip) ); 5661 5662 /* create node 1 */ 5663 SCIP_CALL( SCIPcreateChild(scip, &node1, nodeselest, objest) ); 5664 5665 /* fix variables for the first node */ 5666 if ( conshdlrdata->fixnonzero && nfixingsnode2 == 1 ) 5667 { 5668 SCIP_VAR* var; 5669 SCIP_Real lb; 5670 SCIP_Real ub; 5671 5672 var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[0]); 5673 lb = SCIPvarGetLbLocal(var); 5674 ub = SCIPvarGetUbLocal(var); 5675 5676 if ( SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR ) 5677 { 5678 if ( SCIPisZero(scip, lb) ) 5679 { 5680 /* fix variable to some very small, but positive number or to 1.0 if variable is integral */ 5681 if (SCIPvarIsIntegral(var) ) 5682 { 5683 SCIP_CALL( SCIPchgVarLbNode(scip, node1, var, 1.0) ); 5684 } 5685 else 5686 { 5687 SCIP_CALL( SCIPchgVarLbNode(scip, node1, var, 1.5 * SCIPfeastol(scip)) ); 5688 } 5689 } 5690 else if ( SCIPisZero(scip, ub) ) 5691 { 5692 if (SCIPvarIsIntegral(var) ) 5693 { 5694 /* fix variable to some negative number with small absolute value to -1.0 if variable is integral */ 5695 SCIP_CALL( SCIPchgVarUbNode(scip, node1, var, -1.0) ); 5696 } 5697 else 5698 { 5699 /* fix variable to some negative number with small absolute value to -1.0 if variable is integral */ 5700 SCIP_CALL( SCIPchgVarUbNode(scip, node1, var, -1.5 * SCIPfeastol(scip)) ); 5701 } 5702 } 5703 } 5704 } 5705 5706 for (j = 0; j < nfixingsnode1; ++j) 5707 { 5708 /* fix variable to zero */ 5709 SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]), node1, &infeasible) ); 5710 assert( ! infeasible ); 5711 } 5712 5713 /* calculate node selection and objective estimate for node 2 */ 5714 nodeselest = 0.0; 5715 objest = SCIPgetLocalTransEstimate(scip); 5716 for (j = 0; j < nfixingsnode2; ++j) 5717 { 5718 SCIP_VAR* var; 5719 5720 var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]); 5721 objest += SCIPcalcChildEstimateIncrease(scip, var, SCIPgetSolVal(scip, sol, var), 0.0); 5722 nodeselest += SCIPcalcNodeselPriority(scip, var, SCIP_BRANCHDIR_DOWNWARDS, 0.0); 5723 } 5724 assert( objest >= SCIPgetLocalTransEstimate(scip) ); 5725 5726 /* create node 2 */ 5727 SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) ); 5728 5729 /* fix variables to zero */ 5730 for (j = 0; j < nfixingsnode2; ++j) 5731 { 5732 SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]), node2, &infeasible) ); 5733 assert( ! infeasible ); 5734 } 5735 5736 /* add complementarity constraints to the branching nodes */ 5737 if ( conshdlrdata->addcomps && ( conshdlrdata->addcompsdepth == -1 || conshdlrdata->addcompsdepth >= SCIPgetDepth(scip) ) ) 5738 { 5739 int naddedconss; 5740 5741 assert( ! conshdlrdata->fixnonzero ); 5742 5743 /* add complementarity constraints to the left branching node */ 5744 SCIP_CALL( addBranchingComplementaritiesSOS1(scip, node1, conshdlrdata, conflictgraph, conshdlrdata->localconflicts, sol, 5745 nsos1vars, verticesarefixed, fixingsnode1, nfixingsnode1, fixingsnode2, nfixingsnode2, &naddedconss, TRUE) ); 5746 5747 if ( naddedconss == 0 ) 5748 { 5749 /* add complementarity constraints to the right branching node */ 5750 SCIP_CALL( addBranchingComplementaritiesSOS1(scip, node2, conshdlrdata, conflictgraph, conshdlrdata->localconflicts, sol, 5751 nsos1vars, verticesarefixed, fixingsnode2, nfixingsnode2, fixingsnode1, nfixingsnode1, &naddedconss, TRUE) ); 5752 } 5753 } 5754 5755 /* sets node's lower bound to the best known value */ 5756 if ( nstrongrounds > 0 ) 5757 { 5758 SCIP_CALL( SCIPupdateNodeLowerbound(scip, node1, MAX(lpobjval, bestobjval1) ) ); 5759 SCIP_CALL( SCIPupdateNodeLowerbound(scip, node2, MAX(lpobjval, bestobjval2) ) ); 5760 } 5761 5762 /* remove local conflicts from conflict graph */ 5763 if ( conshdlrdata->isconflocal ) 5764 { 5765 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) ); 5766 conshdlrdata->isconflocal = FALSE; 5767 } 5768 5769 /* free buffer arrays */ 5770 SCIPfreeBufferArrayNull(scip, &fixingsnode2); 5771 SCIPfreeBufferArrayNull(scip, &fixingsnode1); 5772 SCIPfreeBufferArrayNull(scip, &verticesarefixed ); 5773 *result = SCIP_BRANCHED; 5774 5775 return SCIP_OKAY; 5776 } 5777 5778 5779 /** SOS1 branching enforcement method 5780 * 5781 * We check whether the current solution is feasible, i.e., contains at most one nonzero 5782 * variable. If not, we branch along the lines indicated by Beale and Tomlin: 5783 * 5784 * We first compute \f$W = \sum_{j=1}^n |x_i|\f$ and \f$w = \sum_{j=1}^n j\, |x_i|\f$. Then we 5785 * search for the index \f$k\f$ that satisfies 5786 * \f[ 5787 * k \leq \frac{w}{W} < k+1. 5788 * \f] 5789 * The branches are then 5790 * \f[ 5791 * x_1 = 0, \ldots, x_k = 0 \qquad \mbox{and}\qquad x_{k+1} = 0, \ldots, x_n = 0. 5792 * \f] 5793 * 5794 * If the constraint contains two variables, the branching of course simplifies. 5795 * 5796 * Depending on the parameters (@c branchnonzeros, @c branchweight) there are three ways to choose 5797 * the branching constraint. 5798 * 5799 * <TABLE> 5800 * <TR><TD>@c branchnonzeros</TD><TD>@c branchweight</TD><TD>constraint chosen</TD></TR> 5801 * <TR><TD>@c true </TD><TD> ? </TD><TD>most number of nonzeros</TD></TR> 5802 * <TR><TD>@c false </TD><TD> @c true </TD><TD>maximal weight corresponding to nonzero variable</TD></TR> 5803 * <TR><TD>@c false </TD><TD> @c true </TD><TD>largest sum of variable values</TD></TR> 5804 * </TABLE> 5805 * 5806 * @c branchnonzeros = @c false, @c branchweight = @c true allows the user to specify an order for 5807 * the branching importance of the constraints (setting the weights accordingly). 5808 * 5809 * Constraint branching can also be turned off using parameter @c branchsos. 5810 */ 5811 static 5812 SCIP_RETCODE enforceConssSOS1( 5813 SCIP* scip, /**< SCIP pointer */ 5814 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 5815 int nconss, /**< number of constraints */ 5816 SCIP_CONS** conss, /**< indicator constraints */ 5817 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */ 5818 SCIP_RESULT* result /**< result */ 5819 ) 5820 { 5821 SCIP_CONSHDLRDATA* conshdlrdata; 5822 SCIP_CONSDATA* consdata; 5823 SCIP_NODE* node1; 5824 SCIP_NODE* node2; 5825 SCIP_CONS* branchCons; 5826 SCIP_Real maxWeight; 5827 SCIP_VAR** vars; 5828 int nvars; 5829 int c; 5830 5831 assert( scip != NULL ); 5832 assert( conshdlr != NULL ); 5833 assert( conss != NULL ); 5834 assert( result != NULL ); 5835 5836 maxWeight = -SCIP_REAL_MAX; 5837 branchCons = NULL; 5838 5839 SCIPdebugMsg(scip, "Enforcing SOS1 constraints <%s>.\n", SCIPconshdlrGetName(conshdlr) ); 5840 *result = SCIP_FEASIBLE; 5841 5842 /* get constraint handler data */ 5843 conshdlrdata = SCIPconshdlrGetData(conshdlr); 5844 assert( conshdlrdata != NULL ); 5845 5846 /* check each constraint */ 5847 for (c = 0; c < nconss; ++c) 5848 { 5849 SCIP_CONS* cons; 5850 SCIP_Bool cutoff; 5851 SCIP_Real weight; 5852 int ngen; 5853 int cnt; 5854 int j; 5855 5856 cons = conss[c]; 5857 assert( cons != NULL ); 5858 consdata = SCIPconsGetData(cons); 5859 assert( consdata != NULL ); 5860 5861 ngen = 0; 5862 cnt = 0; 5863 nvars = consdata->nvars; 5864 vars = consdata->vars; 5865 5866 /* do nothing if there are not enough variables - this is usually eliminated by preprocessing */ 5867 if ( nvars < 2 ) 5868 continue; 5869 5870 /* first perform propagation (it might happen that standard propagation is turned off) */ 5871 SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) ); 5872 SCIPdebugMsg(scip, "propagating <%s> in enforcing (cutoff: %u, domain reductions: %d).\n", SCIPconsGetName(cons), cutoff, ngen); 5873 if ( cutoff ) 5874 { 5875 *result = SCIP_CUTOFF; 5876 return SCIP_OKAY; 5877 } 5878 if ( ngen > 0 ) 5879 { 5880 *result = SCIP_REDUCEDDOM; 5881 return SCIP_OKAY; 5882 } 5883 assert( ngen == 0 ); 5884 5885 /* check constraint */ 5886 weight = 0.0; 5887 for (j = 0; j < nvars; ++j) 5888 { 5889 SCIP_Real val = REALABS(SCIPgetSolVal(scip, sol, vars[j])); 5890 5891 if ( ! SCIPisFeasZero(scip, val) ) 5892 { 5893 if ( conshdlrdata->branchnonzeros ) 5894 weight += 1.0; 5895 else 5896 { 5897 if ( conshdlrdata->branchweight && consdata->weights != NULL ) 5898 { 5899 /* choose maximum nonzero-variable weight */ 5900 if ( consdata->weights[j] > weight ) 5901 weight = consdata->weights[j]; 5902 } 5903 else 5904 weight += val; 5905 } 5906 ++cnt; 5907 } 5908 } 5909 /* if constraint is violated */ 5910 if ( cnt > 1 && weight > maxWeight ) 5911 { 5912 maxWeight = weight; 5913 branchCons = cons; 5914 } 5915 } 5916 5917 /* if all constraints are feasible */ 5918 if ( branchCons == NULL ) 5919 { 5920 SCIPdebugMsg(scip, "All SOS1 constraints are feasible.\n"); 5921 return SCIP_OKAY; 5922 } 5923 5924 /* if we should leave branching decision to branching rules */ 5925 if ( ! conshdlrdata->branchsos ) 5926 { 5927 int j; 5928 5929 consdata = SCIPconsGetData(branchCons); 5930 for (j = 0; j < consdata->nvars; ++j) 5931 { 5932 if ( ! SCIPvarIsBinary(consdata->vars[j]) ) 5933 break; 5934 } 5935 5936 if ( j == consdata->nvars ) 5937 { 5938 *result = SCIP_INFEASIBLE; 5939 return SCIP_OKAY; 5940 } 5941 else 5942 { 5943 SCIPerrorMessage("Incompatible parameter setting: branchsos can only be set to false if all SOS1 variables are binary.\n"); 5944 return SCIP_PARAMETERWRONGVAL; 5945 } 5946 } 5947 5948 /* otherwise create branches */ 5949 SCIPdebugMsg(scip, "Branching on constraint <%s> (weight: %f).\n", SCIPconsGetName(branchCons), maxWeight); 5950 consdata = SCIPconsGetData(branchCons); 5951 assert( consdata != NULL ); 5952 nvars = consdata->nvars; 5953 vars = consdata->vars; 5954 5955 if ( nvars == 2 ) 5956 { 5957 SCIP_Bool infeasible; 5958 5959 /* constraint is infeasible: */ 5960 assert( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, vars[0])) && ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, vars[1])) ); 5961 5962 /* create branches */ 5963 SCIPdebugMsg(scip, "Creating two branches.\n"); 5964 5965 SCIP_CALL( SCIPcreateChild(scip, &node1, SCIPcalcNodeselPriority(scip, vars[0], SCIP_BRANCHDIR_DOWNWARDS, 0.0), SCIPcalcChildEstimate(scip, vars[0], 0.0) ) ); 5966 SCIP_CALL( fixVariableZeroNode(scip, vars[0], node1, &infeasible) ); 5967 assert( ! infeasible ); 5968 5969 SCIP_CALL( SCIPcreateChild(scip, &node2, SCIPcalcNodeselPriority(scip, vars[1], SCIP_BRANCHDIR_DOWNWARDS, 0.0), SCIPcalcChildEstimate(scip, vars[1], 0.0) ) ); 5970 SCIP_CALL( fixVariableZeroNode(scip, vars[1], node2, &infeasible) ); 5971 assert( ! infeasible ); 5972 } 5973 else 5974 { 5975 SCIP_Bool infeasible; 5976 SCIP_Real weight1; 5977 SCIP_Real weight2; 5978 SCIP_Real nodeselest; 5979 SCIP_Real objest; 5980 SCIP_Real w; 5981 int j; 5982 int ind; 5983 #ifndef NDEBUG 5984 int cnt = 0; 5985 #endif 5986 5987 weight1 = 0.0; 5988 weight2 = 0.0; 5989 5990 /* compute weight */ 5991 for (j = 0; j < nvars; ++j) 5992 { 5993 SCIP_Real val = REALABS(SCIPgetSolVal(scip, sol, vars[j])); 5994 weight1 += val * (SCIP_Real) j; 5995 weight2 += val; 5996 5997 #ifndef NDEBUG 5998 if ( ! SCIPisFeasZero(scip, val) ) 5999 ++cnt; 6000 #endif 6001 } 6002 6003 assert( cnt >= 2 ); 6004 assert( !SCIPisFeasZero(scip, weight2) ); 6005 w = weight1/weight2; /*lint !e795*/ 6006 6007 ind = (int) SCIPfloor(scip, w); 6008 assert( 0 <= ind && ind < nvars-1 ); 6009 6010 /* branch on variable ind: either all variables up to ind or all variables after ind are zero */ 6011 SCIPdebugMsg(scip, "Branching on variable <%s>.\n", SCIPvarGetName(vars[ind])); 6012 6013 /* calculate node selection and objective estimate for node 1 */ 6014 nodeselest = 0.0; 6015 objest = SCIPgetLocalTransEstimate(scip); 6016 for (j = 0; j <= ind; ++j) 6017 { 6018 objest += SCIPcalcChildEstimateIncrease(scip, vars[j], SCIPgetSolVal(scip, sol, vars[j]), 0.0); 6019 nodeselest += SCIPcalcNodeselPriority(scip, vars[j], SCIP_BRANCHDIR_DOWNWARDS, 0.0); 6020 } 6021 assert( objest >= SCIPgetLocalTransEstimate(scip) ); 6022 6023 /* create node 1 */ 6024 SCIP_CALL( SCIPcreateChild(scip, &node1, nodeselest, objest) ); 6025 for (j = 0; j <= ind; ++j) 6026 { 6027 SCIP_CALL( fixVariableZeroNode(scip, vars[j], node1, &infeasible) ); 6028 assert( ! infeasible ); 6029 } 6030 6031 /* calculate node selection and objective estimate for node 1 */ 6032 nodeselest = 0.0; 6033 objest = SCIPgetLocalTransEstimate(scip); 6034 for (j = ind+1; j < nvars; ++j) 6035 { 6036 objest += SCIPcalcChildEstimateIncrease(scip, vars[j], SCIPgetSolVal(scip, sol, vars[j]), 0.0); 6037 nodeselest += SCIPcalcNodeselPriority(scip, vars[j], SCIP_BRANCHDIR_DOWNWARDS, 0.0); 6038 } 6039 assert( objest >= SCIPgetLocalTransEstimate(scip) ); 6040 6041 /* create node 2 */ 6042 SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) ); 6043 for (j = ind+1; j < nvars; ++j) 6044 { 6045 SCIP_CALL( fixVariableZeroNode(scip, vars[j], node2, &infeasible) ); 6046 assert( ! infeasible ); 6047 } 6048 } 6049 SCIP_CALL( SCIPresetConsAge(scip, branchCons) ); 6050 *result = SCIP_BRANCHED; 6051 6052 return SCIP_OKAY; 6053 } 6054 6055 6056 /** constraint enforcing method of constraint handler */ 6057 static 6058 SCIP_RETCODE enforceSOS1( 6059 SCIP* scip, /**< SCIP pointer */ 6060 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 6061 int nconss, /**< number of constraints */ 6062 SCIP_CONS** conss, /**< indicator constraints */ 6063 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */ 6064 SCIP_RESULT* result /**< result */ 6065 ) 6066 { 6067 SCIP_CONSHDLRDATA* conshdlrdata; 6068 6069 assert( scip != NULL ); 6070 assert( conshdlr != NULL ); 6071 assert( conss != NULL ); 6072 assert( result != NULL ); 6073 6074 /* get constraint handler data */ 6075 conshdlrdata = SCIPconshdlrGetData(conshdlr); 6076 assert( conshdlrdata != NULL ); 6077 6078 if ( conshdlrdata->addcomps && conshdlrdata->fixnonzero ) 6079 { 6080 SCIPerrorMessage("Incompatible parameter setting: addcomps = TRUE and fixnonzero = TRUE.\n"); 6081 return SCIP_PARAMETERWRONGVAL; 6082 } 6083 6084 if ( conshdlrdata->fixnonzero && ( conshdlrdata->branchingrule == 'b' || conshdlrdata->branchingrule == 's' ) ) 6085 { 6086 SCIPerrorMessage("Incompatible parameter setting: nonzero fixing is not compatible with bipartite or sos1 branching.\n"); 6087 return SCIP_PARAMETERWRONGVAL; 6088 } 6089 6090 if ( conshdlrdata->branchingrule == 's' && conshdlrdata->nstrongrounds != 0 ) 6091 { 6092 SCIPerrorMessage("Strong branching is not available for SOS1 branching.\n"); 6093 return SCIP_PARAMETERWRONGVAL; 6094 } 6095 6096 if ( conshdlrdata->branchingrule == 's' || conshdlrdata->switchsos1branch ) 6097 { 6098 /* enforce SOS1 constraints */ 6099 SCIP_CALL( enforceConssSOS1(scip, conshdlr, nconss, conss, sol, result) ); 6100 } 6101 else 6102 { 6103 if ( conshdlrdata->branchingrule != 'n' && conshdlrdata->branchingrule != 'b' ) 6104 { 6105 SCIPerrorMessage("branching rule %c unknown\n", conshdlrdata->branchingrule); 6106 return SCIP_PARAMETERWRONGVAL; 6107 } 6108 6109 /* enforce conflict graph */ 6110 SCIP_CALL( enforceConflictgraph(scip, conshdlrdata, conshdlr, nconss, conss, sol, result) ); 6111 } 6112 6113 return SCIP_OKAY; 6114 } 6115 6116 6117 /* ----------------------------- separation ------------------------------------*/ 6118 6119 /** initialitze tclique graph and create clique data */ 6120 static 6121 SCIP_RETCODE initTCliquegraph( 6122 SCIP* scip, /**< SCIP pointer */ 6123 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 6124 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 6125 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 6126 int nsos1vars /**< number of SOS1 variables */ 6127 ) 6128 { 6129 TCLIQUE_DATA* tcliquedata; 6130 int j; 6131 6132 /* try to generate bound cuts */ 6133 if ( ! tcliqueCreate(&conshdlrdata->tcliquegraph) ) 6134 return SCIP_NOMEMORY; 6135 6136 /* add nodes */ 6137 for (j = 0; j < nsos1vars; ++j) 6138 { 6139 if ( ! tcliqueAddNode(conshdlrdata->tcliquegraph, j, 0 ) ) 6140 return SCIP_NOMEMORY; 6141 } 6142 6143 /* add edges */ 6144 for (j = 0; j < nsos1vars; ++j) 6145 { 6146 int* succ; 6147 int nsucc; 6148 int succnode; 6149 int i; 6150 6151 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j); 6152 succ = SCIPdigraphGetSuccessors(conflictgraph, j); 6153 6154 for (i = 0; i < nsucc; ++i) 6155 { 6156 succnode = succ[i]; 6157 6158 if ( succnode > j && SCIPvarIsActive(SCIPnodeGetVarSOS1(conflictgraph, succnode)) ) 6159 { 6160 if ( ! tcliqueAddEdge(conshdlrdata->tcliquegraph, j, succnode) ) 6161 return SCIP_NOMEMORY; 6162 } 6163 } 6164 } 6165 6166 if ( ! tcliqueFlush(conshdlrdata->tcliquegraph) ) 6167 return SCIP_NOMEMORY; 6168 6169 /* allocate clique data */ 6170 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata->tcliquedata) ); 6171 tcliquedata = conshdlrdata->tcliquedata; 6172 6173 /* initialize clique data */ 6174 tcliquedata->scip = scip; 6175 tcliquedata->sol = NULL; 6176 tcliquedata->conshdlr = conshdlr; 6177 tcliquedata->conflictgraph = conflictgraph; 6178 tcliquedata->scaleval = 1000.0; 6179 tcliquedata->ncuts = 0; 6180 tcliquedata->nboundcuts = conshdlrdata->nboundcuts; 6181 tcliquedata->strthenboundcuts = conshdlrdata->strthenboundcuts; 6182 tcliquedata->maxboundcuts = conshdlrdata->maxboundcutsroot; 6183 6184 return SCIP_OKAY; 6185 } 6186 6187 6188 /** update weights of tclique graph */ 6189 static 6190 SCIP_RETCODE updateWeightsTCliquegraph( 6191 SCIP* scip, /**< SCIP pointer */ 6192 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 6193 TCLIQUE_DATA* tcliquedata, /**< tclique data */ 6194 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 6195 SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */ 6196 int nsos1vars /**< number of SOS1 variables */ 6197 ) 6198 { 6199 SCIP_Real scaleval; 6200 int j; 6201 6202 scaleval = tcliquedata->scaleval; 6203 6204 for (j = 0; j < nsos1vars; ++j) 6205 { 6206 SCIP_Real solval; 6207 SCIP_Real bound; 6208 SCIP_VAR* var; 6209 6210 var = SCIPnodeGetVarSOS1(conflictgraph, j); 6211 solval = SCIPgetSolVal(scip, sol, var); 6212 6213 if ( SCIPisFeasPositive(scip, solval) ) 6214 { 6215 if ( conshdlrdata->strthenboundcuts ) 6216 bound = REALABS( nodeGetSolvalVarboundUbSOS1(scip, conflictgraph, sol, j) ); 6217 else 6218 bound = REALABS( SCIPvarGetUbLocal(var) ); 6219 } 6220 else if ( SCIPisFeasNegative(scip, solval) ) 6221 { 6222 if ( conshdlrdata->strthenboundcuts ) 6223 bound = REALABS( nodeGetSolvalVarboundLbSOS1(scip, conflictgraph, sol, j) ); 6224 else 6225 bound = REALABS( SCIPvarGetLbLocal(var) ); 6226 } 6227 else 6228 bound = 0.0; 6229 6230 solval = REALABS( solval ); 6231 6232 if ( ! SCIPisFeasZero(scip, bound) && ! SCIPisInfinity(scip, bound) ) 6233 { 6234 SCIP_Real nodeweight; 6235 nodeweight = REALABS( solval/bound ) * scaleval;/*lint !e414*/ 6236 tcliqueChangeWeight(conshdlrdata->tcliquegraph, j, (int)nodeweight); 6237 } 6238 else 6239 { 6240 tcliqueChangeWeight(conshdlrdata->tcliquegraph, j, 0); 6241 } 6242 } 6243 6244 return SCIP_OKAY; 6245 } 6246 6247 6248 /** adds bound cut(s) to separation storage */ 6249 static 6250 SCIP_RETCODE addBoundCutSepa( 6251 SCIP* scip, /**< SCIP pointer */ 6252 TCLIQUE_DATA* tcliquedata, /**< clique data */ 6253 SCIP_ROW* rowlb, /**< row for lower bounds (or NULL) */ 6254 SCIP_ROW* rowub, /**< row for upper bounds (or NULL) */ 6255 SCIP_Bool* success, /**< pointer to store if bound cut was added */ 6256 SCIP_Bool* cutoff /**< pointer to store if a cutoff occurred */ 6257 ) 6258 { 6259 assert( scip != NULL ); 6260 assert( tcliquedata != NULL ); 6261 assert( success != NULL); 6262 assert( cutoff != NULL ); 6263 6264 *success = FALSE; 6265 *cutoff = FALSE; 6266 6267 /* add cut for lower bounds */ 6268 if ( rowlb != NULL ) 6269 { 6270 if ( ! SCIProwIsInLP(rowlb) && SCIPisCutEfficacious(scip, NULL, rowlb) ) 6271 { 6272 SCIP_Bool infeasible; 6273 6274 SCIP_CALL( SCIPaddRow(scip, rowlb, FALSE, &infeasible) ); 6275 if ( infeasible ) 6276 *cutoff = TRUE; 6277 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowlb, NULL) ) ); 6278 ++tcliquedata->nboundcuts; 6279 ++tcliquedata->ncuts; 6280 *success = TRUE; 6281 } 6282 } 6283 6284 /* add cut for upper bounds */ 6285 if ( rowub != NULL ) 6286 { 6287 if ( ! SCIProwIsInLP(rowub) && SCIPisCutEfficacious(scip, NULL, rowub) ) 6288 { 6289 SCIP_Bool infeasible; 6290 6291 SCIP_CALL( SCIPaddRow(scip, rowub, FALSE, &infeasible) ); 6292 if ( infeasible ) 6293 *cutoff = TRUE; 6294 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowub, NULL) ) ); 6295 ++tcliquedata->nboundcuts; 6296 ++tcliquedata->ncuts; 6297 *success = TRUE; 6298 } 6299 } 6300 6301 return SCIP_OKAY; 6302 } 6303 6304 6305 /** Generate bound constraint 6306 * 6307 * We generate the row corresponding to the following simple valid inequalities: 6308 * \f[ 6309 * \frac{x_1}{u_1} + \ldots + \frac{x_n}{u_n} \leq 1\qquad\mbox{and}\qquad 6310 * \frac{x_1}{\ell_1} + \ldots + \frac{x_n}{\ell_1} \leq 1, 6311 * \f] 6312 * where \f$\ell_1, \ldots, \ell_n\f$ and \f$u_1, \ldots, u_n\f$ are the nonzero and finite lower and upper bounds of 6313 * the variables \f$x_1, \ldots, x_n\f$. If an upper bound < 0 or a lower bound > 0, the constraint itself is 6314 * redundant, so the cut is not applied (lower bounds > 0 and upper bounds < 0 are usually detected in presolving or 6315 * propagation). Infinite bounds and zero are skipped. Thus \f$\ell_1, \ldots, \ell_n\f$ are all negative, which 6316 * results in the \f$\leq\f$ inequality. In case of the presence of variable upper bounds, the bound inequality can 6317 * be further strengthened. 6318 * 6319 * Note that in fact, any mixture of nonzero finite lower and upper bounds would lead to a valid inequality as 6320 * above. However, usually either the lower or upper bound is nonzero. Thus, the above inequalities are the most 6321 * interesting. 6322 */ 6323 static 6324 SCIP_RETCODE generateBoundInequalityFromSOS1Nodes( 6325 SCIP* scip, /**< SCIP pointer */ 6326 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 6327 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 6328 int* nodes, /**< conflict graph nodes for bound constraint */ 6329 int nnodes, /**< number of conflict graph nodes for bound constraint */ 6330 SCIP_Real rhs, /**< right hand side of bound constraint */ 6331 SCIP_Bool local, /**< in any case produce a local cut (even if local bounds of variables are valid globally) */ 6332 SCIP_Bool global, /**< in any case produce a global cut */ 6333 SCIP_Bool strengthen, /**< whether trying to strengthen bound constraint */ 6334 SCIP_Bool removable, /**< should the inequality be removed from the LP due to aging or cleanup? */ 6335 const char* nameext, /**< part of name of bound constraints */ 6336 SCIP_ROW** rowlb, /**< output: row for lower bounds (or NULL if not needed) */ 6337 SCIP_ROW** rowub /**< output: row for upper bounds (or NULL if not needed) */ 6338 ) 6339 { 6340 char name[SCIP_MAXSTRLEN]; 6341 SCIP_VAR* lbboundvar = NULL; 6342 SCIP_VAR* ubboundvar = NULL; 6343 SCIP_Bool locallbs; 6344 SCIP_Bool localubs; 6345 SCIP_VAR** vars; 6346 SCIP_Real* vals; 6347 6348 assert( scip != NULL ); 6349 assert( conshdlr != NULL ); 6350 assert( conflictgraph != NULL ); 6351 assert( ! local || ! global ); 6352 assert( nodes != NULL ); 6353 6354 /* allocate buffer array */ 6355 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nnodes+1) ); 6356 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nnodes+1) ); 6357 6358 /* take care of upper bounds */ 6359 if ( rowub != NULL ) 6360 { 6361 SCIP_Bool useboundvar; 6362 int cnt = 0; 6363 int j; 6364 6365 /* Loop through all variables. We check whether all bound variables (if existent) are equal; if this is the 6366 * case then the bound constraint can be strengthened */ 6367 localubs = local; 6368 useboundvar = strengthen; 6369 for (j = 0; j < nnodes; ++j) 6370 { 6371 SCIP_NODEDATA* nodedata; 6372 SCIP_VAR* var; 6373 SCIP_Real val; 6374 6375 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, nodes[j]); 6376 assert( nodedata != NULL ); 6377 var = nodedata->var; 6378 assert( var != NULL ); 6379 6380 /* if variable is not involved in a variable bound constraint */ 6381 if ( ! useboundvar || nodedata->ubboundvar == NULL ) 6382 { 6383 useboundvar = FALSE; 6384 if ( localubs ) 6385 { 6386 assert( ! global ); 6387 val = SCIPvarGetUbLocal(var); 6388 } 6389 else 6390 { 6391 val = SCIPvarGetUbGlobal(var); 6392 if ( ! global && ! SCIPisFeasEQ(scip, val, SCIPvarGetUbLocal(var)) ) 6393 { 6394 localubs = TRUE; 6395 val = SCIPvarGetUbLocal(var); 6396 } 6397 } 6398 } 6399 else 6400 { 6401 /* in this case the cut is always valid globally */ 6402 6403 /* if we have a bound variable for the first time */ 6404 if ( ubboundvar == NULL ) 6405 { 6406 ubboundvar = nodedata->ubboundvar; 6407 val = nodedata->ubboundcoef; 6408 } 6409 /* else if the bound variable equals the stored bound variable */ 6410 else if ( ubboundvar == nodedata->ubboundvar ) 6411 val = nodedata->ubboundcoef; 6412 else /* else use bounds on the variables */ 6413 { 6414 useboundvar = FALSE; 6415 6416 /* restart 'for'-loop */ 6417 j = -1; /*lint !e850*/ 6418 cnt = 0; 6419 continue; 6420 } 6421 } 6422 6423 /* should not apply the cut if a variable is fixed to be negative -> constraint is redundant */ 6424 if ( SCIPisNegative(scip, val) ) 6425 break; 6426 6427 /* store variable if relevant for bound inequality */ 6428 if ( ! SCIPisInfinity(scip, val) && ! SCIPisZero(scip, val) ) 6429 { 6430 vars[cnt] = var; 6431 6432 /* if only two nodes then we scale the cut differently */ 6433 if ( nnodes == 2 ) 6434 vals[cnt++] = val; 6435 else 6436 vals[cnt++] = 1.0/val; 6437 } 6438 } 6439 6440 /* if cut is meaningful */ 6441 if ( j == nnodes && cnt >= 2 )/*lint !e850*/ 6442 { 6443 /* if only two nodes then we scale the cut differently */ 6444 if ( nnodes == 2 ) 6445 { 6446 SCIP_Real save; 6447 6448 save = vals[0]; 6449 vals[0] = vals[1]; 6450 vals[1] = save; 6451 rhs = rhs * vals[0] * vals[1]; 6452 assert( (! useboundvar && cnt == 2 ) || (useboundvar && cnt == 3 ) ); 6453 } 6454 6455 if ( useboundvar ) 6456 { 6457 /* add bound variable to array */ 6458 vars[cnt] = ubboundvar; 6459 vals[cnt++] = -rhs; 6460 assert(ubboundvar != NULL ); 6461 6462 /* create upper bound inequality if at least two of the bounds are finite and nonzero */ 6463 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sosub#%s", nameext); 6464 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowub, conshdlr, name, -SCIPinfinity(scip), 0.0, localubs, FALSE, removable) ); 6465 SCIP_CALL( SCIPaddVarsToRow(scip, *rowub, cnt, vars, vals) ); 6466 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowub, NULL) ) ); 6467 } 6468 else 6469 { 6470 /* create upper bound inequality if at least two of the bounds are finite and nonzero */ 6471 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sosub#%s", nameext); 6472 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowub, conshdlr, name, -SCIPinfinity(scip), rhs, localubs, FALSE, removable) ); 6473 SCIP_CALL( SCIPaddVarsToRow(scip, *rowub, cnt, vars, vals) ); 6474 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowub, NULL) ) ); 6475 } 6476 } 6477 } 6478 6479 /* take care of lower bounds */ 6480 if ( rowlb != NULL ) 6481 { 6482 SCIP_Bool useboundvar; 6483 int cnt = 0; 6484 int j; 6485 6486 /* loop through all variables. We check whether all bound variables (if existent) are equal; if this is the 6487 * case then the bound constraint can be strengthened */ 6488 locallbs = local; 6489 useboundvar = strengthen; 6490 for (j = 0; j < nnodes; ++j) 6491 { 6492 SCIP_NODEDATA* nodedata; 6493 SCIP_VAR* var; 6494 SCIP_Real val; 6495 6496 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, nodes[j]); 6497 assert( nodedata != NULL ); 6498 var = nodedata->var; 6499 assert( var != NULL ); 6500 6501 /* if variable is not involved in a variable bound constraint */ 6502 if ( ! useboundvar || nodedata->lbboundvar == NULL ) 6503 { 6504 useboundvar = FALSE; 6505 if ( locallbs ) 6506 { 6507 assert( ! global ); 6508 val = SCIPvarGetLbLocal(var); 6509 } 6510 else 6511 { 6512 val = SCIPvarGetLbGlobal(var); 6513 if ( ! global && ! SCIPisFeasEQ(scip, val, SCIPvarGetLbLocal(var)) ) 6514 { 6515 locallbs = TRUE; 6516 val = SCIPvarGetLbLocal(var); 6517 } 6518 } 6519 } 6520 else 6521 { 6522 /* in this case the cut is always valid globally */ 6523 6524 /* if we have a bound variable for the first time */ 6525 if ( lbboundvar == NULL ) 6526 { 6527 lbboundvar = nodedata->lbboundvar; 6528 val = nodedata->lbboundcoef; 6529 } 6530 /* else if the bound variable equals the stored bound variable */ 6531 else if ( SCIPvarCompare(lbboundvar, nodedata->lbboundvar) == 0 ) 6532 { 6533 val = nodedata->lbboundcoef; 6534 } 6535 else /* else use bounds on the variables */ 6536 { 6537 useboundvar = FALSE; 6538 6539 /* restart 'for'-loop */ 6540 j = -1; /*lint !e850*/ 6541 cnt = 0; 6542 continue; 6543 } 6544 } 6545 6546 /* should not apply the cut if a variable is fixed to be positive -> constraint is redundant */ 6547 if ( SCIPisPositive(scip, val) ) 6548 break; 6549 6550 /* store variable if relevant for bound inequality */ 6551 if ( ! SCIPisInfinity(scip, -val) && ! SCIPisZero(scip, val) ) 6552 { 6553 vars[cnt] = var; 6554 6555 /* if only two nodes then we scale the cut differently */ 6556 if ( nnodes == 2 ) 6557 vals[cnt++] = val; 6558 else 6559 vals[cnt++] = 1.0/val; 6560 } 6561 } 6562 6563 /* if cut is meaningful */ 6564 if ( j == nnodes && cnt >= 2 )/*lint !e850*/ 6565 { 6566 /* if only two nodes then we scale the cut differently */ 6567 if ( nnodes == 2 ) 6568 { 6569 SCIP_Real save; 6570 6571 save = vals[0]; 6572 vals[0] = vals[1]; 6573 vals[1] = save; 6574 rhs = rhs * vals[0] * vals[1]; 6575 assert( (! useboundvar && cnt == 2 ) || (useboundvar && cnt == 3 ) ); 6576 } 6577 6578 if ( useboundvar ) 6579 { 6580 /* add bound variable to array */ 6581 vars[cnt] = lbboundvar; 6582 vals[cnt++] = -rhs; 6583 assert(lbboundvar != NULL ); 6584 6585 /* create upper bound inequality if at least two of the bounds are finite and nonzero */ 6586 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "soslb#%s", nameext); 6587 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowlb, conshdlr, name, -SCIPinfinity(scip), 0.0, locallbs, FALSE, TRUE) ); 6588 SCIP_CALL( SCIPaddVarsToRow(scip, *rowlb, cnt, vars, vals) ); 6589 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowlb, NULL) ) ); 6590 } 6591 else 6592 { 6593 /* create upper bound inequality if at least two of the bounds are finite and nonzero */ 6594 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "soslb#%s", nameext); 6595 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowlb, conshdlr, name, -SCIPinfinity(scip), rhs, locallbs, FALSE, TRUE) ); 6596 SCIP_CALL( SCIPaddVarsToRow(scip, *rowlb, cnt, vars, vals) ); 6597 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowlb, NULL) ) ); 6598 } 6599 } 6600 } 6601 6602 /* free buffer array */ 6603 SCIPfreeBufferArray(scip, &vals); 6604 SCIPfreeBufferArray(scip, &vars); 6605 6606 return SCIP_OKAY; 6607 } 6608 6609 6610 /** generates bound cuts using a clique found by algorithm for maximum weight clique 6611 * and decides whether to stop generating cliques with the algorithm for maximum weight clique 6612 */ 6613 static 6614 TCLIQUE_NEWSOL(tcliqueNewsolClique) 6615 { 6616 TCLIQUE_WEIGHT minweightinc; 6617 6618 assert( acceptsol != NULL ); 6619 assert( stopsolving != NULL ); 6620 assert( tcliquedata != NULL ); 6621 6622 /* we don't accept the solution as new incumbent, because we want to find many violated clique inequalities */ 6623 *acceptsol = FALSE; 6624 *stopsolving = FALSE; 6625 6626 /* slightly increase the minimal weight for additional cliques */ 6627 minweightinc = (cliqueweight - *minweight)/10; 6628 minweightinc = MAX(minweightinc, 1); 6629 *minweight += minweightinc; 6630 6631 /* adds cut if weight of the clique is greater than 1 */ 6632 if( cliqueweight > tcliquedata->scaleval ) 6633 { 6634 SCIP* scip; 6635 SCIP_SOL* sol; 6636 SCIP_Real unscaledweight; 6637 SCIP_Real solval; 6638 SCIP_Real bound; 6639 SCIP_VAR* var; 6640 int node; 6641 int i; 6642 6643 scip = tcliquedata->scip; 6644 sol = tcliquedata->sol; 6645 assert( scip != NULL ); 6646 6647 /* calculate the weight of the clique in unscaled fractional variable space */ 6648 unscaledweight = 0.0; 6649 for( i = 0; i < ncliquenodes; i++ ) 6650 { 6651 node = cliquenodes[i]; 6652 var = SCIPnodeGetVarSOS1(tcliquedata->conflictgraph, node); 6653 solval = SCIPgetSolVal(scip, sol, var); 6654 6655 if ( SCIPisFeasPositive(scip, solval) ) 6656 { 6657 if ( tcliquedata->strthenboundcuts ) 6658 bound = REALABS( nodeGetSolvalVarboundUbSOS1(scip, tcliquedata->conflictgraph, sol, node) ); 6659 else 6660 bound = REALABS( SCIPvarGetUbLocal(var) ); 6661 } 6662 else if ( SCIPisFeasNegative(scip, solval) ) 6663 { 6664 if ( tcliquedata->strthenboundcuts ) 6665 bound = REALABS( nodeGetSolvalVarboundLbSOS1(scip, tcliquedata->conflictgraph, sol, node) ); 6666 else 6667 bound = REALABS( SCIPvarGetLbLocal(var) ); 6668 } 6669 else 6670 bound = 0.0; 6671 6672 solval = REALABS( solval ); 6673 6674 if ( ! SCIPisFeasZero(scip, bound) && ! SCIPisInfinity(scip, bound) ) 6675 unscaledweight += REALABS( solval/bound );/*lint !e414*/ 6676 } 6677 6678 if ( SCIPisEfficacious(scip, unscaledweight - 1.0) ) 6679 { 6680 char nameext[SCIP_MAXSTRLEN]; 6681 SCIP_ROW* rowlb = NULL; 6682 SCIP_ROW* rowub = NULL; 6683 SCIP_Bool success; 6684 SCIP_Bool cutoff; 6685 6686 /* generate bound inequalities for lower and upper bound case 6687 * NOTE: tests have shown that non-removable rows give the best results */ 6688 (void) SCIPsnprintf(nameext, SCIP_MAXSTRLEN, "%d", tcliquedata->nboundcuts); 6689 if ( generateBoundInequalityFromSOS1Nodes(scip, tcliquedata->conshdlr, tcliquedata->conflictgraph, 6690 cliquenodes, ncliquenodes, 1.0, FALSE, FALSE, tcliquedata->strthenboundcuts, FALSE, nameext, &rowlb, &rowub) != SCIP_OKAY ) 6691 { 6692 SCIPerrorMessage("Unexpected error in bound cut creation.\n"); 6693 SCIPABORT(); 6694 return; /*lint !e527*/ 6695 } 6696 6697 /* add bound cut(s) to separation storage if existent */ 6698 if ( addBoundCutSepa(scip, tcliquedata, rowlb, rowub, &success, &cutoff) != SCIP_OKAY ) 6699 { 6700 SCIPerrorMessage("Unexpected error in bound cut creation.\n"); 6701 SCIPABORT(); 6702 return; /*lint !e527*/ 6703 } 6704 6705 if ( rowlb != NULL ) 6706 { 6707 if ( SCIPreleaseRow(scip, &rowlb) != SCIP_OKAY ) 6708 { 6709 SCIPerrorMessage("Cannot release row,\n"); 6710 SCIPABORT(); 6711 return; /*lint !e527*/ 6712 } 6713 } 6714 if ( rowub != NULL ) 6715 { 6716 if ( SCIPreleaseRow(scip, &rowub) != SCIP_OKAY ) 6717 { 6718 SCIPerrorMessage("Cannot release row,\n"); 6719 SCIPABORT(); 6720 return; /*lint !e527*/ 6721 } 6722 } 6723 6724 /* if at least one cut has been added */ 6725 if ( success ) 6726 { 6727 SCIPdebugMsg(scip, " -> found bound cut corresponding to clique (act=%g)\n", unscaledweight); 6728 6729 /* if we found more than half the cuts we are allowed to generate, we accept the clique as new incumbent, 6730 * such that only more violated cuts are generated afterwards 6731 */ 6732 if( tcliquedata->maxboundcuts >= 0 ) 6733 { 6734 if ( tcliquedata->ncuts > tcliquedata->maxboundcuts/2 ) 6735 *acceptsol = TRUE; 6736 if ( tcliquedata->ncuts >= tcliquedata->maxboundcuts ) 6737 *stopsolving = TRUE; 6738 } 6739 } 6740 else 6741 *stopsolving = TRUE; 6742 } /*lint !e438*/ 6743 } 6744 } 6745 6746 6747 /** separate bound inequalities from conflict graph */ 6748 static 6749 SCIP_RETCODE sepaBoundInequalitiesFromGraph( 6750 SCIP* scip, /**< SCIP pointer */ 6751 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 6752 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 6753 SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */ 6754 int maxboundcuts, /**< maximal number of bound cuts separated per separation round (-1: no limit) */ 6755 int* ngen, /**< pointer to store number of cuts generated */ 6756 SCIP_Bool* cutoff /**< pointer whether a cutoff occurred */ 6757 ) 6758 { 6759 SCIP_DIGRAPH* conflictgraph; 6760 TCLIQUE_DATA* tcliquedata; 6761 TCLIQUE_WEIGHT cliqueweight; 6762 TCLIQUE_STATUS tcliquestatus; 6763 int nsos1vars; 6764 6765 SCIP_Real scaleval = 1000.0; /* factor for scaling weights */ 6766 int maxtreenodes = 10000; /* maximal number of nodes of b&b tree */ 6767 int maxzeroextensions = 1000; /* maximal number of zero-valued variables extending the clique (-1: no limit) */ 6768 int backtrackfreq = 1000; /* frequency for premature backtracking up to tree level 1 (0: no backtracking) */ 6769 int ntreenodes; 6770 int* cliquenodes; 6771 int ncliquenodes; 6772 6773 assert( scip != NULL ); 6774 assert( conshdlr != NULL ); 6775 assert( conshdlrdata != NULL ); 6776 assert( ngen != NULL ); 6777 6778 /* get conflict graph */ 6779 conflictgraph = SCIPgetConflictgraphSOS1(conshdlr); 6780 assert( conflictgraph != NULL ); 6781 6782 /* get number of SOS1 variables */ 6783 nsos1vars = SCIPgetNSOS1Vars(conshdlr); 6784 6785 /* initialize data of tclique graph*/ 6786 tcliquedata = conshdlrdata->tcliquedata; 6787 tcliquedata->scaleval = scaleval; 6788 tcliquedata->maxboundcuts = maxboundcuts; 6789 tcliquedata->sol = sol; 6790 tcliquedata->ncuts = 0; 6791 tcliquedata->cutoff = FALSE; 6792 6793 /* update the weights of the tclique graph */ 6794 SCIP_CALL( updateWeightsTCliquegraph(scip, conshdlrdata, tcliquedata, conflictgraph, sol, nsos1vars) ); 6795 6796 /* allocate buffer array */ 6797 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nsos1vars) ); 6798 6799 /* start algorithm to find maximum weight cliques and use them to generate bound cuts */ 6800 tcliqueMaxClique(tcliqueGetNNodes, tcliqueGetWeights, tcliqueIsEdge, tcliqueSelectAdjnodes, 6801 conshdlrdata->tcliquegraph, tcliqueNewsolClique, tcliquedata, 6802 cliquenodes, &ncliquenodes, &cliqueweight, (int)scaleval-1, (int)scaleval+1, 6803 maxtreenodes, backtrackfreq, maxzeroextensions, -1, &ntreenodes, &tcliquestatus); 6804 6805 /* free buffer array */ 6806 SCIPfreeBufferArray(scip, &cliquenodes); 6807 6808 /* get number of cuts of current separation round */ 6809 *ngen = tcliquedata->ncuts; 6810 6811 /* store whether a cutoff occurred */ 6812 *cutoff = tcliquedata->cutoff; 6813 6814 /* update number of bound cuts in separator data */ 6815 conshdlrdata->nboundcuts = tcliquedata->nboundcuts; 6816 6817 return SCIP_OKAY; 6818 } 6819 6820 6821 /** Generate a bound constraint from the variables of an SOS1 constraint (see generateBoundInequalityFromSOS1Nodes() for more information) */ 6822 static 6823 SCIP_RETCODE generateBoundInequalityFromSOS1Cons( 6824 SCIP* scip, /**< SCIP pointer */ 6825 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 6826 SCIP_CONS* cons, /**< SOS1 constraint */ 6827 SCIP_Bool local, /**< in any case produce a local cut (even if local bounds of variables are valid globally) */ 6828 SCIP_Bool global, /**< in any case produce a global cut */ 6829 SCIP_Bool strengthen, /**< whether trying to strengthen bound constraint */ 6830 SCIP_Bool removable, /**< should the inequality be removed from the LP due to aging or cleanup? */ 6831 SCIP_ROW** rowlb, /**< output: row for lower bounds (or NULL if not needed) */ 6832 SCIP_ROW** rowub /**< output: row for upper bounds (or NULL if not needed) */ 6833 ) 6834 { 6835 SCIP_CONSHDLRDATA* conshdlrdata; 6836 SCIP_CONSDATA* consdata; 6837 int* nodes; 6838 int nvars; 6839 int cnt = 0; 6840 int j; 6841 6842 assert( scip != NULL ); 6843 assert( conshdlr != NULL ); 6844 assert( cons != NULL ); 6845 6846 /* get constraint data */ 6847 consdata = SCIPconsGetData(cons); 6848 assert( consdata != NULL ); 6849 assert( consdata->vars != NULL ); 6850 nvars = consdata->nvars; 6851 6852 /* get constraint handler data */ 6853 conshdlrdata = SCIPconshdlrGetData(conshdlr); 6854 assert( conshdlrdata != NULL ); 6855 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 6856 6857 /* allocate buffer array */ 6858 SCIP_CALL( SCIPallocBufferArray(scip, &nodes, nvars) ); 6859 6860 /* get nodes in the conflict graph */ 6861 for (j = 0; j < nvars; ++j) 6862 { 6863 if ( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(consdata->vars[j])) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(consdata->vars[j])) ) 6864 { 6865 assert( varGetNodeSOS1(conshdlrdata, consdata->vars[j]) >= 0 ); 6866 nodes[cnt++] = varGetNodeSOS1(conshdlrdata, consdata->vars[j]); 6867 } 6868 } 6869 6870 /* generate bound constraint from conflict graph nodes */ 6871 if ( cnt > 0 ) 6872 { 6873 SCIP_CALL( generateBoundInequalityFromSOS1Nodes(scip, conshdlr, conshdlrdata->conflictgraph, nodes, cnt, 1.0, local, global, 6874 strengthen, removable, SCIPconsGetName(cons), rowlb, rowub) ); 6875 } 6876 6877 /* free buffer array */ 6878 SCIPfreeBufferArray(scip, &nodes); 6879 6880 return SCIP_OKAY; 6881 } 6882 6883 6884 /** initialize or separate bound inequalities from SOS1 constraints */ 6885 static 6886 SCIP_RETCODE initsepaBoundInequalityFromSOS1Cons( 6887 SCIP* scip, /**< SCIP pointer */ 6888 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 6889 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 6890 SCIP_CONS** conss, /**< SOS1 constraints */ 6891 int nconss, /**< number of SOS1 constraints */ 6892 SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */ 6893 SCIP_Bool solvedinitlp, /**< TRUE if initial LP relaxation at a node is solved */ 6894 int maxboundcuts, /**< maximal number of bound cuts separated per separation round (-1: no limit) */ 6895 int* ngen, /**< pointer to store number of cuts generated (or NULL) */ 6896 SCIP_Bool* cutoff /**< pointer to store whether a cutoff occurred */ 6897 ) 6898 { 6899 int cnt = 0; 6900 int c; 6901 6902 assert( scip != NULL ); 6903 assert( conshdlrdata != NULL ); 6904 assert( conss != NULL ); 6905 6906 *cutoff = FALSE; 6907 6908 for (c = 0; c < nconss; ++c) 6909 { 6910 SCIP_CONSDATA* consdata; 6911 SCIP_ROW* rowub = NULL; 6912 SCIP_ROW* rowlb = NULL; 6913 SCIP_Bool release = FALSE; 6914 6915 assert( conss != NULL ); 6916 assert( conss[c] != NULL ); 6917 consdata = SCIPconsGetData(conss[c]); 6918 assert( consdata != NULL ); 6919 6920 if ( solvedinitlp ) 6921 { 6922 SCIPdebugMsg(scip, "Separating inequalities for SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) ); 6923 } 6924 else 6925 { 6926 SCIPdebugMsg(scip, "Checking for initial rows for SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) ); 6927 } 6928 6929 /* in case that the SOS1 constraint is local, we always generate new rows - the former rows might be invalid; 6930 * otherwise if the SOS1 constraint is global, we only generate rows if not yet done */ 6931 if ( consdata->local ) 6932 { 6933 SCIP_CALL( generateBoundInequalityFromSOS1Cons(scip, conshdlr, conss[c], TRUE, FALSE, TRUE, FALSE, &rowlb, &rowub) ); 6934 release = TRUE; 6935 } 6936 else 6937 { 6938 if ( consdata->rowub == NULL || consdata->rowlb == NULL ) 6939 { 6940 SCIP_CALL( generateBoundInequalityFromSOS1Cons(scip, conshdlr, conss[c], FALSE, TRUE, TRUE, FALSE, 6941 (consdata->rowlb == NULL) ? &consdata->rowlb : NULL, 6942 (consdata->rowub == NULL) ? &consdata->rowub : NULL) ); /*lint !e826*/ 6943 } 6944 rowub = consdata->rowub; 6945 rowlb = consdata->rowlb; 6946 } 6947 6948 /* put corresponding rows into LP */ 6949 if ( rowub != NULL && ! SCIProwIsInLP(rowub) && ( solvedinitlp || SCIPisCutEfficacious(scip, sol, rowub) ) ) 6950 { 6951 SCIP_CALL( SCIPaddRow(scip, rowub, FALSE, cutoff) ); 6952 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowub, NULL) ) ); 6953 6954 if ( solvedinitlp ) 6955 { 6956 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) ); 6957 } 6958 ++cnt; 6959 } 6960 6961 if ( ! (*cutoff) && rowlb != NULL && ! SCIProwIsInLP(rowlb) && ( solvedinitlp || SCIPisCutEfficacious(scip, sol, rowlb) ) ) 6962 { 6963 SCIP_CALL( SCIPaddRow(scip, rowlb, FALSE, cutoff) ); 6964 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowlb, NULL) ) ); 6965 6966 if ( solvedinitlp ) 6967 { 6968 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) ); 6969 } 6970 ++cnt; 6971 } 6972 6973 /* release rows if they are local */ 6974 if ( release ) 6975 { 6976 if ( rowlb != NULL ) 6977 { 6978 SCIP_CALL( SCIPreleaseRow(scip, &rowlb) ); 6979 } 6980 if ( rowub != NULL ) 6981 { 6982 SCIP_CALL( SCIPreleaseRow(scip, &rowub) ); 6983 } 6984 } 6985 6986 if ( *cutoff || ( maxboundcuts >= 0 && cnt >= maxboundcuts ) ) 6987 break; 6988 } 6989 6990 /* store number of generated cuts */ 6991 if ( ngen != NULL ) 6992 *ngen = cnt; 6993 6994 return SCIP_OKAY; 6995 } 6996 6997 6998 /** separate implied bound cuts */ 6999 static 7000 SCIP_RETCODE sepaImplBoundCutsSOS1( 7001 SCIP* scip, /**< SCIP pointer */ 7002 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 7003 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 7004 SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */ 7005 int maxcuts, /**< maximal number of implied bound cuts separated per separation round (-1: no limit) */ 7006 int* ngen, /**< pointer to store number of cuts generated */ 7007 SCIP_Bool* cutoff /**< pointer whether a cutoff occurred */ 7008 ) 7009 { 7010 SCIP_DIGRAPH* implgraph; 7011 SCIP_Bool genbreak; 7012 int nimplnodes; 7013 int i; 7014 7015 assert( scip != NULL); 7016 assert( conshdlrdata != NULL); 7017 assert( conshdlr != NULL); 7018 assert( ngen != NULL); 7019 assert( cutoff != NULL); 7020 7021 *cutoff = FALSE; 7022 *ngen = 0; 7023 7024 /* return if conflict graph is not available */ 7025 if ( conshdlrdata->conflictgraph == NULL ) 7026 return SCIP_OKAY; 7027 7028 /* get implication graph */ 7029 implgraph = conshdlrdata->implgraph; 7030 7031 /* create implication graph if not done already */ 7032 if ( implgraph == NULL ) 7033 { 7034 int nchbds; 7035 7036 if ( SCIPgetDepth(scip) == 0 ) 7037 { 7038 SCIP_Bool success; 7039 SCIP_CALL( initImplGraphSOS1(scip, conshdlrdata, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, conshdlrdata->maxtightenbds, &nchbds, cutoff, &success) ); 7040 if ( *cutoff || ! success ) 7041 return SCIP_OKAY; 7042 implgraph = conshdlrdata->implgraph; 7043 } 7044 else 7045 { 7046 return SCIP_OKAY; 7047 } 7048 } 7049 nimplnodes = conshdlrdata->nimplnodes; 7050 assert( implgraph != NULL ); 7051 assert( nimplnodes > 0); 7052 7053 /* exit if implication graph has no arcs between its nodes */ 7054 if ( SCIPdigraphGetNArcs(implgraph) < 1 ) 7055 return SCIP_OKAY; 7056 7057 /* loop through all nodes of the implication graph */ 7058 genbreak = FALSE; 7059 for (i = 0; i < nimplnodes && ! genbreak; ++i) 7060 { 7061 SCIP_SUCCDATA** succdatas; 7062 SCIP_NODEDATA* nodedata; 7063 SCIP_Real solval; 7064 SCIP_VAR* var; 7065 int* succ; 7066 int nsucc; 7067 int s; 7068 7069 succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, i); 7070 nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, i); 7071 assert( nodedata != NULL ); 7072 var = nodedata->var; 7073 assert( var != NULL ); 7074 solval = SCIPgetSolVal(scip, sol, var); 7075 7076 if ( succdatas != NULL && ! SCIPisFeasZero(scip, solval) ) 7077 { 7078 succ = SCIPdigraphGetSuccessors(implgraph, i); 7079 nsucc = SCIPdigraphGetNSuccessors(implgraph, i); 7080 7081 for (s = 0; s < nsucc && ! genbreak; ++s) 7082 { 7083 SCIP_SUCCDATA* succdata; 7084 SCIP_VAR* succvar; 7085 SCIP_ROW* cut = NULL; 7086 SCIP_Bool bound1lower; 7087 SCIP_Bool bound2lower; 7088 SCIP_Real solvalsucc; 7089 SCIP_Real bound1; 7090 SCIP_Real bound2; 7091 SCIP_Real lhsrhs; 7092 SCIP_Real impl; 7093 int k; 7094 7095 nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, succ[s]); 7096 succdata = succdatas[s]; 7097 assert( nodedata != NULL && succdata != NULL && nodedata->var != NULL ); 7098 succvar = nodedata->var; 7099 solvalsucc = SCIPgetSolVal(scip, sol, succvar); 7100 7101 /* determine coefficients for bound inequality */ 7102 assert( ! SCIPisFeasZero(scip, solval) ); 7103 if ( SCIPisFeasNegative(scip, solval) ) 7104 { 7105 bound1lower = TRUE; 7106 bound1 = SCIPvarGetLbGlobal(var); 7107 } 7108 else 7109 { 7110 bound1lower = FALSE; 7111 bound1 = SCIPvarGetUbGlobal(var); 7112 } 7113 7114 /* handle lower bound upper bound implications */ 7115 for (k = 0; k < 2; ++k) 7116 { 7117 if ( k == 0 ) 7118 { 7119 SCIP_Real lbsucc; 7120 lbsucc = SCIPvarGetLbGlobal(succvar); 7121 if ( SCIPisFeasLT(scip, lbsucc, succdata->lbimpl) ) 7122 { 7123 impl = succdata->lbimpl; 7124 bound2 = lbsucc; 7125 } 7126 else 7127 continue; 7128 } 7129 else 7130 { 7131 SCIP_Real ubsucc; 7132 ubsucc = SCIPvarGetUbGlobal(succvar); 7133 if ( SCIPisFeasGT(scip, ubsucc, succdata->ubimpl) ) 7134 { 7135 impl = succdata->ubimpl; 7136 bound2 = ubsucc; 7137 } 7138 else 7139 continue; 7140 } 7141 7142 if ( SCIPisInfinity(scip, REALABS(bound1)) || SCIPisInfinity(scip, REALABS(bound2)) ) 7143 continue; 7144 assert( ! SCIPisInfinity(scip, REALABS(impl)) ); 7145 7146 if ( SCIPisFeasNegative(scip, bound2-impl) ) 7147 bound2lower = TRUE; 7148 else 7149 bound2lower = FALSE; 7150 7151 /* determine left/right hand side of bound inequality */ 7152 lhsrhs = bound1 * bound2; 7153 7154 /* create cut */ 7155 if ( bound1lower == bound2lower ) 7156 { 7157 if ( SCIPisFeasGT(scip, solval * (bound2-impl) + solvalsucc * bound1, lhsrhs) ) 7158 { 7159 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &cut, conshdlr, "", -SCIPinfinity(scip), lhsrhs, FALSE, FALSE, TRUE) ); 7160 } 7161 else 7162 continue; 7163 } 7164 else 7165 { 7166 if ( SCIPisFeasLT(scip, solval * (bound2-impl) + solvalsucc * bound1, lhsrhs) ) 7167 { 7168 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &cut, conshdlr, "", lhsrhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) ); 7169 } 7170 else 7171 continue; 7172 } 7173 7174 /* add coefficients of variables */ 7175 SCIP_CALL( SCIPcacheRowExtensions(scip, cut) ); 7176 SCIP_CALL( SCIPaddVarToRow(scip, cut, var, bound2-impl) ); 7177 SCIP_CALL( SCIPaddVarToRow(scip, cut, succvar, bound1) ); 7178 SCIP_CALL( SCIPflushRowExtensions(scip, cut) ); 7179 7180 /* add cut if useful */ 7181 if ( ! SCIProwIsInLP(cut) && SCIPisCutEfficacious(scip, NULL, cut) ) 7182 { 7183 SCIP_Bool infeasible; 7184 SCIP_CALL( SCIPaddRow(scip, cut, FALSE, &infeasible) ); 7185 if ( infeasible ) 7186 { 7187 genbreak = TRUE; 7188 *cutoff = TRUE; 7189 break; 7190 } 7191 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, cut, NULL) ) ); 7192 #ifdef SCIP_DEBUG 7193 if ( k == 0 ) 7194 { 7195 SCIPdebugMsg(scip, "added cut for implication %s != 0 -> %s >= %f \n", SCIPvarGetName(var), SCIPvarGetName(succvar), succdata->lbimpl); 7196 } 7197 else 7198 { 7199 SCIPdebugMsg(scip, "added cut for implication %s != 0 -> %s <= %f \n", SCIPvarGetName(var), SCIPvarGetName(succvar), succdata->ubimpl); 7200 } 7201 #endif 7202 7203 ++(*ngen); 7204 } 7205 7206 if ( maxcuts >= 0 && *ngen > maxcuts ) 7207 { 7208 genbreak = TRUE; 7209 break; 7210 } 7211 } 7212 7213 if ( cut != NULL ) 7214 SCIP_CALL( SCIPreleaseRow(scip, &cut) ); 7215 } 7216 } 7217 } 7218 7219 return SCIP_OKAY; 7220 } 7221 7222 7223 /** separates SOS1 constraints for arbitrary solutions */ 7224 static 7225 SCIP_RETCODE separateSOS1( 7226 SCIP* scip, /**< SCIP pointer */ 7227 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 7228 SCIP_SOL* sol, /**< solution to be separated (or NULL) */ 7229 int nconss, /**< number of constraints */ 7230 SCIP_CONS** conss, /**< SOS1 constraints */ 7231 SCIP_RESULT* result /**< result */ 7232 ) 7233 { 7234 SCIP_CONSHDLRDATA* conshdlrdata; 7235 int depth; 7236 7237 assert( scip != NULL ); 7238 assert( conshdlr != NULL ); 7239 assert( conss != NULL ); 7240 assert( result != NULL ); 7241 7242 *result = SCIP_DIDNOTRUN; 7243 7244 if ( nconss == 0 ) 7245 return SCIP_OKAY; 7246 7247 /* only separate cuts if we are not close to terminating */ 7248 if( SCIPisStopped(scip) ) 7249 return SCIP_OKAY; 7250 7251 *result = SCIP_DIDNOTFIND; 7252 7253 /* get constraint handler data */ 7254 conshdlrdata = SCIPconshdlrGetData(conshdlr); 7255 assert( conshdlrdata != NULL ); 7256 7257 /* get node depth */ 7258 depth = SCIPgetDepth(scip); 7259 7260 /* separate bound (clique) inequalities */ 7261 if ( conshdlrdata->boundcutsfreq >= 0 && 7262 ( (conshdlrdata->boundcutsfreq == 0 && depth == 0) || (conshdlrdata->boundcutsfreq > 0 && depth % conshdlrdata->boundcutsfreq == 0)) ) 7263 { 7264 int maxboundcuts; 7265 int ngen = 0; 7266 7267 /* determine maximal number of cuts*/ 7268 if ( depth == 0 ) 7269 maxboundcuts = conshdlrdata->maxboundcutsroot; 7270 else 7271 maxboundcuts = conshdlrdata->maxboundcuts; 7272 7273 if ( maxboundcuts >= 1 ) 7274 { 7275 /* separate bound inequalities from SOS1 constraints */ 7276 if( conshdlrdata->boundcutsfromsos1 || conshdlrdata->switchcutsfromsos1 ) 7277 { 7278 SCIP_Bool cutoff; 7279 7280 SCIP_CALL( initsepaBoundInequalityFromSOS1Cons(scip, conshdlr, conshdlrdata, conss, nconss, sol, TRUE, maxboundcuts, &ngen, &cutoff) ); 7281 if ( cutoff ) 7282 { 7283 *result = SCIP_CUTOFF; 7284 return SCIP_OKAY; 7285 } 7286 } 7287 7288 /* separate bound inequalities from the conflict graph */ 7289 if( conshdlrdata->boundcutsfromgraph && ! conshdlrdata->switchcutsfromsos1 ) 7290 { 7291 SCIP_Bool cutoff; 7292 SCIP_CALL( sepaBoundInequalitiesFromGraph(scip, conshdlr, conshdlrdata, sol, maxboundcuts, &ngen, &cutoff) ); 7293 if ( cutoff ) 7294 { 7295 *result = SCIP_CUTOFF; 7296 return SCIP_OKAY; 7297 } 7298 } 7299 } 7300 7301 /* evaluate results */ 7302 if ( ngen > 0 ) 7303 *result = SCIP_SEPARATED; 7304 SCIPdebugMsg(scip, "Separated %d bound (clique) inequalities.\n", ngen); 7305 } 7306 7307 /* separate implied bound inequalities */ 7308 if ( conshdlrdata->implcutsfreq >= 0 && 7309 ( (conshdlrdata->implcutsfreq == 0 && depth == 0) || (conshdlrdata->implcutsfreq > 0 && depth % conshdlrdata->implcutsfreq == 0)) ) 7310 { 7311 int maximplcuts; 7312 int ngen = 0; 7313 7314 /* determine maximal number of cuts*/ 7315 if ( depth == 0 ) 7316 maximplcuts = conshdlrdata->maximplcutsroot; 7317 else 7318 maximplcuts = conshdlrdata->maximplcuts; 7319 7320 /* call separator for implied bound cuts */ 7321 if ( maximplcuts >= 1 ) 7322 { 7323 SCIP_Bool cutoff; 7324 SCIP_CALL( sepaImplBoundCutsSOS1(scip, conshdlr, conshdlrdata, sol, maximplcuts, &ngen, &cutoff) ); 7325 if ( cutoff ) 7326 { 7327 *result = SCIP_CUTOFF; 7328 return SCIP_OKAY; 7329 } 7330 } 7331 7332 /* evaluate results */ 7333 if ( ngen > 0 ) 7334 *result = SCIP_SEPARATED; 7335 SCIPdebugMsg(scip, "Separated %d implied bound inequalities.\n", ngen); 7336 } 7337 7338 return SCIP_OKAY; 7339 } 7340 7341 7342 /* -------------------------- heuristic methods --------------------------------*/ 7343 7344 /** gets weights determining an order of the variables in a heuristic for the maximum weighted independent set problem */ 7345 static 7346 SCIP_RETCODE getVectorOfWeights( 7347 SCIP* scip, /**< SCIP pointer */ 7348 SCIP_SOL* sol, /**< primal solution or NULL for current LP solution */ 7349 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 7350 int nsos1vars, /**< number of SOS1 variables */ 7351 SCIP_Bool* indicatorzero, /**< vector that indicates which variables are currently fixed to zero */ 7352 SCIP_Real* weights /**< pointer to store weights determining the order of the variables (length = nsos1vars) */ 7353 ) 7354 { 7355 SCIP_VAR* var; 7356 SCIP_Real val; 7357 SCIP_Real sum; 7358 int nviols; 7359 int* succ; 7360 int nsucc; 7361 int i; 7362 int j; 7363 7364 assert( scip != NULL ); 7365 assert( conflictgraph != NULL ); 7366 assert( indicatorzero != NULL ); 7367 assert( weights != NULL ); 7368 7369 for (i = 0; i < nsos1vars; ++i) 7370 { 7371 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i); 7372 7373 if( nsucc == 0 || indicatorzero[i] ) 7374 weights[i] = 0.0; 7375 else 7376 { 7377 var = SCIPnodeGetVarSOS1(conflictgraph, i); 7378 val = REALABS( SCIPgetSolVal(scip, sol, var) ); 7379 if ( SCIPisFeasZero(scip, val) ) 7380 weights[i] = 0.0; 7381 else 7382 { 7383 succ = SCIPdigraphGetSuccessors(conflictgraph, i); 7384 7385 nviols = 0; 7386 sum = 0.0; 7387 for (j = 0; j < nsucc; ++j) 7388 { 7389 SCIP_Real valsucc; 7390 7391 valsucc = REALABS( SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, succ[j])) ); 7392 if( ! SCIPisFeasZero(scip, valsucc) ) 7393 { 7394 sum += MIN(10E05, valsucc); 7395 ++nviols; 7396 } 7397 } 7398 7399 if ( nviols == 0 ) 7400 weights[i] = 0.0; 7401 else 7402 { 7403 assert( SCIPisFeasPositive(scip, sum * (SCIP_Real)nviols)); 7404 val = MIN(1e6, val); 7405 weights[i] = ( val + SCIPsumepsilon(scip) ) / ( sum * (SCIP_Real)nviols + SCIPsumepsilon(scip) ); 7406 } 7407 } 7408 } 7409 } 7410 7411 return SCIP_OKAY; 7412 } 7413 7414 7415 /* marks neighbors of a given node as not a member of the maximal independent set */ 7416 static 7417 SCIP_RETCODE markNeighborsMWISHeuristic( 7418 SCIP* scip, /**< SCIP pointer */ 7419 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */ 7420 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 7421 int node, /**< node of the conflict graph */ 7422 SCIP_Bool* mark, /**< indicator vector of processed nodes */ 7423 SCIP_Bool* indset, /**< indicator vector of current independent */ 7424 int* cnt, /**< pointer to store number of marked nodes */ 7425 SCIP_Bool* cutoff /**< pointer to store whether operation is infeasible */ 7426 ) 7427 { 7428 int nsucc; 7429 int* succ; 7430 int j; 7431 7432 assert( scip != NULL ); 7433 assert( conflictgraph != NULL ); 7434 assert( mark != NULL ); 7435 assert( indset != NULL ); 7436 assert( cutoff != NULL ); 7437 assert( cnt != NULL ); 7438 7439 *cutoff = FALSE; 7440 7441 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node); 7442 succ = SCIPdigraphGetSuccessors(conflictgraph, node); 7443 7444 /* for all successors */ 7445 for (j = 0; j < nsucc && !(*cutoff); ++j) 7446 { 7447 int succj; 7448 7449 succj = succ[j]; 7450 assert( indset[succj] == 0 ); 7451 if( ! mark[succj] ) 7452 { 7453 SCIP_VARSTATUS varstatus; 7454 SCIP_VAR* var; 7455 7456 /* mark node as processed */ 7457 mark[succj] = TRUE; 7458 ++(*cnt); 7459 7460 /* get variable and variable status corresponding to successor node */ 7461 var = SCIPnodeGetVarSOS1(conflictgraph, succj); 7462 varstatus = SCIPvarGetStatus(var); 7463 7464 /* if variable is aggregated */ 7465 if ( varstatus == SCIP_VARSTATUS_AGGREGATED ) 7466 { 7467 int aggrnode; 7468 7469 aggrnode = SCIPvarGetNodeSOS1(conshdlr, SCIPvarGetAggrVar(var)); 7470 7471 /* if aggregated variable is an SOS1 variable */ 7472 if ( aggrnode >= 0 ) 7473 { 7474 /* if aggregated variable is implied to be zero */ 7475 if ( SCIPisFeasZero(scip, SCIPvarGetAggrConstant(var)) ) 7476 { 7477 if ( ! mark[aggrnode] ) 7478 { 7479 mark[aggrnode] = TRUE; 7480 ++(*cnt); 7481 } 7482 else if ( indset[aggrnode] == 1 ) 7483 { 7484 *cutoff = TRUE; 7485 return SCIP_OKAY; 7486 } 7487 } 7488 else 7489 { 7490 /* if aggregated variable is not already a member of the maximal independent set */ 7491 if ( indset[aggrnode] == 0 ) 7492 { 7493 /* if variable is already marked */ 7494 if ( mark[aggrnode] ) 7495 { 7496 *cutoff = TRUE; 7497 return SCIP_OKAY; 7498 } 7499 else 7500 { 7501 indset[aggrnode] = 1; 7502 mark[aggrnode] = TRUE; 7503 ++(*cnt); 7504 } 7505 7506 /* mark neighbors of aggregated variable */ 7507 SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, aggrnode, mark, indset, cnt, cutoff) ); 7508 } 7509 } 7510 } 7511 } 7512 else if ( varstatus == SCIP_VARSTATUS_NEGATED ) 7513 { 7514 int negnode; 7515 7516 negnode = SCIPvarGetNodeSOS1(conshdlr, SCIPvarGetNegationVar(var)); 7517 7518 /* if negated variable is an SOS1 variable */ 7519 if ( negnode >= 0 ) 7520 { 7521 if ( SCIPisFeasZero(scip, SCIPvarGetNegationConstant(var) ) ) 7522 { 7523 if ( indset[negnode] == 1 ) 7524 { 7525 *cutoff = TRUE; 7526 return SCIP_OKAY; 7527 } 7528 else if ( ! mark[negnode] ) 7529 { 7530 mark[negnode] = TRUE; 7531 ++(*cnt); 7532 } 7533 } 7534 } 7535 } 7536 } 7537 } 7538 7539 return SCIP_OKAY; 7540 } 7541 7542 7543 /** calls greedy algorithm for the maximum weighted independent set problem (MWIS) 7544 * 7545 * We compute a feasible solution to 7546 * \f[ 7547 * \begin{array}{ll} 7548 * \min\limits_{z} & {x^*}^T z \\ 7549 * & z_i + z_j \leq 1, \qquad (i,j)\in E \\ 7550 * & z_i \in \{0,1\}, \qquad\quad i\in V 7551 * \end{array} 7552 * \f] 7553 * by the algorithm GGWMIN of Shuichi Sakai, Mitsunori Togasaki and Koichi Yamazaki in "A note on greedy algorithms for the 7554 * maximum weighted independent set problem", Discrete Applied Mathematics. Here \f$x^*\f$ denotes the current LP 7555 * relaxation solution. Note that the solution of the MWIS is the indicator vector of an independent set. 7556 */ 7557 static 7558 SCIP_RETCODE maxWeightIndSetHeuristic( 7559 SCIP* scip, /**< SCIP pointer */ 7560 SCIP_SOL* sol, /**< primal solution or NULL for current LP solution */ 7561 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */ 7562 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 7563 int nsos1vars, /**< number of SOS1 variables */ 7564 SCIP_Bool* indicatorzero, /**< vector that indicates which variables are currently fixed to zero */ 7565 SCIP_Bool* indset /**< pointer to store indicator vector of an independent set */ 7566 ) 7567 { 7568 SCIP_Bool* mark = NULL; 7569 SCIP_Real* weights = NULL; 7570 int* indscipvars = NULL; 7571 int ind; 7572 int nsucc; 7573 int i; 7574 int k; 7575 7576 assert( scip != NULL ); 7577 assert( conflictgraph != NULL ); 7578 assert( indicatorzero != NULL ); 7579 assert( indset != NULL ); 7580 7581 /* allocate buffer arrays */ 7582 SCIP_CALL( SCIPallocBufferArray(scip, &mark, nsos1vars) ); 7583 SCIP_CALL( SCIPallocBufferArray(scip, &weights, nsos1vars) ); 7584 SCIP_CALL( SCIPallocBufferArray(scip, &indscipvars, nsos1vars) ); 7585 7586 /* sort SOS1 variables in nonincreasing order of weights */ 7587 for (i = 0; i < nsos1vars; ++i) 7588 indscipvars[i] = i; 7589 7590 SCIP_CALL( getVectorOfWeights(scip, sol, conflictgraph, nsos1vars, indicatorzero, weights) ); 7591 SCIPsortDownRealInt(weights, indscipvars, nsos1vars); 7592 7593 /* mark fixed variables and variables without any neighbors in the conflict graph */ 7594 k = 0; 7595 for (i = 0; i < nsos1vars; ++i) 7596 { 7597 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i); 7598 7599 if ( indset[i] == 0 ) 7600 { 7601 if( indicatorzero[i] ) 7602 { 7603 mark[i] = TRUE; 7604 ++k; 7605 } 7606 else if ( nsucc == 0 ) 7607 { 7608 indset[i] = 1; 7609 mark[i] = TRUE; 7610 ++k; 7611 } 7612 else 7613 mark[i] = FALSE; 7614 } 7615 else 7616 { 7617 SCIP_Bool cutoff; 7618 7619 ++k; 7620 mark[i] = TRUE; 7621 7622 SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, i, mark, indset, &k, &cutoff) ); 7623 assert( ! cutoff ); 7624 } 7625 } 7626 7627 /* mark vertices in the order of their largest weight */ 7628 for (i = 0; k < nsos1vars; ++i) /*lint !e440*/ 7629 { 7630 assert( i < nsos1vars ); 7631 7632 ind = indscipvars[i]; 7633 7634 if ( ! mark[ind] ) 7635 { 7636 SCIP_Bool cutoff; 7637 7638 /* mark ind */ 7639 indset[ind] = 1; 7640 mark[ind] = TRUE; 7641 ++k; 7642 7643 SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, ind, mark, indset, &k, &cutoff) ); 7644 if ( cutoff ) 7645 indset[ind] = 0; 7646 } 7647 } 7648 assert( k == nsos1vars ); 7649 7650 /* free buffer arrays */ 7651 SCIPfreeBufferArrayNull(scip, &indscipvars); 7652 SCIPfreeBufferArrayNull(scip, &weights); 7653 SCIPfreeBufferArrayNull(scip, &mark); 7654 7655 return SCIP_OKAY; 7656 } 7657 7658 7659 /** based on solution values of the variables, fixes variables of the conflict graph to zero to turn all SOS1 constraints feasible 7660 * 7661 * if the SOS1 constraints do not overlap, the method makeSOS1constraintsFeasible() may be faster 7662 */ 7663 static 7664 SCIP_RETCODE makeSOS1conflictgraphFeasible( 7665 SCIP* scip, /**< SCIP pointer */ 7666 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */ 7667 SCIP_SOL* sol, /**< solution */ 7668 SCIP_Bool* changed, /**< pointer to store whether the solution has been changed */ 7669 SCIP_Bool* allroundable /**< pointer to store whether all variables are roundable */ 7670 ) 7671 { 7672 SCIP_DIGRAPH* conflictgraph; /* conflict graph for SOS1 constraints */ 7673 SCIP_Bool* indicatorzero; /* indicates which solution values are zero */ 7674 SCIP_Bool* indset; /* indicator vector of feasible solution; i.e., an independent set */ 7675 int nsos1vars; 7676 int j; 7677 7678 assert( scip != NULL ); 7679 assert( conshdlr != NULL ); 7680 assert( sol != NULL ); 7681 assert( changed != NULL ); 7682 assert( allroundable != NULL ); 7683 7684 *allroundable = TRUE; 7685 *changed = FALSE; 7686 7687 /* get number of SOS1 variables */ 7688 nsos1vars = SCIPgetNSOS1Vars(conshdlr); 7689 assert( nsos1vars >= 0 ); 7690 7691 /* get conflict graph */ 7692 conflictgraph = SCIPgetConflictgraphSOS1(conshdlr); 7693 assert( conflictgraph != NULL ); 7694 7695 /* allocate buffer arrays */ 7696 SCIP_CALL( SCIPallocBufferArray(scip, &indset, nsos1vars) ); 7697 SCIP_CALL( SCIPallocBufferArray(scip, &indicatorzero, nsos1vars) ); 7698 7699 /* determine if variables with nonzero solution value are roundable */ 7700 for (j = 0; j < nsos1vars; ++j) 7701 { 7702 SCIP_VAR* var; 7703 SCIP_Real lb; 7704 SCIP_Real ub; 7705 7706 var = SCIPnodeGetVarSOS1(conflictgraph, j); 7707 lb = SCIPvarGetLbLocal(var); 7708 ub = SCIPvarGetUbLocal(var); 7709 indset[j] = 0; 7710 7711 /* if solution value of variable is zero */ 7712 if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, var)) ) 7713 indicatorzero[j] = TRUE; 7714 else 7715 { 7716 indicatorzero[j] = FALSE; 7717 7718 /* if variable is not roundable */ 7719 if ( ! SCIPvarMayRoundDown(var) && ! SCIPvarMayRoundUp(var) ) 7720 { 7721 *allroundable = FALSE; 7722 break; 7723 } 7724 7725 /* if bounds of variable are fixed to zero */ 7726 if ( SCIPisFeasZero(scip, ub) && SCIPisFeasZero(scip, lb) ) 7727 indicatorzero[j] = TRUE; 7728 else if ( SCIPisFeasPositive(scip, lb) || SCIPisFeasNegative(scip, ub) ) /* if variable is fixed to be nonzero */ 7729 indset[j] = 1; 7730 } 7731 } 7732 7733 /* return if at least one SOS1 variable is not roundable */ 7734 if ( ! (*allroundable) ) 7735 { 7736 SCIPfreeBufferArray(scip, &indicatorzero); 7737 SCIPfreeBufferArray(scip, &indset); 7738 return SCIP_OKAY; 7739 } 7740 7741 /* call greedy algorithm for the maximum weighted independent set problem */ 7742 SCIP_CALL( maxWeightIndSetHeuristic(scip, sol, conshdlr, conflictgraph, nsos1vars, indicatorzero, indset) ); 7743 7744 /* make solution feasible */ 7745 for (j = 0; j < nsos1vars; ++j) 7746 { 7747 if ( indset[j] == 0 ) 7748 { 7749 SCIP_CALL( SCIPsetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, j), 0.0) ); 7750 *changed = TRUE; 7751 } 7752 } 7753 7754 /* free buffer arrays */ 7755 SCIPfreeBufferArray(scip, &indicatorzero); 7756 SCIPfreeBufferArray(scip, &indset); 7757 7758 #ifdef SCIP_NDEBUG 7759 { 7760 SCIP_CONSDATA* consdata; 7761 SCIP_CONS** conss; 7762 int nconss; 7763 int c; 7764 7765 conss = SCIPconshdlrGetConss(conshdlr); 7766 nconss = SCIPconshdlrGetNConss(conshdlr); 7767 for (c = 0; c < nconss; ++c) 7768 { 7769 int cnt = 0; 7770 consdata = SCIPconsGetData(conss[c]); 7771 assert( consdata != NULL ); 7772 7773 for (j = 0; j < consdata->nvars; ++j) 7774 { 7775 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) ) 7776 { 7777 ++cnt; 7778 } 7779 } 7780 assert( cnt < 2 ); 7781 } 7782 } 7783 #endif 7784 7785 return SCIP_OKAY; 7786 } 7787 7788 7789 /** based on solution values of the variables, fixes variables of the SOS1 constraints to zero to turn these constraints feasible 7790 * 7791 * if the SOS1 constraints overlap, the method makeSOS1constraintsFeasible() may result in better primal solutions 7792 */ 7793 static 7794 SCIP_RETCODE makeSOS1constraintsFeasible( 7795 SCIP* scip, /**< SCIP pointer */ 7796 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */ 7797 SCIP_SOL* sol, /**< solution */ 7798 SCIP_Bool* changed, /**< pointer to store whether the solution has been changed */ 7799 SCIP_Bool* allroundable /**< pointer to store whether all variables are roundable */ 7800 ) 7801 { 7802 SCIP_CONSDATA* consdata; 7803 SCIP_CONS** conss; 7804 int nconss; 7805 int c; 7806 7807 assert( scip != NULL ); 7808 assert( conshdlr != NULL ); 7809 assert( sol != NULL ); 7810 assert( changed != NULL ); 7811 assert( allroundable != NULL ); 7812 7813 *allroundable = TRUE; 7814 *changed = FALSE; 7815 7816 /* get SOS1 constraints and number of SOS1 constraints */ 7817 conss = SCIPconshdlrGetConss(conshdlr); 7818 nconss = SCIPconshdlrGetNConss(conshdlr); 7819 assert( nconss > 0 ); 7820 7821 /* loop through all SOS1 constraints */ 7822 for (c = 0; c < nconss && *allroundable; ++c) 7823 { 7824 SCIP_CONS* cons; 7825 SCIP_VAR** vars; 7826 SCIP_Bool varisfixed = FALSE; 7827 SCIP_Real maxval = 0.0; 7828 int pos = -1; 7829 int nvars; 7830 int j; 7831 7832 cons = conss[c]; 7833 assert( cons != NULL ); 7834 consdata = SCIPconsGetData(cons); 7835 assert( consdata != NULL ); 7836 7837 nvars = consdata->nvars; 7838 vars = consdata->vars; 7839 7840 /* search for maximum solution value */ 7841 for (j = 0; j < nvars; ++j) 7842 { 7843 SCIP_VAR* var; 7844 7845 var = vars[j]; 7846 7847 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, var)) ) 7848 { 7849 SCIP_Real lb; 7850 SCIP_Real ub; 7851 7852 lb = SCIPvarGetLbLocal(var); 7853 ub = SCIPvarGetUbLocal(var); 7854 7855 /* if variable is not roundable */ 7856 if ( ! SCIPvarMayRoundDown(var) && ! SCIPvarMayRoundUp(var) ) 7857 { 7858 *allroundable = FALSE; 7859 break; 7860 } 7861 7862 /* it is possible that the bounds were proagated to zero although the current solution value is nonzero 7863 * in this case fix the solution value to zero */ 7864 if ( SCIPisFeasZero(scip, ub) && SCIPisFeasZero(scip, lb) ) 7865 { 7866 SCIP_CALL( SCIPsetSolVal(scip, sol, var, 0.0) ); 7867 *changed = TRUE; 7868 } 7869 else if ( SCIPisFeasPositive(scip, lb) || SCIPisFeasNegative(scip, ub) ) /* if variable is fixed to be nonzero */ 7870 { 7871 assert( ! varisfixed ); 7872 varisfixed = TRUE; 7873 maxval = SCIPgetSolVal(scip, sol, var); 7874 pos = j; 7875 } 7876 else if ( ! varisfixed && SCIPisFeasGT(scip, REALABS(SCIPgetSolVal(scip, sol, var)), REALABS(maxval)) ) /* search for variable with maximum solution value */ 7877 { 7878 maxval = SCIPgetSolVal(scip, sol, var); 7879 pos = j; 7880 } 7881 7882 /* fix variable to zero; the solution value of the variable with maximum solution value 7883 * will be restored in a later step */ 7884 SCIP_CALL( SCIPsetSolVal(scip, sol, var, 0.0) ); 7885 *changed = TRUE; 7886 } 7887 } 7888 7889 if ( ! (*allroundable) ) 7890 break; 7891 else if ( pos >= 0 ) /* restore solution of variable with maximum solution value */ 7892 { 7893 SCIP_CALL( SCIPsetSolVal(scip, sol, vars[pos], maxval) ); 7894 } 7895 } 7896 7897 #ifdef SCIP_NDEBUG 7898 if ( *allroundable ) 7899 { 7900 for (c = 0; c < nconss; ++c) 7901 { 7902 int cnt = 0; 7903 int j; 7904 7905 consdata = SCIPconsGetData(conss[c]); 7906 assert( consdata != NULL ); 7907 7908 for (j = 0; j < consdata->nvars; ++j) 7909 { 7910 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) ) 7911 { 7912 ++cnt; 7913 } 7914 } 7915 assert( cnt < 2 ); 7916 } 7917 } 7918 #endif 7919 7920 return SCIP_OKAY; 7921 } 7922 7923 7924 /** determine a diving variables and boundchanges of diving variables by analyzing the conflict graph 7925 * 7926 * if the SOS1 constraints do not overlap, the method getDiveBdChgsSOS1constraints() may be faster 7927 */ 7928 static 7929 SCIP_RETCODE getDiveBdChgsSOS1conflictgraph( 7930 SCIP* scip, /**< SCIP pointer */ 7931 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */ 7932 SCIP_DIVESET* diveset, /**< diving settings */ 7933 SCIP_SOL* sol, /**< solution */ 7934 SCIP_Bool* success /**< pointer to store */ 7935 ) 7936 { 7937 SCIP_DIGRAPH* conflictgraph; 7938 SCIP_VAR* bestvar = NULL; 7939 SCIP_Bool bestvarfixneigh = FALSE; 7940 SCIP_Real bestscore = SCIP_REAL_MIN; 7941 int bestnode = -1; 7942 int nsos1vars; 7943 int v; 7944 7945 assert( scip != NULL ); 7946 assert( conshdlr != NULL ); 7947 assert( diveset != NULL ); 7948 assert( success != NULL ); 7949 7950 *success = FALSE; 7951 7952 /* get number of SOS1 variables */ 7953 nsos1vars = SCIPgetNSOS1Vars(conshdlr); 7954 7955 /* get conflict graph of SOS1 constraints */ 7956 conflictgraph = SCIPgetConflictgraphSOS1(conshdlr); 7957 7958 /* loop over SOS1 variables */ 7959 for (v = 0; v < nsos1vars; ++v) 7960 { 7961 /* check whether the variable violates an SOS1 constraint together with at least one other variable */ 7962 if ( isViolatedSOS1(scip, conflictgraph, v, sol) ) 7963 { 7964 SCIP_VAR* var; 7965 SCIP_Real solval; 7966 SCIP_Real score; 7967 SCIP_Real bound; 7968 SCIP_Real fracval; 7969 SCIP_Bool fixneigh; 7970 7971 var = SCIPnodeGetVarSOS1(conflictgraph, v); 7972 solval = SCIPgetSolVal(scip, sol, var); 7973 7974 /* compute (variable) bound of candidate */ 7975 if ( SCIPisFeasNegative(scip, solval) ) 7976 bound = nodeGetSolvalVarboundLbSOS1(scip, conflictgraph, sol, v); 7977 else 7978 bound = nodeGetSolvalVarboundUbSOS1(scip, conflictgraph, sol, v); 7979 7980 /* ensure finiteness */ 7981 bound = MIN(DIVINGCUTOFFVALUE, REALABS(bound)); /*lint !e666*/ 7982 fracval = MIN(DIVINGCUTOFFVALUE, REALABS(solval)); /*lint !e666*/ 7983 assert( ! SCIPisInfinity(scip, bound) ); 7984 assert( ! SCIPisInfinity(scip, fracval) ); 7985 assert( SCIPisPositive(scip, bound) ); 7986 7987 /* bound may have changed in propagation; ensure that fracval <= 1 */ 7988 if ( SCIPisFeasLT(scip, bound, fracval) ) 7989 bound = fracval; 7990 7991 /* get fractionality of candidate */ 7992 fracval /= (bound + SCIPsumepsilon(scip)); 7993 7994 /* should SOS1 variables be scored by the diving heuristics specific score function; 7995 * otherwise use the score function of the SOS1 constraint handler */ 7996 if ( SCIPdivesetSupportsType(diveset, SCIP_DIVETYPE_SOS1VARIABLE) ) 7997 { 7998 SCIP_Bool roundup; 7999 8000 SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_SOS1VARIABLE, var, solval, fracval, 8001 &score, &roundup) ); 8002 8003 fixneigh = roundup; 8004 if ( SCIPisFeasNegative(scip, solval) ) 8005 fixneigh = !fixneigh; 8006 } 8007 else 8008 { 8009 /* we always fix the candidates neighbors in the conflict graph to zero */ 8010 fixneigh = TRUE; 8011 8012 /* score fractionality of candidate */ 8013 score = fracval; 8014 } 8015 8016 /* best candidate maximizes the score */ 8017 if ( score > bestscore ) 8018 { 8019 bestscore = score; 8020 8021 *success = TRUE; 8022 bestvar = var; 8023 bestnode = v; 8024 bestvarfixneigh = fixneigh; 8025 } 8026 } 8027 } 8028 assert( !(*success) || bestvar != NULL ); 8029 8030 if ( *success ) 8031 { 8032 int* succ; 8033 int nsucc; 8034 int s; 8035 8036 assert( bestnode >= 0 && bestnode < nsos1vars ); 8037 8038 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, bestnode); 8039 succ = SCIPdigraphGetSuccessors(conflictgraph, bestnode); 8040 8041 /* if the diving score voted for fixing the best variable to 0.0, we add this as the preferred bound change; 8042 * otherwise, fixing the neighbors in the conflict graph to 0.0 is the preferred bound change. 8043 */ 8044 assert( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(bestvar)) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(bestvar)) ); 8045 SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_FIXED, 0.0, !bestvarfixneigh) ); 8046 for (s = 0; s < nsucc; ++s) 8047 { 8048 SCIP_VAR* var; 8049 8050 var = SCIPnodeGetVarSOS1(conflictgraph, succ[s]); 8051 8052 /* if variable is not already fixed */ 8053 if ( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var)) ) 8054 { 8055 SCIP_CALL( SCIPaddDiveBoundChange(scip, var, SCIP_BRANCHDIR_FIXED, 0.0, bestvarfixneigh) ); 8056 } 8057 } 8058 } 8059 8060 return SCIP_OKAY; 8061 } 8062 8063 8064 /** determine a diving variables and boundchanges of diving variables by analyzing the SOS1 constraints 8065 * 8066 * if the SOS1 constraints overlap, the method getDiveBdChgsSOS1conflictgraph() may produce better results (e.g., due to more 8067 * diving candidates) 8068 */ 8069 static 8070 SCIP_RETCODE getDiveBdChgsSOS1constraints( 8071 SCIP* scip, /**< SCIP pointer */ 8072 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */ 8073 SCIP_DIVESET* diveset, /**< diving settings */ 8074 SCIP_SOL* sol, /**< solution */ 8075 SCIP_Bool* success /**< pointer to store */ 8076 ) 8077 { 8078 SCIP_VAR* bestvar = NULL; 8079 SCIP_Bool bestvarfixcomp = FALSE; 8080 SCIP_Real bestscore = SCIP_REAL_MIN; 8081 SCIP_CONSDATA* consdata; 8082 SCIP_CONS** conss; 8083 int nconss; 8084 int bestcons = -1; 8085 int c; 8086 8087 assert( scip != NULL ); 8088 assert( conshdlr != NULL ); 8089 assert( diveset != NULL ); 8090 assert( success != NULL ); 8091 8092 *success = FALSE; 8093 8094 /* get SOS1 constraints and number of SOS1 constraints */ 8095 conss = SCIPconshdlrGetConss(conshdlr); 8096 nconss = SCIPconshdlrGetNConss(conshdlr); 8097 8098 /* loop through all SOS1 constraints */ 8099 for (c = 0; c < nconss; ++c) 8100 { 8101 SCIP_VAR** vars; 8102 int nvars; 8103 int cnt = 0; 8104 int j; 8105 8106 consdata = SCIPconsGetData(conss[c]); 8107 assert( consdata != NULL ); 8108 8109 nvars = consdata->nvars; 8110 vars = consdata->vars; 8111 8112 /* check whether SOS1 constraint is violated */ 8113 for (j = 0; j < nvars && cnt < 2; ++j) 8114 { 8115 SCIP_VAR* var; 8116 8117 var = vars[j]; 8118 8119 /* check whether variable is nonzero w.r.t. sol and the bounds have not been fixed to zero by propagation */ 8120 if ( !SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, var)) 8121 && (!SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || !SCIPisFeasZero(scip, SCIPvarGetUbLocal(var))) ) 8122 ++cnt; 8123 } 8124 8125 /* if SOS1 constraint is not violated then continue with the next SOS1 constraint */ 8126 if ( cnt < 2 ) 8127 continue; 8128 8129 /* get diving score of every variable in constraint */ 8130 for (j = 0; j < nvars; ++j) 8131 { 8132 SCIP_VAR* var; 8133 SCIP_Real solval; 8134 SCIP_Real score; 8135 SCIP_Real bound; 8136 SCIP_Real fracval; 8137 SCIP_Real lb; 8138 SCIP_Real ub; 8139 SCIP_Bool fixcomp; /* whether to fix the complementary variables of the candidate in the SOS1 constraint to zero */ 8140 8141 var = vars[j]; 8142 solval = SCIPgetSolVal(scip, sol, var); 8143 lb = SCIPvarGetLbLocal(var); 8144 ub = SCIPvarGetUbLocal(var); 8145 8146 /* check whether variable is nonzero w.r.t. sol and the bounds have not been fixed to zero by propagation */ 8147 if ( ! SCIPisFeasZero(scip, solval) && ( ! SCIPisFeasZero(scip, lb) || ! SCIPisFeasZero(scip, ub) ) ) 8148 { 8149 /* compute (variable) bound of candidate */ 8150 if ( SCIPisFeasNegative(scip, solval) ) 8151 bound = lb; 8152 else 8153 bound = ub; 8154 8155 /* bound may have changed in propagation; ensure that fracval <= 1 */ 8156 if ( SCIPisFeasLT(scip, REALABS(bound), REALABS(solval)) ) 8157 bound = solval; 8158 8159 /* ensure finiteness */ 8160 bound = MIN(DIVINGCUTOFFVALUE, REALABS(bound)); /*lint !e666*/ 8161 fracval = MIN(DIVINGCUTOFFVALUE, REALABS(solval)); /*lint !e666*/ 8162 assert( ! SCIPisInfinity(scip, bound) ); 8163 assert( ! SCIPisInfinity(scip, fracval) ); 8164 assert( SCIPisPositive(scip, bound) ); 8165 8166 /* get fractionality of candidate */ 8167 fracval /= (bound + SCIPsumepsilon(scip)); 8168 8169 /* should SOS1 variables be scored by the diving heuristics specific score function; 8170 * otherwise use the score function of the SOS1 constraint handler 8171 */ 8172 if ( SCIPdivesetSupportsType(diveset, SCIP_DIVETYPE_SOS1VARIABLE) ) 8173 { 8174 SCIP_Bool roundup; 8175 8176 SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_SOS1VARIABLE, var, solval, fracval, 8177 &score, &roundup) ); 8178 8179 fixcomp = roundup; 8180 if ( SCIPisFeasNegative(scip, solval) ) 8181 fixcomp = !fixcomp; 8182 } 8183 else 8184 { 8185 /* we always fix the complementary variables of the candidate in the SOS1 constraint to zero */ 8186 fixcomp = TRUE; 8187 8188 /* score fractionality of candidate */ 8189 score = fracval; 8190 } 8191 8192 /* best candidate maximizes the score */ 8193 if ( score > bestscore ) 8194 { 8195 bestscore = score; 8196 8197 *success = TRUE; 8198 bestvar = var; 8199 bestcons = c; 8200 bestvarfixcomp = fixcomp; 8201 } 8202 } 8203 } 8204 } 8205 assert( !(*success) || bestvar != NULL ); 8206 8207 if ( *success ) 8208 { 8209 SCIP_VAR** vars; 8210 int nvars; 8211 int j; 8212 8213 consdata = SCIPconsGetData(conss[bestcons]); 8214 assert( consdata != NULL ); 8215 8216 nvars = consdata->nvars; 8217 vars = consdata->vars; 8218 8219 assert( bestcons >= 0 && bestcons < nconss ); 8220 8221 /* if the diving score voted for fixing the best variable to 0.0, we add this as the preferred bound change; 8222 * otherwise, fixing the complementary variables of the candidate in the SOS1 constraint to 0.0 is the preferred bound change. 8223 */ 8224 assert( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(bestvar)) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(bestvar)) ); 8225 8226 SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_FIXED, 0.0, !bestvarfixcomp) ); 8227 for (j = 0; j < nvars; ++j) 8228 { 8229 SCIP_VAR* var; 8230 8231 var = vars[j]; 8232 8233 /* if variable is not already fixed and is not the candidate variable */ 8234 if ( var != bestvar && ( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var)) ) ) 8235 { 8236 SCIP_CALL( SCIPaddDiveBoundChange(scip, var, SCIP_BRANCHDIR_FIXED, 0.0, bestvarfixcomp) ); 8237 } 8238 } 8239 } 8240 8241 return SCIP_OKAY; 8242 } 8243 8244 8245 /* --------------------initialization/deinitialization ------------------------*/ 8246 8247 /** check whether \f$x_1\f$ is a bound variable of \f$x_0\f$; i.e., \f$x_0 \leq c\cdot x_1\f$ or \f$x_0 \geq d\cdot x_1\f$ 8248 * for positive values \f$c, d\f$. If true, then add this information to the node data of the conflict graph. 8249 */ 8250 static 8251 SCIP_RETCODE detectVarboundSOS1( 8252 SCIP* scip, /**< SCIP pointer */ 8253 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */ 8254 SCIP_VAR* var0, /**< first variable */ 8255 SCIP_VAR* var1, /**< second variable */ 8256 SCIP_Real val0, /**< first coefficient */ 8257 SCIP_Real val1 /**< second coefficient */ 8258 ) 8259 { 8260 int node0; 8261 8262 assert( scip != NULL ); 8263 assert( conshdlrdata != NULL ); 8264 assert( var0 != NULL && var1 != NULL ); 8265 8266 /* get nodes of variable in the conflict graph (node = -1 if no SOS1 variable) */ 8267 node0 = varGetNodeSOS1(conshdlrdata, var0); 8268 8269 /* if var0 is an SOS1 variable */ 8270 if ( node0 >= 0 ) 8271 { 8272 SCIP_Real val; 8273 8274 assert( ! SCIPisFeasZero(scip, val0) ); 8275 val = -val1/val0; 8276 8277 /* check variable bound relation of variables */ 8278 8279 /* handle lower bound case */ 8280 if ( SCIPisFeasNegative(scip, val0) && SCIPisFeasNegative(scip, val) ) 8281 { 8282 SCIP_NODEDATA* nodedata; 8283 8284 /* get node data of the conflict graph */ 8285 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, node0); 8286 8287 /* @todo: maybe save multiple variable bounds for each SOS1 variable */ 8288 if ( nodedata->lbboundvar == NULL ) 8289 { 8290 /* add variable bound information to node data */ 8291 nodedata->lbboundvar = var1; 8292 nodedata->lbboundcoef = val; 8293 8294 SCIPdebugMsg(scip, "detected variable bound constraint %s >= %f %s.\n", SCIPvarGetName(var0), val, SCIPvarGetName(var1)); 8295 } 8296 } 8297 /* handle upper bound case */ 8298 else if ( SCIPisFeasPositive(scip, val0) && SCIPisFeasPositive(scip, val) ) 8299 { 8300 SCIP_NODEDATA* nodedata; 8301 assert( SCIPisFeasPositive(scip, val0) ); 8302 8303 /* get node data of the conflict graph */ 8304 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, node0); 8305 8306 if ( nodedata->ubboundvar == NULL ) 8307 { 8308 /* add variable bound information to node data */ 8309 nodedata->ubboundvar = var1; 8310 nodedata->ubboundcoef = val; 8311 8312 SCIPdebugMsg(scip, "detected variable bound constraint %s <= %f %s.\n", SCIPvarGetName(var0), val, SCIPvarGetName(var1)); 8313 } 8314 } 8315 } 8316 8317 return SCIP_OKAY; 8318 } 8319 8320 8321 /** pass connected component \f$C\f$ of the conflict graph and check whether all the variables correspond to a unique variable upper bound variable \f$z\f$, 8322 * i.e., \f$x_i \leq u_i z\f$ for every \f$i\in C\f$. 8323 * 8324 * @note if the bound variable is unique, then bound inequalities can be strengthened. 8325 */ 8326 static 8327 SCIP_RETCODE passConComponentVarbound( 8328 SCIP* scip, /**< SCIP pointer */ 8329 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 8330 int node, /**< current node of connected component */ 8331 SCIP_VAR* boundvar, /**< bound variable of connected component */ 8332 SCIP_Bool checklb, /**< whether to check lower bound variable (else upper bound variable) */ 8333 SCIP_Bool* processed, /**< states for each variable whether it has been processed */ 8334 int* concomp, /**< current connected component */ 8335 int* nconcomp, /**< pointer to store number of elements of connected component */ 8336 SCIP_Bool* unique /**< pointer to store whether bound variable is unique */ 8337 ) 8338 { 8339 int* succ; 8340 int nsucc; 8341 int s; 8342 8343 assert( scip != NULL ); 8344 assert( conflictgraph != NULL ); 8345 assert( processed != NULL ); 8346 assert( concomp != NULL ); 8347 assert( nconcomp != NULL ); 8348 assert( unique != NULL ); 8349 8350 processed[node] = TRUE;/*lint !e737*/ 8351 concomp[(*nconcomp)++] = node; 8352 8353 /* if bound variable of connected component without new node is unique */ 8354 if ( *unique ) 8355 { 8356 SCIP_NODEDATA* nodedata; 8357 SCIP_VAR* comparevar; 8358 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node); 8359 assert( nodedata != NULL ); 8360 8361 if ( checklb ) 8362 comparevar = nodedata->lbboundvar; 8363 else 8364 comparevar = nodedata->ubboundvar; 8365 8366 /* check whether bound variable is unique for connected component without new node */ 8367 if ( boundvar == NULL ) 8368 { 8369 if ( comparevar != NULL ) 8370 *unique = FALSE; 8371 } 8372 else 8373 { 8374 if ( comparevar == NULL ) 8375 *unique = FALSE; 8376 else if ( SCIPvarCompare(boundvar, comparevar) != 0 ) 8377 *unique = FALSE; 8378 } 8379 } 8380 8381 /* pass through successor variables */ 8382 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node); 8383 succ = SCIPdigraphGetSuccessors(conflictgraph, node); 8384 for (s = 0; s < nsucc; ++s) 8385 { 8386 if ( ! processed[succ[s]] ) 8387 SCIP_CALL( passConComponentVarbound(scip, conflictgraph, succ[s], boundvar, checklb, processed, concomp, nconcomp, unique) ); 8388 } 8389 8390 return SCIP_OKAY; 8391 } 8392 8393 8394 /** for each connected component \f$C\f$ of the conflict graph check whether all the variables correspond to a unique variable upper bound variable \f$z\f$ 8395 * (e.g., for the upper bound case this means that \f$x_i \leq u_i z\f$ for every \f$i\in C\f$). 8396 * 8397 * @note if the bound variable is unique, then bound inequalities can be strengthened. 8398 */ 8399 static 8400 SCIP_RETCODE checkConComponentsVarbound( 8401 SCIP* scip, /**< SCIP pointer */ 8402 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 8403 int nsos1vars, /**< number of SOS1 variables */ 8404 SCIP_Bool checklb /**< whether to check lower bound variable (else check upper bound variable) */ 8405 ) 8406 { 8407 SCIP_Bool* processed; /* states for each variable whether it has been processed */ 8408 int* concomp; /* current connected component */ 8409 int nconcomp; 8410 int j; 8411 8412 assert( scip != NULL ); 8413 assert( conflictgraph != NULL ); 8414 8415 /* allocate buffer arrays and initialize 'processed' array */ 8416 SCIP_CALL( SCIPallocBufferArray(scip, &processed, nsos1vars) ); 8417 SCIP_CALL( SCIPallocBufferArray(scip, &concomp, nsos1vars) ); 8418 for (j = 0; j < nsos1vars; ++j) 8419 processed[j] = FALSE; 8420 8421 /* run through all SOS1 variables */ 8422 for (j = 0; j < nsos1vars; ++j) 8423 { 8424 /* if variable belongs to a connected component that has not been processed so far */ 8425 if ( ! processed[j] ) 8426 { 8427 SCIP_NODEDATA* nodedata; 8428 SCIP_VAR* boundvar; 8429 SCIP_Bool unique; 8430 int* succ; 8431 int nsucc; 8432 int s; 8433 8434 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, j); 8435 assert( nodedata != NULL ); 8436 8437 if ( checklb ) 8438 boundvar = nodedata->lbboundvar; 8439 else 8440 boundvar = nodedata->ubboundvar; 8441 unique = TRUE; 8442 8443 processed[j] = TRUE; 8444 concomp[0] = j; 8445 nconcomp = 1; 8446 8447 /* pass through successor variables */ 8448 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j); 8449 succ = SCIPdigraphGetSuccessors(conflictgraph, j); 8450 for (s = 0; s < nsucc; ++s) 8451 { 8452 if ( ! processed[succ[s]] ) 8453 { 8454 SCIP_CALL( passConComponentVarbound(scip, conflictgraph, succ[s], boundvar, checklb, processed, concomp, &nconcomp, &unique) ); 8455 } 8456 } 8457 8458 /* if the connected component has a unique bound variable */ 8459 if ( unique && boundvar != NULL ) 8460 { 8461 for (s = 0; s < nconcomp; ++s) 8462 { 8463 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, concomp[s]); 8464 assert( processed[concomp[s]] == TRUE ); 8465 assert( nodedata != NULL ); 8466 8467 if ( checklb ) 8468 nodedata->lbboundcomp = TRUE; 8469 else 8470 nodedata->ubboundcomp = TRUE; 8471 } 8472 SCIPdebugMsg(scip, "Found a connected component of size <%i> with unique bound variable.\n", nconcomp); 8473 } 8474 } 8475 } 8476 8477 /* free buffer arrays */ 8478 SCIPfreeBufferArray(scip, &concomp); 8479 SCIPfreeBufferArray(scip, &processed); 8480 8481 return SCIP_OKAY; 8482 } 8483 8484 8485 /** check all linear constraints for variable bound constraints of the form \f$c\cdot z \leq x \leq d\cdot z\f$, where @p x is some SOS1 8486 * variable and @p z is some arbitrary variable (not necessarily binary) 8487 */ 8488 static 8489 SCIP_RETCODE checkLinearConssVarboundSOS1( 8490 SCIP* scip, /**< SCIP pointer */ 8491 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */ 8492 SCIP_CONS** linconss, /**< linear constraints */ 8493 int nlinconss /**< number of linear constraints */ 8494 ) 8495 { 8496 int c; 8497 8498 /* loop through linear constraints */ 8499 for (c = 0; c < nlinconss; ++c) 8500 { 8501 SCIP_CONS* lincons; 8502 int nvars; 8503 8504 lincons = linconss[c]; 8505 8506 /* variable bound constraints only contain two variables */ 8507 nvars = SCIPgetNVarsLinear(scip, lincons); 8508 if ( nvars == 2 ) 8509 { 8510 SCIP_VAR** vars; 8511 SCIP_Real* vals; 8512 SCIP_VAR* var0; 8513 SCIP_VAR* var1; 8514 SCIP_Real lhs; 8515 SCIP_Real rhs; 8516 8517 /* get constraint data */ 8518 vars = SCIPgetVarsLinear(scip, lincons); 8519 vals = SCIPgetValsLinear(scip, lincons); 8520 lhs = SCIPgetLhsLinear(scip, lincons); 8521 rhs = SCIPgetRhsLinear(scip, lincons); 8522 8523 var0 = vars[0]; 8524 var1 = vars[1]; 8525 assert( var0 != NULL && var1 != NULL ); 8526 8527 /* at least one variable should be an SOS1 variable */ 8528 if ( varIsSOS1(conshdlrdata, var0) || varIsSOS1(conshdlrdata, var1) ) 8529 { 8530 SCIP_Real val0; 8531 SCIP_Real val1; 8532 8533 /* check whether right hand side or left hand side of constraint is zero */ 8534 if ( SCIPisFeasZero(scip, lhs) ) 8535 { 8536 val0 = -vals[0]; 8537 val1 = -vals[1]; 8538 8539 /* check whether the two variables are in a variable bound relation */ 8540 SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var0, var1, val0, val1) ); 8541 SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var1, var0, val1, val0) ); 8542 } 8543 else if( SCIPisFeasZero(scip, rhs) ) 8544 { 8545 val0 = vals[0]; 8546 val1 = vals[1]; 8547 8548 /* check whether the two variables are in a variable bound relation */ 8549 SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var0, var1, val0, val1) ); 8550 SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var1, var0, val1, val0) ); 8551 } 8552 } 8553 } 8554 } 8555 8556 return SCIP_OKAY; 8557 } 8558 8559 8560 /** switch to SOS1 branching and separating bound iniqualities from SOS1 constraints if the SOS1 constraints do not overlap */ 8561 static 8562 SCIP_RETCODE checkSwitchNonoverlappingSOS1Methods( 8563 SCIP* scip, /**< SCIP pointer */ 8564 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */ 8565 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 8566 SCIP_CONS** conss, /**< SOS1 constraints */ 8567 int nconss /**< number of SOS1 constraints */ 8568 ) 8569 { 8570 SCIP_Bool nonoverlap = TRUE; 8571 int c; 8572 8573 /* loop through all SOS1 constraints */ 8574 if ( conshdlrdata->nsos1vars > 0 ) 8575 { 8576 for (c = 0; c < nconss && nonoverlap; ++c) 8577 { 8578 SCIP_CONSDATA* consdata; 8579 SCIP_VAR** vars; 8580 int notfixed = 0; 8581 int nvars; 8582 int i; 8583 8584 assert( conss[c] != NULL ); 8585 8586 /* get constraint data field of the constraint */ 8587 consdata = SCIPconsGetData(conss[c]); 8588 assert( consdata != NULL ); 8589 8590 /* get variables and number of variables of constraint */ 8591 nvars = consdata->nvars; 8592 vars = consdata->vars; 8593 8594 /* get number of variables of SOS1 constraint that are not fixed to zero */ 8595 for (i = 0; i < nvars; ++i) 8596 { 8597 if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(vars[i])) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(vars[i])) ) 8598 ++notfixed; 8599 } 8600 8601 /* check variables of SOS1 constraint */ 8602 for (i = 0; i < nvars; ++i) 8603 { 8604 int node; 8605 8606 assert( vars[i] != NULL ); 8607 8608 node = varGetNodeSOS1(conshdlrdata, vars[i]); 8609 assert( node >= 0 || ( SCIPisFeasZero(scip, SCIPvarGetLbLocal(vars[i])) && SCIPisFeasZero(scip, SCIPvarGetUbLocal(vars[i]))) ); 8610 assert( node < conshdlrdata->nsos1vars ); 8611 assert( node < 0 || SCIPdigraphGetNSuccessors(conflictgraph, node) >= notfixed-1 ); 8612 if ( node >= 0 && SCIPdigraphGetNSuccessors(conflictgraph, node) > notfixed-1 ) 8613 { 8614 nonoverlap = FALSE; 8615 break; 8616 } 8617 } 8618 } 8619 } 8620 8621 /* if the SOS1 constraints do not overlap */ 8622 if ( nonoverlap ) 8623 { 8624 if ( conshdlrdata->autosos1branch ) 8625 { 8626 conshdlrdata->switchsos1branch = TRUE; 8627 SCIPdebugMsg(scip, "Switched to SOS1 branching, since the SOS1 constraints do not overlap\n"); 8628 } 8629 8630 if ( conshdlrdata->autocutsfromsos1 ) 8631 { 8632 conshdlrdata->switchcutsfromsos1 = TRUE; 8633 SCIPdebugMsg(scip, "Switched to separating bound cuts from SOS1 constraints (and not from the conflict graph), since the SOS1 constraints do not overlap\n"); 8634 } 8635 } 8636 8637 return SCIP_OKAY; 8638 } 8639 8640 8641 /** sets node data of conflict graph nodes */ 8642 static 8643 SCIP_RETCODE computeNodeDataSOS1( 8644 SCIP* scip, /**< SCIP pointer */ 8645 SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */ 8646 int nsos1vars /**< number of SOS1 variables */ 8647 ) 8648 { 8649 SCIP_CONSHDLR* linconshdlr; 8650 SCIP_CONS** linconss; 8651 int nlinconss; 8652 8653 /* if no SOS1 variables exist -> exit */ 8654 if ( nsos1vars == 0 ) 8655 return SCIP_OKAY; 8656 8657 /* get constraint handler data of linear constraints */ 8658 linconshdlr = SCIPfindConshdlr(scip, "linear"); 8659 if ( linconshdlr == NULL ) 8660 return SCIP_OKAY; 8661 8662 /* get linear constraints and number of linear constraints */ 8663 nlinconss = SCIPconshdlrGetNConss(linconshdlr); 8664 linconss = SCIPconshdlrGetConss(linconshdlr); 8665 8666 /* check linear constraints for variable bound constraints */ 8667 SCIP_CALL( checkLinearConssVarboundSOS1(scip, conshdlrdata, linconss, nlinconss) ); 8668 8669 /* for each connected component of the conflict graph check whether all the variables correspond to a unique variable 8670 * upper bound variable */ 8671 SCIP_CALL( checkConComponentsVarbound(scip, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, TRUE) ); 8672 SCIP_CALL( checkConComponentsVarbound(scip, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, FALSE) ); 8673 8674 return SCIP_OKAY; 8675 } 8676 8677 8678 /** initialize conflictgraph and create hashmap for SOS1 variables */ 8679 static 8680 SCIP_RETCODE initConflictgraph( 8681 SCIP* scip, /**< SCIP pointer */ 8682 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 8683 SCIP_CONS** conss, /**< SOS1 constraints */ 8684 int nconss /**< number of SOS1 constraints */ 8685 ) 8686 { 8687 SCIP_Bool* nodecreated; /* nodecreated[i] = TRUE if a node in the conflict graph is already created for index i 8688 * (with i index of the original variables) */ 8689 int* nodeorig; /* nodeorig[i] = node of original variable x_i in the conflict graph */ 8690 int ntotalvars; 8691 int cntsos; 8692 int i; 8693 int j; 8694 int c; 8695 8696 assert( conshdlrdata != NULL ); 8697 assert( nconss == 0 || conss != NULL ); 8698 8699 /* get the number of original problem variables */ 8700 ntotalvars = SCIPgetNTotalVars(scip); 8701 8702 /* initialize vector 'nodecreated' */ 8703 SCIP_CALL( SCIPallocBufferArray(scip, &nodeorig, ntotalvars) ); 8704 SCIP_CALL( SCIPallocBufferArray(scip, &nodecreated, ntotalvars) ); 8705 for (i = 0; i < ntotalvars; ++i) 8706 nodecreated[i] = FALSE; 8707 8708 /* compute number of SOS1 variables */ 8709 cntsos = 0; 8710 for (c = 0; c < nconss; ++c) 8711 { 8712 SCIP_CONSDATA* consdata; 8713 SCIP_VAR** vars; 8714 int nvars; 8715 8716 assert( conss[c] != NULL ); 8717 8718 /* get constraint data field of the constraint */ 8719 consdata = SCIPconsGetData(conss[c]); 8720 assert( consdata != NULL ); 8721 8722 /* get variables and number of variables of constraint */ 8723 nvars = consdata->nvars; 8724 vars = consdata->vars; 8725 8726 /* update number of SOS1 variables */ 8727 for (i = 0; i < nvars; ++i) 8728 { 8729 SCIP_VAR* var; 8730 8731 var = vars[i]; 8732 8733 /* if the variable is not fixed to zero */ 8734 if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) 8735 { 8736 int ind; 8737 8738 ind = SCIPvarGetIndex(var); 8739 assert( ind >= 0 && ind < ntotalvars ); 8740 if ( ! nodecreated[ind] ) 8741 { 8742 nodecreated[ind] = TRUE; /* mark node as counted */ 8743 nodeorig[ind] = cntsos; 8744 ++cntsos; 8745 } 8746 } 8747 } 8748 } 8749 if ( cntsos <= 0 ) 8750 { 8751 /* free buffer arrays */ 8752 SCIPfreeBufferArray(scip, &nodecreated); 8753 SCIPfreeBufferArray(scip, &nodeorig); 8754 conshdlrdata->nsos1vars = 0; 8755 return SCIP_OKAY; 8756 } 8757 8758 /* reinitialize vector 'nodecreated' */ 8759 for (i = 0; i < ntotalvars; ++i) 8760 nodecreated[i] = FALSE; 8761 8762 /* create conflict graph */ 8763 SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->conflictgraph, cntsos) ); 8764 8765 /* set up hash map */ 8766 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), cntsos) ); 8767 8768 /* for every SOS1 constraint */ 8769 cntsos = 0; 8770 for (c = 0; c < nconss; ++c) 8771 { 8772 SCIP_CONSDATA* consdata; 8773 SCIP_VAR** vars; 8774 int nvars; 8775 8776 assert( conss[c] != NULL ); 8777 8778 /* get constraint data field of the constraint */ 8779 consdata = SCIPconsGetData(conss[c]); 8780 assert( consdata != NULL ); 8781 8782 /* get variables and number of variables of constraint */ 8783 nvars = consdata->nvars; 8784 vars = consdata->vars; 8785 8786 /* add edges to the conflict graph and create node data for each of its nodes */ 8787 for (i = 0; i < nvars; ++i) 8788 { 8789 SCIP_VAR* var; 8790 8791 var = vars[i]; 8792 8793 /* if the variable is not fixed to zero */ 8794 if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) 8795 { 8796 int indi; 8797 8798 indi = SCIPvarGetIndex(var); 8799 8800 if ( ! nodecreated[indi] ) 8801 { 8802 SCIP_NODEDATA* nodedata = NULL; 8803 8804 /* insert node number to hash map */ 8805 assert( ! SCIPhashmapExists(conshdlrdata->varhash, var) ); 8806 SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->varhash, var, cntsos) ); 8807 assert( cntsos == SCIPhashmapGetImageInt(conshdlrdata->varhash, var) ); 8808 assert( SCIPhashmapExists(conshdlrdata->varhash, var) ); 8809 8810 /* create node data */ 8811 SCIP_CALL( SCIPallocBlockMemory(scip, &nodedata) ); 8812 nodedata->var = var; 8813 nodedata->lbboundvar = NULL; 8814 nodedata->ubboundvar = NULL; 8815 nodedata->lbboundcoef = 0.0; 8816 nodedata->ubboundcoef = 0.0; 8817 nodedata->lbboundcomp = FALSE; 8818 nodedata->ubboundcomp = FALSE; 8819 8820 /* set node data */ 8821 SCIPdigraphSetNodeData(conshdlrdata->conflictgraph, (void*)nodedata, cntsos); 8822 8823 /* mark node and var data of node as created and update SOS1 counter */ 8824 nodecreated[indi] = TRUE; 8825 ++cntsos; 8826 } 8827 8828 /* add edges to the conflict graph */ 8829 for (j = i+1; j < nvars; ++j) 8830 { 8831 var = vars[j]; 8832 8833 /* if the variable is not fixed to zero */ 8834 if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) 8835 { 8836 int indj; 8837 8838 indj = SCIPvarGetIndex(var); 8839 8840 /* in case indi = indj the variable will be deleted in the presolving step */ 8841 if ( indi != indj ) 8842 { 8843 /* arcs have to be added 'safe' */ 8844 SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->conflictgraph, nodeorig[indi], nodeorig[indj], NULL) ); 8845 SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->conflictgraph, nodeorig[indj], nodeorig[indi], NULL) ); 8846 } 8847 } 8848 } 8849 } 8850 } 8851 } 8852 8853 /* set number of problem variables that are contained in at least one SOS1 constraint */ 8854 conshdlrdata->nsos1vars = cntsos; 8855 8856 /* free buffer arrays */ 8857 SCIPfreeBufferArray(scip, &nodecreated); 8858 SCIPfreeBufferArray(scip, &nodeorig); 8859 8860 /* sort successors in ascending order */ 8861 for (j = 0; j < conshdlrdata->nsos1vars; ++j) 8862 { 8863 int nsucc; 8864 8865 nsucc = SCIPdigraphGetNSuccessors(conshdlrdata->conflictgraph, j); 8866 SCIPsortInt(SCIPdigraphGetSuccessors(conshdlrdata->conflictgraph, j), nsucc); 8867 } 8868 8869 return SCIP_OKAY; 8870 } 8871 8872 8873 /** free conflict graph, nodedata and hashmap */ 8874 static 8875 SCIP_RETCODE freeConflictgraph( 8876 SCIP* scip, /**< SCIP pointer */ 8877 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */ 8878 ) 8879 { 8880 int j; 8881 8882 if ( conshdlrdata->conflictgraph == NULL ) 8883 { 8884 assert( conshdlrdata->nsos1vars == 0 ); 8885 return SCIP_OKAY; 8886 } 8887 8888 /* for every SOS1 variable */ 8889 assert( conshdlrdata->nsos1vars > 0 ); 8890 for (j = 0; j < conshdlrdata->nsos1vars; ++j) 8891 { 8892 SCIP_NODEDATA* nodedata; 8893 8894 /* get node data */ 8895 assert( conshdlrdata->conflictgraph != NULL ); 8896 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, j); 8897 assert( nodedata != NULL ); 8898 8899 /* free node data */ 8900 SCIPfreeBlockMemory(scip, &nodedata); 8901 SCIPdigraphSetNodeData(conshdlrdata->conflictgraph, NULL, j); 8902 } 8903 8904 /* free conflict graph and hash map */ 8905 assert( conshdlrdata->varhash != NULL ); 8906 SCIPhashmapFree(&conshdlrdata->varhash); 8907 SCIPdigraphFree(&conshdlrdata->conflictgraph); 8908 conshdlrdata->nsos1vars = 0; 8909 8910 assert( conshdlrdata->varhash == NULL ); 8911 assert( conshdlrdata->conflictgraph == NULL ); 8912 8913 return SCIP_OKAY; 8914 } 8915 8916 8917 /* ---------------------------- constraint handler callback methods ----------------------*/ 8918 8919 /** copy method for constraint handler plugins (called when SCIP copies plugins) */ 8920 static 8921 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySOS1) 8922 { /*lint --e{715}*/ 8923 assert( scip != NULL ); 8924 assert( conshdlr != NULL ); 8925 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 8926 8927 /* call inclusion method of constraint handler */ 8928 SCIP_CALL( SCIPincludeConshdlrSOS1(scip) ); 8929 8930 *valid = TRUE; 8931 8932 return SCIP_OKAY; 8933 } 8934 8935 8936 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */ 8937 static 8938 SCIP_DECL_CONSFREE(consFreeSOS1) 8939 { 8940 SCIP_CONSHDLRDATA* conshdlrdata; 8941 8942 assert( scip != NULL ); 8943 assert( conshdlr != NULL ); 8944 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 8945 8946 conshdlrdata = SCIPconshdlrGetData(conshdlr); 8947 assert(conshdlrdata != NULL); 8948 8949 /* free stack of variables fixed to nonzero (usually already freed in consExitsolSOS1 unless instance was solved during presolving) */ 8950 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars); /*lint !e737*/ 8951 8952 SCIPfreeBlockMemory(scip, &conshdlrdata); 8953 8954 return SCIP_OKAY; 8955 } 8956 8957 8958 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */ 8959 static 8960 SCIP_DECL_CONSINITSOL(consInitsolSOS1) 8961 { /*lint --e{715}*/ 8962 SCIP_CONSHDLRDATA* conshdlrdata; 8963 8964 assert( scip != NULL ); 8965 assert( conshdlr != NULL ); 8966 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 8967 8968 conshdlrdata = SCIPconshdlrGetData(conshdlr); 8969 assert( conshdlrdata != NULL ); 8970 8971 conshdlrdata->nsos1vars = 0; 8972 conshdlrdata->varhash = NULL; 8973 8974 if ( nconss > 0 ) 8975 { 8976 /* initialize conflict graph and hashmap for SOS1 variables */ 8977 SCIP_CALL( initConflictgraph(scip, conshdlrdata, conss, nconss) ); 8978 8979 /* add data to conflict graph nodes */ 8980 SCIP_CALL( computeNodeDataSOS1(scip, conshdlrdata, conshdlrdata->nsos1vars) ); 8981 8982 if ( ( conshdlrdata->autosos1branch || conshdlrdata->autocutsfromsos1 ) 8983 && ( ! conshdlrdata->switchsos1branch || ! conshdlrdata->switchcutsfromsos1 ) 8984 ) 8985 { 8986 /* switch to nonoverlapping methods if the SOS1 constraints do not overlap */ 8987 SCIP_CALL( checkSwitchNonoverlappingSOS1Methods(scip, conshdlrdata, conshdlrdata->conflictgraph, conss, nconss) ); 8988 } 8989 8990 /* initialize tclique graph */ 8991 SCIP_CALL( initTCliquegraph(scip, conshdlr, conshdlrdata, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars) ); 8992 8993 /* create local conflict graph if needed */ 8994 if ( conshdlrdata->addcomps ) 8995 { 8996 SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->localconflicts, conshdlrdata->nsos1vars) ); 8997 } 8998 8999 /* initialize stack of variables fixed to nonzero (memory may be already allocated in consTransSOS1()) */ 9000 if ( conshdlrdata->fixnonzerovars == NULL ) 9001 { 9002 conshdlrdata->maxnfixnonzerovars = conshdlrdata->nsos1vars; 9003 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars) ); 9004 } 9005 } 9006 9007 return SCIP_OKAY; 9008 } 9009 9010 9011 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */ 9012 static 9013 SCIP_DECL_CONSEXITSOL(consExitsolSOS1) 9014 { /*lint --e{715}*/ 9015 SCIP_CONSHDLRDATA* conshdlrdata; 9016 int c; 9017 9018 assert( scip != NULL ); 9019 assert( conshdlr != NULL ); 9020 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9021 conshdlrdata = SCIPconshdlrGetData(conshdlr); 9022 assert( conshdlrdata != NULL ); 9023 9024 /* check each constraint */ 9025 for (c = 0; c < nconss; ++c) 9026 { 9027 SCIP_CONSDATA* consdata; 9028 9029 assert( conss != NULL ); 9030 assert( conss[c] != NULL ); 9031 consdata = SCIPconsGetData(conss[c]); 9032 assert( consdata != NULL ); 9033 9034 SCIPdebugMsg(scip, "Exiting SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) ); 9035 9036 /* free rows */ 9037 if ( consdata->rowub != NULL ) 9038 { 9039 SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowub) ); 9040 } 9041 9042 if ( consdata->rowlb != NULL ) 9043 { 9044 SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowlb) ); 9045 } 9046 } 9047 9048 /* free implication graph */ 9049 if ( conshdlrdata->implgraph != NULL ) 9050 { 9051 SCIP_CALL( freeImplGraphSOS1(scip, conshdlrdata) ); 9052 } 9053 assert( conshdlrdata->implgraph == NULL ); 9054 9055 /* free tclique graph and tclique data */ 9056 if ( conshdlrdata->tcliquegraph != NULL ) 9057 { 9058 assert( conshdlrdata->tcliquedata != NULL ); 9059 SCIPfreeBlockMemory(scip, &conshdlrdata->tcliquedata); 9060 tcliqueFree(&conshdlrdata->tcliquegraph); 9061 } 9062 assert(conshdlrdata->tcliquegraph == NULL); 9063 assert(conshdlrdata->tcliquedata == NULL); 9064 9065 /* free stack of variables fixed to nonzero */ 9066 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars); /*lint !e737*/ 9067 conshdlrdata->nfixnonzerovars = 0; 9068 conshdlrdata->maxnfixnonzerovars = 0; 9069 9070 /* free graph for storing local conflicts */ 9071 if ( conshdlrdata->localconflicts != NULL ) 9072 SCIPdigraphFree(&conshdlrdata->localconflicts); 9073 assert( conshdlrdata->localconflicts == NULL ); 9074 9075 /* free conflict graph */ 9076 SCIP_CALL( freeConflictgraph(scip, conshdlrdata) ); 9077 assert( conshdlrdata->conflictgraph == NULL ); 9078 9079 return SCIP_OKAY; 9080 } 9081 9082 9083 /** frees specific constraint data */ 9084 static 9085 SCIP_DECL_CONSDELETE(consDeleteSOS1) 9086 { 9087 assert( scip != NULL ); 9088 assert( conshdlr != NULL ); 9089 assert( cons != NULL ); 9090 assert( consdata != NULL ); 9091 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9092 9093 SCIPdebugMsg(scip, "Deleting SOS1 constraint <%s>.\n", SCIPconsGetName(cons) ); 9094 9095 /* drop events on transformed variables */ 9096 if ( SCIPconsIsTransformed(cons) ) 9097 { 9098 SCIP_CONSHDLRDATA* conshdlrdata; 9099 int j; 9100 9101 /* get constraint handler data */ 9102 conshdlrdata = SCIPconshdlrGetData(conshdlr); 9103 assert( conshdlrdata != NULL ); 9104 assert( conshdlrdata->eventhdlr != NULL ); 9105 9106 for (j = 0; j < (*consdata)->nvars; ++j) 9107 { 9108 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->vars[j], EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr, 9109 (SCIP_EVENTDATA*)cons, -1) ); /*lint !e737 !e740*/ 9110 } 9111 } 9112 9113 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->maxvars); 9114 if ( (*consdata)->weights != NULL ) 9115 { 9116 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->maxvars); 9117 } 9118 9119 /* free rows */ 9120 if ( (*consdata)->rowub != NULL ) 9121 { 9122 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowub) ); 9123 } 9124 if ( (*consdata)->rowlb != NULL ) 9125 { 9126 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowlb) ); 9127 } 9128 assert( (*consdata)->rowub == NULL ); 9129 assert( (*consdata)->rowlb == NULL ); 9130 9131 SCIPfreeBlockMemory(scip, consdata); 9132 9133 return SCIP_OKAY; 9134 } 9135 9136 9137 /** transforms constraint data into data belonging to the transformed problem */ 9138 static 9139 SCIP_DECL_CONSTRANS(consTransSOS1) 9140 { 9141 SCIP_CONSDATA* consdata; 9142 SCIP_CONSHDLRDATA* conshdlrdata; 9143 SCIP_CONSDATA* sourcedata; 9144 char s[SCIP_MAXSTRLEN]; 9145 int j; 9146 9147 assert( scip != NULL ); 9148 assert( conshdlr != NULL ); 9149 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9150 assert( sourcecons != NULL ); 9151 assert( targetcons != NULL ); 9152 9153 /* get constraint handler data */ 9154 conshdlrdata = SCIPconshdlrGetData(conshdlr); 9155 assert( conshdlrdata != NULL ); 9156 assert( conshdlrdata->eventhdlr != NULL ); 9157 9158 SCIPdebugMsg(scip, "Transforming SOS1 constraint: <%s>.\n", SCIPconsGetName(sourcecons) ); 9159 9160 /* get data of original constraint */ 9161 sourcedata = SCIPconsGetData(sourcecons); 9162 assert( sourcedata != NULL ); 9163 assert( sourcedata->nvars > 0 ); 9164 assert( sourcedata->nvars <= sourcedata->maxvars ); 9165 9166 /* initialize stack of variables fixed to nonzero */ 9167 if ( conshdlrdata->fixnonzerovars == NULL ) 9168 { 9169 conshdlrdata->maxnfixnonzerovars = SCIPgetNTotalVars(scip); 9170 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars) ); 9171 } 9172 9173 /* create constraint data */ 9174 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) ); 9175 9176 consdata->nvars = sourcedata->nvars; 9177 consdata->maxvars = sourcedata->nvars; 9178 consdata->rowub = NULL; 9179 consdata->rowlb = NULL; 9180 consdata->nfixednonzeros = 0; 9181 consdata->local = sourcedata->local; 9182 9183 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, consdata->nvars) ); 9184 9185 /* if weights were used */ 9186 if ( sourcedata->weights != NULL ) 9187 { 9188 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, sourcedata->weights, consdata->nvars) ); 9189 } 9190 else 9191 consdata->weights = NULL; 9192 9193 for (j = 0; j < sourcedata->nvars; ++j) 9194 { 9195 assert( sourcedata->vars[j] != 0 ); 9196 SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->vars[j], &(consdata->vars[j])) ); 9197 9198 /* if variable is fixed to be nonzero */ 9199 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->vars[j])) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(consdata->vars[j])) ) 9200 ++(consdata->nfixednonzeros); 9201 } 9202 9203 /* create transformed constraint with the same flags */ 9204 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons)); 9205 SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata, 9206 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), 9207 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons), 9208 SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons), 9209 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), 9210 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) ); 9211 9212 /* catch bound change events on variable */ 9213 for (j = 0; j < consdata->nvars; ++j) 9214 { 9215 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[j], EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr, 9216 (SCIP_EVENTDATA*)*targetcons, NULL) ); /*lint !e740*/ 9217 } 9218 9219 #ifdef SCIP_DEBUG 9220 if ( consdata->nfixednonzeros > 0 ) 9221 { 9222 SCIPdebugMsg(scip, "constraint <%s> has %d variables fixed to be nonzero.\n", SCIPconsGetName(*targetcons), 9223 consdata->nfixednonzeros ); 9224 } 9225 #endif 9226 9227 return SCIP_OKAY; 9228 } 9229 9230 9231 /** presolving method of constraint handler */ 9232 static 9233 SCIP_DECL_CONSPRESOL(consPresolSOS1) 9234 { /*lint --e{715}*/ 9235 SCIP_CONSHDLRDATA* conshdlrdata; 9236 SCIPdebug( int oldnfixedvars = *nfixedvars; ) 9237 SCIPdebug( int oldnchgbds = *nchgbds; ) 9238 SCIPdebug( int oldndelconss = *ndelconss; ) 9239 SCIPdebug( int oldnupgdconss = *nupgdconss; ) 9240 int nremovedvars; 9241 9242 assert( scip != NULL ); 9243 assert( conshdlr != NULL ); 9244 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9245 assert( result != NULL ); 9246 9247 conshdlrdata = SCIPconshdlrGetData(conshdlr); 9248 assert( conshdlrdata != NULL ); 9249 9250 SCIPdebugMsg(scip, "Presolving SOS1 constraints.\n"); 9251 9252 *result = SCIP_DIDNOTRUN; 9253 9254 nremovedvars = 0; 9255 9256 /* only run if success if possible */ 9257 if( nconss > 0 && ( nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 ) ) 9258 { 9259 SCIP_Bool** adjacencymatrix = NULL; 9260 SCIP_DIGRAPH* conflictgraph; 9261 SCIP_EVENTHDLR* eventhdlr; 9262 int nsos1vars; 9263 int i; 9264 int j; 9265 9266 *result = SCIP_DIDNOTFIND; 9267 9268 /* get constraint handler data */ 9269 assert( SCIPconshdlrGetData(conshdlr) != NULL ); 9270 eventhdlr = SCIPconshdlrGetData(conshdlr)->eventhdlr; 9271 assert( eventhdlr != NULL ); 9272 9273 /* initialize conflict graph */ 9274 SCIP_CALL( initConflictgraph(scip, conshdlrdata, conss, nconss)); 9275 9276 /* get conflict graph and number of SOS1 variables */ 9277 conflictgraph = conshdlrdata->conflictgraph; 9278 nsos1vars = conshdlrdata->nsos1vars; 9279 if ( nsos1vars < 2 ) 9280 { 9281 SCIP_CALL( freeConflictgraph(scip, conshdlrdata)); 9282 return SCIP_OKAY; 9283 } 9284 9285 /* we do not create the adjacency matrix of the conflict graph if the number of SOS1 variables is larger than a predefined value */ 9286 if ( conshdlrdata->maxsosadjacency == -1 || nsos1vars <= conshdlrdata->maxsosadjacency ) 9287 { 9288 /* allocate buffer arrays for adjacency matrix */ 9289 SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix, nsos1vars) ); 9290 for (i = 0; i < nsos1vars; ++i) 9291 { 9292 SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix[i], i+1) );/*lint !e866*/ 9293 } 9294 9295 /* create adjacency matrix */ 9296 for (i = 0; i < nsos1vars; ++i) 9297 { 9298 for (j = 0; j < i+1; ++j) 9299 adjacencymatrix[i][j] = 0; 9300 } 9301 for (i = 0; i < nsos1vars; ++i) 9302 { 9303 int* succ; 9304 int nsucc; 9305 9306 succ = SCIPdigraphGetSuccessors(conflictgraph, i); 9307 nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i); 9308 9309 for (j = 0; j < nsucc; ++j) 9310 { 9311 if ( i > succ[j] ) 9312 adjacencymatrix[i][succ[j]] = 1; 9313 } 9314 } 9315 } 9316 else 9317 { 9318 SCIPdebugMsg(scip, "Adjacency matrix was not created since number of SOS1 variables (%d) is larger than %d.\n", nsos1vars, conshdlrdata->maxsosadjacency); 9319 } 9320 9321 /* perform one presolving round for SOS1 constraints */ 9322 SCIP_CALL( presolRoundConssSOS1(scip, eventhdlr, conshdlrdata, conflictgraph, adjacencymatrix, conss, nconss, nsos1vars, naddconss, ndelconss, nupgdconss, nfixedvars, &nremovedvars, result) ); 9323 9324 if ( adjacencymatrix != NULL ) 9325 { 9326 /* perform one presolving round for SOS1 variables */ 9327 if ( conshdlrdata->maxtightenbds != 0 && *result != SCIP_CUTOFF ) 9328 { 9329 SCIP_CALL( presolRoundVarsSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, nsos1vars, nfixedvars, nchgbds, naddconss, result) ); 9330 } 9331 9332 /* free adjacency matrix */ 9333 for (j = nsos1vars-1; j >= 0; --j) 9334 SCIPfreeBufferArrayNull(scip, &adjacencymatrix[j]); 9335 SCIPfreeBufferArrayNull(scip, &adjacencymatrix); 9336 } 9337 9338 /* free memory allocated in function initConflictgraph() */ 9339 SCIP_CALL( freeConflictgraph(scip, conshdlrdata)); 9340 } 9341 (*nchgcoefs) += nremovedvars; 9342 9343 SCIPdebug( SCIPdebugMsg(scip, "presolving fixed %d variables, changed %d bounds, removed %d variables, deleted %d constraints, and upgraded %d constraints.\n", 9344 *nfixedvars - oldnfixedvars, *nchgbds - oldnchgbds, nremovedvars, *ndelconss - oldndelconss, *nupgdconss - oldnupgdconss); ) 9345 9346 return SCIP_OKAY; 9347 } 9348 9349 9350 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */ 9351 static 9352 SCIP_DECL_CONSINITLP(consInitlpSOS1) 9353 { 9354 SCIP_CONSHDLRDATA* conshdlrdata; 9355 9356 assert( scip != NULL ); 9357 assert( conshdlr != NULL ); 9358 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9359 9360 conshdlrdata = SCIPconshdlrGetData(conshdlr); 9361 assert( conshdlrdata != NULL ); 9362 9363 *infeasible = FALSE; 9364 9365 /* checking for initial rows for SOS1 constraints */ 9366 if( conshdlrdata->boundcutsfromsos1 || conshdlrdata->switchcutsfromsos1 ) 9367 { 9368 SCIP_CALL( initsepaBoundInequalityFromSOS1Cons(scip, conshdlr, conshdlrdata, conss, nconss, NULL, FALSE, -1, NULL, infeasible) ); 9369 } 9370 9371 return SCIP_OKAY; 9372 } 9373 9374 9375 /** separation method of constraint handler for LP solutions */ 9376 static 9377 SCIP_DECL_CONSSEPALP(consSepalpSOS1) 9378 { /*lint --e{715}*/ 9379 assert( scip != NULL ); 9380 assert( conshdlr != NULL ); 9381 assert( conss != NULL ); 9382 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9383 assert( result != NULL ); 9384 9385 SCIP_CALL( separateSOS1(scip, conshdlr, NULL, nconss, conss, result) ); 9386 9387 return SCIP_OKAY; 9388 } 9389 9390 9391 /** separation method of constraint handler for arbitrary primal solutions */ 9392 static 9393 SCIP_DECL_CONSSEPASOL(consSepasolSOS1) 9394 { /*lint --e{715}*/ 9395 assert( scip != NULL ); 9396 assert( conshdlr != NULL ); 9397 assert( conss != NULL ); 9398 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9399 assert( result != NULL ); 9400 9401 SCIP_CALL( separateSOS1(scip, conshdlr, sol, nconss, conss, result) ); 9402 9403 return SCIP_OKAY; 9404 } 9405 9406 9407 /** constraint enforcing method of constraint handler for LP solutions */ 9408 static 9409 SCIP_DECL_CONSENFOLP(consEnfolpSOS1) 9410 { /*lint --e{715}*/ 9411 assert( scip != NULL ); 9412 assert( conshdlr != NULL ); 9413 assert( conss != NULL ); 9414 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9415 assert( result != NULL ); 9416 9417 SCIP_CALL( enforceSOS1(scip, conshdlr, nconss, conss, NULL, result) ); 9418 9419 return SCIP_OKAY; 9420 } 9421 9422 9423 /** constraint enforcing method of constraint handler for relaxation solutions */ 9424 static 9425 SCIP_DECL_CONSENFORELAX(consEnforelaxSOS1) 9426 { /*lint --e{715}*/ 9427 assert( scip != NULL ); 9428 assert( conshdlr != NULL ); 9429 assert( conss != NULL ); 9430 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9431 assert( result != NULL ); 9432 9433 SCIP_CALL( enforceSOS1(scip, conshdlr, nconss, conss, sol, result) ); 9434 9435 return SCIP_OKAY; 9436 } 9437 9438 9439 /** constraint enforcing method of constraint handler for pseudo solutions */ 9440 static 9441 SCIP_DECL_CONSENFOPS(consEnfopsSOS1) 9442 { /*lint --e{715}*/ 9443 assert( scip != NULL ); 9444 assert( conshdlr != NULL ); 9445 assert( conss != NULL ); 9446 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9447 assert( result != NULL ); 9448 9449 SCIP_CALL( enforceSOS1(scip, conshdlr, nconss, conss, NULL, result) ); 9450 9451 return SCIP_OKAY; 9452 } 9453 9454 9455 /** feasibility check method of constraint handler for integral solutions 9456 * 9457 * We simply check whether at most one variable is nonzero in the given solution. 9458 */ 9459 static 9460 SCIP_DECL_CONSCHECK(consCheckSOS1) 9461 { /*lint --e{715}*/ 9462 int c; 9463 9464 assert( scip != NULL ); 9465 assert( conshdlr != NULL ); 9466 assert( conss != NULL ); 9467 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9468 assert( result != NULL ); 9469 9470 *result = SCIP_FEASIBLE; 9471 9472 /* check each constraint */ 9473 for (c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c) 9474 { 9475 SCIP_CONSDATA* consdata; 9476 int j; 9477 int cnt; 9478 9479 cnt = 0; 9480 assert( conss[c] != NULL ); 9481 consdata = SCIPconsGetData(conss[c]); 9482 assert( consdata != NULL ); 9483 SCIPdebugMsg(scip, "Checking SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c])); 9484 9485 /* check all variables */ 9486 for (j = 0; j < consdata->nvars; ++j) 9487 { 9488 /* if variable is nonzero */ 9489 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) ) 9490 { 9491 ++cnt; 9492 9493 /* if more than one variable is nonzero */ 9494 if ( cnt > 1 ) 9495 { 9496 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) ); 9497 *result = SCIP_INFEASIBLE; 9498 9499 /* update constraint violation in solution */ 9500 if ( sol != NULL ) 9501 SCIPupdateSolConsViolation(scip, sol, 1.0, 1.0); 9502 9503 if ( printreason ) 9504 { 9505 int l; 9506 9507 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) ); 9508 SCIPinfoMessage(scip, NULL, ";\nviolation: "); 9509 9510 for (l = 0; l < consdata->nvars; ++l) 9511 { 9512 /* if variable is nonzero */ 9513 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[l])) ) 9514 { 9515 SCIPinfoMessage(scip, NULL, "<%s> = %.15g ", 9516 SCIPvarGetName(consdata->vars[l]), SCIPgetSolVal(scip, sol, consdata->vars[l])); 9517 } 9518 } 9519 SCIPinfoMessage(scip, NULL, "\n"); 9520 } 9521 } 9522 } 9523 } 9524 } 9525 9526 return SCIP_OKAY; 9527 } 9528 9529 9530 /** domain propagation method of constraint handler */ 9531 static 9532 SCIP_DECL_CONSPROP(consPropSOS1) 9533 { /*lint --e{715}*/ 9534 SCIP_CONSHDLRDATA* conshdlrdata; 9535 SCIP_DIGRAPH* conflictgraph; 9536 SCIP_DIGRAPH* implgraph; 9537 int ngen = 0; 9538 9539 assert( scip != NULL ); 9540 assert( conshdlr != NULL ); 9541 assert( conss != NULL ); 9542 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9543 assert( result != NULL ); 9544 assert( SCIPisTransformed(scip) ); 9545 9546 /* return if number of SOS1 constraints is zero */ 9547 if ( nconss < 1 ) 9548 { 9549 *result = SCIP_DIDNOTRUN; 9550 return SCIP_OKAY; 9551 } 9552 *result = SCIP_DIDNOTFIND; 9553 9554 /* get constraint handler data */ 9555 conshdlrdata = SCIPconshdlrGetData(conshdlr); 9556 assert( conshdlrdata != NULL ); 9557 9558 /* get conflict graph */ 9559 conflictgraph = conshdlrdata->conflictgraph; 9560 9561 /* get/initialize implication graph */ 9562 implgraph = conshdlrdata->implgraph; 9563 if ( implgraph == NULL && conshdlrdata->implprop && conflictgraph != NULL ) 9564 { 9565 if ( SCIPgetDepth(scip) == 0 ) 9566 { 9567 SCIP_Bool success; 9568 SCIP_Bool cutoff; 9569 int nchbds; 9570 9571 SCIP_CALL( initImplGraphSOS1(scip, conshdlrdata, conflictgraph, conshdlrdata->nsos1vars, conshdlrdata->maxtightenbds, &nchbds, &cutoff, &success) ); 9572 if ( ! success ) 9573 conshdlrdata->implprop = FALSE; 9574 9575 if ( cutoff ) 9576 { 9577 *result = SCIP_CUTOFF; 9578 return SCIP_OKAY; 9579 } 9580 else if ( nchbds > 0 ) 9581 *result = SCIP_REDUCEDDOM; 9582 implgraph = conshdlrdata->implgraph; 9583 } 9584 else 9585 conshdlrdata->implprop = FALSE; 9586 } 9587 9588 /* if conflict graph propagation shall be used */ 9589 if ( conshdlrdata->conflictprop && conflictgraph != NULL ) 9590 { 9591 SCIP_VAR** fixnonzerovars; 9592 int nfixnonzerovars; 9593 int j; 9594 9595 assert( nconss > 0 ); 9596 9597 /* stack of variables fixed to nonzero */ 9598 nfixnonzerovars = conshdlrdata->nfixnonzerovars; 9599 fixnonzerovars = conshdlrdata->fixnonzerovars; 9600 assert( fixnonzerovars != NULL ); 9601 9602 /* check each variable from stack */ 9603 for (j = 0; j < nfixnonzerovars; ++j) 9604 { 9605 SCIP_VAR* var; 9606 9607 var = fixnonzerovars[j]; 9608 if ( var != NULL ) 9609 { 9610 int node; 9611 node = varGetNodeSOS1(conshdlrdata, var); 9612 9613 /* if variable is involved in an SOS1 constraint */ 9614 if ( node >= 0 ) 9615 { 9616 assert( varGetNodeSOS1(conshdlrdata, var) < conshdlrdata->nsos1vars ); 9617 SCIPdebugMsg(scip, "Propagating SOS1 variable <%s>.\n", SCIPvarGetName(var) ); 9618 9619 /* if zero is outside the domain of variable */ 9620 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(var)) ) 9621 { 9622 SCIP_Bool cutoff; 9623 9624 SCIP_CALL( propVariableNonzero(scip, conflictgraph, implgraph, conss[0], node, conshdlrdata->implprop, &cutoff, &ngen) ); 9625 if ( cutoff ) 9626 { 9627 *result = SCIP_CUTOFF; 9628 return SCIP_OKAY; 9629 } 9630 } 9631 } 9632 } 9633 } 9634 } 9635 conshdlrdata->nfixnonzerovars = 0; 9636 9637 /* if SOS1 constraint propagation shall be used */ 9638 if ( conshdlrdata->sosconsprop || conflictgraph == NULL ) 9639 { 9640 int c; 9641 9642 /* check each constraint */ 9643 for (c = 0; c < nconss; ++c) 9644 { 9645 SCIP_CONS* cons; 9646 SCIP_CONSDATA* consdata; 9647 SCIP_Bool cutoff; 9648 9649 assert( conss[c] != NULL ); 9650 cons = conss[c]; 9651 consdata = SCIPconsGetData(cons); 9652 assert( consdata != NULL ); 9653 SCIPdebugMsg(scip, "Propagating SOS1 constraint <%s>.\n", SCIPconsGetName(cons) ); 9654 9655 SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) ); 9656 if ( cutoff ) 9657 { 9658 *result = SCIP_CUTOFF; 9659 return SCIP_OKAY; 9660 } 9661 } 9662 } 9663 9664 SCIPdebugMsg(scip, "Propagated %d domains.\n", ngen); 9665 if ( ngen > 0 ) 9666 *result = SCIP_REDUCEDDOM; 9667 9668 return SCIP_OKAY; 9669 } 9670 9671 9672 /** propagation conflict resolving method of constraint handler 9673 * 9674 * We check which bound changes were the reason for infeasibility. We 9675 * use that @a inferinfo stores the index of the variable that has 9676 * bounds that fix it to be nonzero (these bounds are the reason). */ 9677 static 9678 SCIP_DECL_CONSRESPROP(consRespropSOS1) 9679 { /*lint --e{715}*/ 9680 SCIP_VAR* var; 9681 9682 assert( scip != NULL ); 9683 assert( cons != NULL ); 9684 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9685 assert( infervar != NULL ); 9686 assert( bdchgidx != NULL ); 9687 assert( result != NULL ); 9688 9689 *result = SCIP_DIDNOTFIND; 9690 SCIPdebugMsg(scip, "Propagation resolution method of SOS1 constraint <%s>.\n", SCIPconsGetName(cons)); 9691 9692 /* check whether conflict was detected in variable propagation or constraint propagation */ 9693 if ( inferinfo < 0 ) 9694 { 9695 SCIP_CONSHDLRDATA* conshdlrdata; 9696 9697 assert( conshdlr != NULL ); 9698 9699 /* get constraint handler data */ 9700 conshdlrdata = SCIPconshdlrGetData(conshdlr); 9701 assert( conshdlrdata != NULL ); 9702 assert( conshdlrdata->conflictgraph != NULL ); 9703 assert( inferinfo >= -conshdlrdata->maxnfixnonzerovars ); 9704 assert( inferinfo >= -conshdlrdata->nsos1vars ); 9705 assert( inferinfo <= -1 ); 9706 9707 var = SCIPnodeGetVarSOS1(conshdlrdata->conflictgraph, -inferinfo - 1); /*lint !e2704*/ 9708 } 9709 else 9710 { 9711 SCIP_CONSDATA* consdata; 9712 9713 /* get constraint data */ 9714 consdata = SCIPconsGetData(cons); 9715 assert( consdata != NULL ); 9716 assert( inferinfo < consdata->nvars ); 9717 9718 var = consdata->vars[inferinfo]; 9719 } 9720 assert( var != NULL ); 9721 assert( var != infervar ); 9722 9723 /* check if lower bound of var was the reason */ 9724 if ( SCIPisFeasPositive(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) ) 9725 { 9726 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) ); 9727 *result = SCIP_SUCCESS; 9728 } 9729 9730 /* check if upper bound of var was the reason */ 9731 if ( SCIPisFeasNegative(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) ) 9732 { 9733 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) ); 9734 *result = SCIP_SUCCESS; 9735 } 9736 9737 return SCIP_OKAY; 9738 } 9739 9740 9741 /** variable rounding lock method of constraint handler 9742 * 9743 * Let lb and ub be the lower and upper bounds of a 9744 * variable. Preprocessing usually makes sure that lb <= 0 <= ub. 9745 * 9746 * - If lb < 0 then rounding down may violate the constraint. 9747 * - If ub > 0 then rounding up may violated the constraint. 9748 * - If lb > 0 or ub < 0 then the constraint is infeasible and we do 9749 * not have to deal with it here. 9750 * - If lb == 0 then rounding down does not violate the constraint. 9751 * - If ub == 0 then rounding up does not violate the constraint. 9752 */ 9753 static 9754 SCIP_DECL_CONSLOCK(consLockSOS1) 9755 { 9756 SCIP_CONSDATA* consdata; 9757 SCIP_VAR** vars; 9758 int nvars; 9759 int j; 9760 9761 assert( scip != NULL ); 9762 assert( conshdlr != NULL ); 9763 assert( cons != NULL ); 9764 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9765 assert(locktype == SCIP_LOCKTYPE_MODEL); 9766 9767 consdata = SCIPconsGetData(cons); 9768 assert( consdata != NULL ); 9769 9770 SCIPdebugMsg(scip, "Locking constraint <%s>.\n", SCIPconsGetName(cons)); 9771 9772 vars = consdata->vars; 9773 nvars = consdata->nvars; 9774 assert( vars != NULL ); 9775 9776 for (j = 0; j < nvars; ++j) 9777 { 9778 SCIP_VAR* var; 9779 var = vars[j]; 9780 9781 /* if lower bound is negative, rounding down may violate constraint */ 9782 if ( SCIPisFeasNegative(scip, SCIPvarGetLbGlobal(var)) ) 9783 { 9784 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlockspos, nlocksneg) ); 9785 } 9786 9787 /* additionally: if upper bound is positive, rounding up may violate constraint */ 9788 if ( SCIPisFeasPositive(scip, SCIPvarGetUbGlobal(var)) ) 9789 { 9790 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlocksneg, nlockspos) ); 9791 } 9792 } 9793 9794 return SCIP_OKAY; 9795 } 9796 9797 9798 /** constraint display method of constraint handler */ 9799 static 9800 SCIP_DECL_CONSPRINT(consPrintSOS1) 9801 { /*lint --e{715}*/ 9802 SCIP_CONSDATA* consdata; 9803 int j; 9804 9805 assert( scip != NULL ); 9806 assert( conshdlr != NULL ); 9807 assert( cons != NULL ); 9808 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9809 9810 consdata = SCIPconsGetData(cons); 9811 assert( consdata != NULL ); 9812 9813 for (j = 0; j < consdata->nvars; ++j) 9814 { 9815 if ( j > 0 ) 9816 SCIPinfoMessage(scip, file, ", "); 9817 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[j], FALSE) ); 9818 if ( consdata->weights == NULL ) 9819 SCIPinfoMessage(scip, file, " (%d)", j+1); 9820 else 9821 SCIPinfoMessage(scip, file, " (%3.2f)", consdata->weights[j]); 9822 } 9823 9824 return SCIP_OKAY; 9825 } 9826 9827 9828 /** constraint copying method of constraint handler */ 9829 static 9830 SCIP_DECL_CONSCOPY(consCopySOS1) 9831 { /*lint --e{715}*/ 9832 SCIP_CONSDATA* sourceconsdata; 9833 SCIP_VAR** sourcevars; 9834 SCIP_VAR** targetvars; 9835 SCIP_Real* targetweights = NULL; 9836 const char* consname; 9837 int nvars; 9838 int v; 9839 9840 assert( scip != NULL ); 9841 assert( sourcescip != NULL ); 9842 assert( sourcecons != NULL ); 9843 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 ); 9844 assert( valid != NULL ); 9845 9846 *valid = TRUE; 9847 9848 if ( name != NULL ) 9849 consname = name; 9850 else 9851 consname = SCIPconsGetName(sourcecons); 9852 9853 SCIPdebugMsg(scip, "Copying SOS1 constraint <%s> ...\n", consname); 9854 9855 sourceconsdata = SCIPconsGetData(sourcecons); 9856 assert( sourceconsdata != NULL ); 9857 9858 /* get variables and weights of the source constraint */ 9859 nvars = sourceconsdata->nvars; 9860 assert( nvars >= 0 ); 9861 9862 /* duplicate weights array */ 9863 if ( sourceconsdata->weights != NULL ) 9864 { 9865 SCIP_CALL( SCIPduplicateBufferArray(sourcescip, &targetweights, sourceconsdata->weights, nvars) ); 9866 } 9867 9868 /* get copied variables in target SCIP */ 9869 sourcevars = sourceconsdata->vars; 9870 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetvars, nvars) ); 9871 for (v = 0; v < nvars && *valid; ++v) 9872 { 9873 assert( sourcevars != NULL ); 9874 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &(targetvars[v]), varmap, consmap, global, valid) ); 9875 } 9876 9877 /* only create the target constraint, if all variables were be copied */ 9878 if ( *valid ) 9879 { 9880 SCIP_CALL( SCIPcreateConsSOS1(scip, cons, consname, nvars, targetvars, targetweights, 9881 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) ); 9882 } 9883 9884 /* free buffer array */ 9885 SCIPfreeBufferArray(sourcescip, &targetvars); 9886 SCIPfreeBufferArrayNull(sourcescip, &targetweights); 9887 9888 return SCIP_OKAY; 9889 } 9890 9891 9892 /** constraint parsing method of constraint handler */ 9893 static 9894 SCIP_DECL_CONSPARSE(consParseSOS1) 9895 { /*lint --e{715}*/ 9896 SCIP_VAR* var; 9897 SCIP_Real weight; 9898 const char* s; 9899 char* t; 9900 9901 assert(scip != NULL); 9902 assert(conshdlr != NULL); 9903 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 9904 assert(cons != NULL); 9905 assert(success != NULL); 9906 9907 *success = TRUE; 9908 s = str; 9909 9910 /* create empty SOS1 constraint */ 9911 SCIP_CALL( SCIPcreateConsSOS1(scip, cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) ); 9912 9913 /* loop through string */ 9914 while( *s != '\0' ) 9915 { 9916 /* parse variable name */ 9917 SCIP_CALL( SCIPparseVarName(scip, s, &var, &t) ); 9918 9919 if( var == NULL ) 9920 break; 9921 9922 /* skip until beginning of weight */ 9923 t = strchr(t, '('); 9924 9925 if( t == NULL ) 9926 { 9927 SCIPerrorMessage("Syntax error: expected opening '(' at input: %s\n", s); 9928 *success = FALSE; 9929 break; 9930 } 9931 9932 s = t; 9933 9934 /* skip '(' */ 9935 ++s; 9936 9937 /* find weight */ 9938 weight = strtod(s, &t); 9939 9940 if( t == NULL ) 9941 { 9942 SCIPerrorMessage("Syntax error during parsing of the weight: %s\n", s); 9943 *success = FALSE; 9944 break; 9945 } 9946 9947 s = t; 9948 9949 /* skip until ending of weight */ 9950 t = strchr(t, ')'); 9951 9952 if( t == NULL ) 9953 { 9954 SCIPerrorMessage("Syntax error: expected closing ')' at input %s\n", s); 9955 *success = FALSE; 9956 break; 9957 } 9958 9959 s = t; 9960 9961 /* skip ')' */ 9962 ++s; 9963 9964 /* skip white space */ 9965 SCIP_CALL( SCIPskipSpace((char**)&s) ); 9966 9967 /* skip ',' */ 9968 if( *s == ',' ) 9969 ++s; 9970 9971 /* add variable */ 9972 SCIP_CALL( SCIPaddVarSOS1(scip, *cons, var, weight) ); 9973 } 9974 9975 if( !*success ) 9976 SCIP_CALL( SCIPreleaseCons(scip, cons) ); 9977 9978 return SCIP_OKAY; 9979 } 9980 9981 9982 /** constraint method of constraint handler which returns the variables (if possible) */ 9983 static 9984 SCIP_DECL_CONSGETVARS(consGetVarsSOS1) 9985 { /*lint --e{715}*/ 9986 SCIP_CONSDATA* consdata; 9987 9988 consdata = SCIPconsGetData(cons); 9989 assert(consdata != NULL); 9990 9991 if( varssize < consdata->nvars ) 9992 (*success) = FALSE; 9993 else 9994 { 9995 assert(vars != NULL); 9996 9997 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars); 9998 (*success) = TRUE; 9999 } 10000 10001 return SCIP_OKAY; 10002 } 10003 10004 10005 /** constraint method of constraint handler which returns the number of variables (if possible) */ 10006 static 10007 SCIP_DECL_CONSGETNVARS(consGetNVarsSOS1) 10008 { /*lint --e{715}*/ 10009 SCIP_CONSDATA* consdata; 10010 10011 consdata = SCIPconsGetData(cons); 10012 assert(consdata != NULL); 10013 10014 (*nvars) = consdata->nvars; 10015 (*success) = TRUE; 10016 10017 return SCIP_OKAY; 10018 } 10019 10020 10021 /* ---------------- Callback methods of event handler ---------------- */ 10022 10023 /** exec the event handler 10024 * 10025 * We update the number of variables fixed to be nonzero 10026 */ 10027 static 10028 SCIP_DECL_EVENTEXEC(eventExecSOS1) 10029 { 10030 SCIP_CONSHDLRDATA* conshdlrdata; 10031 SCIP_EVENTTYPE eventtype; 10032 SCIP_CONSHDLR* conshdlr; 10033 SCIP_CONSDATA* consdata; 10034 SCIP_CONS* cons; 10035 SCIP_VAR* var; 10036 SCIP_Real oldbound; 10037 SCIP_Real newbound; 10038 10039 assert( eventhdlr != NULL ); 10040 assert( eventdata != NULL ); 10041 assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0 ); 10042 assert( event != NULL ); 10043 10044 cons = (SCIP_CONS*)eventdata; 10045 assert( cons != NULL ); 10046 consdata = SCIPconsGetData(cons); 10047 assert( 0 <= consdata->nfixednonzeros && consdata->nfixednonzeros <= consdata->nvars ); 10048 10049 oldbound = SCIPeventGetOldbound(event); 10050 newbound = SCIPeventGetNewbound(event); 10051 10052 eventtype = SCIPeventGetType(event); 10053 switch ( eventtype ) 10054 { 10055 case SCIP_EVENTTYPE_LBTIGHTENED: 10056 /* if variable is now fixed to be nonzero */ 10057 if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) ) 10058 { 10059 conshdlr = SCIPconsGetHdlr(cons); 10060 assert( conshdlr != NULL ); 10061 conshdlrdata = SCIPconshdlrGetData(conshdlr); 10062 assert( conshdlrdata != NULL ); 10063 10064 /* store variable fixed to be nonzero on stack */ 10065 assert( 0 <= conshdlrdata->nfixnonzerovars && conshdlrdata->nfixnonzerovars <= SCIPgetNTotalVars(scip) ); 10066 if ( conshdlrdata->nfixnonzerovars < conshdlrdata->maxnfixnonzerovars ) 10067 { 10068 assert( conshdlrdata->fixnonzerovars != NULL ); 10069 assert( SCIPeventGetVar(event) != NULL ); 10070 conshdlrdata->fixnonzerovars[conshdlrdata->nfixnonzerovars++] = SCIPeventGetVar(event); 10071 } 10072 10073 ++(consdata->nfixednonzeros); 10074 } 10075 break; 10076 10077 case SCIP_EVENTTYPE_UBTIGHTENED: 10078 /* if variable is now fixed to be nonzero */ 10079 if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) ) 10080 { 10081 conshdlr = SCIPconsGetHdlr(cons); 10082 assert( conshdlr != NULL ); 10083 conshdlrdata = SCIPconshdlrGetData(conshdlr); 10084 assert( conshdlrdata != NULL ); 10085 10086 /* store variable fixed to be nonzero on stack */ 10087 assert( 0 <= conshdlrdata->nfixnonzerovars && conshdlrdata->nfixnonzerovars <= SCIPgetNTotalVars(scip) ); 10088 if ( conshdlrdata->nfixnonzerovars < conshdlrdata->maxnfixnonzerovars ) 10089 { 10090 assert( conshdlrdata->fixnonzerovars != NULL ); 10091 assert( SCIPeventGetVar(event) != NULL ); 10092 conshdlrdata->fixnonzerovars[conshdlrdata->nfixnonzerovars++] = SCIPeventGetVar(event); 10093 } 10094 10095 ++(consdata->nfixednonzeros); 10096 } 10097 break; 10098 10099 case SCIP_EVENTTYPE_LBRELAXED: 10100 /* if variable is not fixed to be nonzero anymore */ 10101 if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) ) 10102 --(consdata->nfixednonzeros); 10103 break; 10104 10105 case SCIP_EVENTTYPE_UBRELAXED: 10106 /* if variable is not fixed to be nonzero anymore */ 10107 if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) ) 10108 --(consdata->nfixednonzeros); 10109 break; 10110 10111 case SCIP_EVENTTYPE_GLBCHANGED: 10112 var = SCIPeventGetVar(event); 10113 assert(var != NULL); 10114 10115 /* global lower bound is not negative anymore -> remove down lock */ 10116 if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) ) 10117 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) ); 10118 /* global lower bound turned negative -> add down lock */ 10119 else if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) ) 10120 SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, FALSE) ); 10121 break; 10122 10123 case SCIP_EVENTTYPE_GUBCHANGED: 10124 var = SCIPeventGetVar(event); 10125 assert(var != NULL); 10126 10127 /* global upper bound is not positive anymore -> remove up lock */ 10128 if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) ) 10129 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) ); 10130 /* global upper bound turned positive -> add up lock */ 10131 else if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) ) 10132 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) ); 10133 break; 10134 10135 default: 10136 SCIPerrorMessage("invalid event type.\n"); 10137 return SCIP_INVALIDDATA; 10138 } 10139 assert( 0 <= consdata->nfixednonzeros && consdata->nfixednonzeros <= consdata->nvars ); 10140 10141 SCIPdebugMsg(scip, "changed bound of variable <%s> from %f to %f (nfixednonzeros: %d).\n", SCIPvarGetName(SCIPeventGetVar(event)), 10142 oldbound, newbound, consdata->nfixednonzeros); 10143 10144 return SCIP_OKAY; 10145 } 10146 10147 10148 /** constraint handler method to determine a diving variable by assigning a variable and two values for diving */ 10149 static 10150 SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsSOS1) 10151 { 10152 SCIP_CONSHDLRDATA* conshdlrdata; 10153 10154 assert( scip != NULL ); 10155 assert( conshdlr != NULL ); 10156 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 ); 10157 assert( diveset != NULL ); 10158 assert( success != NULL ); 10159 assert( infeasible != NULL ); 10160 10161 *infeasible = FALSE; 10162 *success = FALSE; 10163 10164 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 ) 10165 { 10166 SCIPerrorMessage("not an SOS1 constraint handler.\n"); 10167 return SCIP_INVALIDDATA; 10168 } 10169 conshdlrdata = SCIPconshdlrGetData(conshdlr); 10170 assert( conshdlrdata != NULL ); 10171 10172 /* if the SOS1 constraints do not overlap, we apply a faster method getDiveBdChgsSOS1constraints() that does not make use of the conflict graph; 10173 * for overlapping SOS1 constraints we apply the method getDiveBdChgsSOS1conflictgraph(), which then may produce better results (e.g. due to more 10174 * diving candidates) */ 10175 if ( conshdlrdata->switchsos1branch ) 10176 { 10177 SCIP_CALL( getDiveBdChgsSOS1constraints(scip, conshdlr, diveset, sol, success) ); 10178 } 10179 else 10180 { 10181 SCIP_CALL( getDiveBdChgsSOS1conflictgraph(scip, conshdlr, diveset, sol, success) ); 10182 } 10183 10184 return SCIP_OKAY; 10185 } 10186 10187 10188 /** constraint handler method which returns the permutation symmetry detection graph of a constraint */ 10189 static 10190 SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphSOS1) 10191 { /*lint --e{715}*/ 10192 SCIP_CONSDATA* consdata; 10193 SCIP_VAR** consvars; 10194 SCIP_VAR** locvars; 10195 SCIP_Real* locvals; 10196 SCIP_Real constant = 0.0; 10197 int consnodeidx; 10198 int nodeidx; 10199 int nconsvars; 10200 int nlocvars; 10201 int nvars; 10202 int i; 10203 10204 consdata = SCIPconsGetData(cons); 10205 assert(consdata != NULL); 10206 10207 /* get active variables of the constraint */ 10208 nvars = SCIPgetNVars(scip); 10209 nconsvars = consdata->nvars; 10210 consvars = SCIPgetVarsSOS1(scip, cons); 10211 assert(consvars != NULL); 10212 10213 SCIP_CALL( SCIPallocBufferArray(scip, &locvars, nvars) ); 10214 SCIP_CALL( SCIPallocBufferArray(scip, &locvals, nvars) ); 10215 10216 /* add node initializing constraint (with artificial rhs) */ 10217 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, 0.0, 0.0, &consnodeidx) ); 10218 10219 /* for all (aggregations of) variables, add a node to graph and connect it with the root */ 10220 for( i = 0; i < nconsvars; ++i ) 10221 { 10222 locvars[0] = consvars[i]; 10223 locvals[0] = 1.0; 10224 constant = 0.0; 10225 nlocvars = 1; 10226 10227 /* ignore weights of SOS1 constraint (variables are sorted according to these weights) */ 10228 SCIP_CALL( SCIPgetActiveVariables(scip, SYM_SYMTYPE_PERM, &locvars, &locvals, 10229 &nlocvars, &constant, SCIPisTransformed(scip)) ); 10230 10231 if( nlocvars == 1 && SCIPisZero(scip, constant) && SCIPisEQ(scip, locvals[0], 1.0) ) 10232 { 10233 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, locvars[0]); 10234 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, nodeidx, FALSE, 0.0) ); 10235 } 10236 else 10237 { 10238 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &nodeidx) ); /*lint !e641*/ 10239 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, nodeidx, FALSE, 0.0) ); 10240 SCIP_CALL( SCIPaddSymgraphVarAggegration(scip, graph, nodeidx, locvars, locvals, nlocvars, constant) ); 10241 } 10242 } 10243 10244 SCIPfreeBufferArray(scip, &locvals); 10245 SCIPfreeBufferArray(scip, &locvars); 10246 10247 return SCIP_OKAY; 10248 } 10249 10250 10251 /** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */ 10252 static 10253 SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphSOS1) 10254 { /*lint --e{715}*/ 10255 SCIP_CONSDATA* consdata; 10256 SCIP_VAR** consvars; 10257 SCIP_VAR** locvars; 10258 SCIP_Real* locvals; 10259 SCIP_Real constant = 0.0; 10260 int consnodeidx; 10261 int nodeidx; 10262 int nconsvars; 10263 int nlocvars; 10264 int nvars; 10265 int i; 10266 10267 consdata = SCIPconsGetData(cons); 10268 assert(consdata != NULL); 10269 10270 /* get active variables of the constraint */ 10271 nvars = SCIPgetNVars(scip); 10272 nconsvars = consdata->nvars; 10273 consvars = SCIPgetVarsSOS1(scip, cons); 10274 assert(consvars != NULL); 10275 10276 SCIP_CALL( SCIPallocBufferArray(scip, &locvars, nvars) ); 10277 SCIP_CALL( SCIPallocBufferArray(scip, &locvals, nvars) ); 10278 10279 /* add node initializing constraint (with artificial rhs) */ 10280 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, 0.0, 0.0, &consnodeidx) ); 10281 10282 /* for all (aggregation of) variables, add a node to graph and connect it with the root */ 10283 for( i = 0; i < nconsvars; ++i ) 10284 { 10285 locvars[0] = consvars[i]; 10286 locvals[0] = 1.0; 10287 constant = 0.0; 10288 nlocvars = 1; 10289 10290 /* ignore weights of SOS1 constraint (variables are sorted according to these weights) */ 10291 10292 /* use SYM_SYMTYPE_PERM here to NOT center variable domains at 0, as the latter might not preserve 10293 * SOS1 constraints */ 10294 SCIP_CALL( SCIPgetActiveVariables(scip, SYM_SYMTYPE_PERM, &locvars, &locvals, 10295 &nlocvars, &constant, SCIPisTransformed(scip)) ); 10296 10297 if( nlocvars == 1 && SCIPisZero(scip, constant) && SCIPisEQ(scip, locvals[0], 1.0) ) 10298 { 10299 SCIP_Bool allownegation = FALSE; 10300 10301 /* a negation is allowed if it is centered around 0 */ 10302 if ( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(locvars[0])) == SCIPisInfinity(scip, SCIPvarGetUbGlobal(locvars[0])) 10303 && (SCIPisInfinity(scip, SCIPvarGetUbGlobal(locvars[0])) 10304 || SCIPisZero(scip, (SCIPvarGetLbGlobal(locvars[0]) + SCIPvarGetUbGlobal(locvars[0]))/2)) ) 10305 allownegation = TRUE; 10306 10307 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, locvars[0]); 10308 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, nodeidx, TRUE, 1.0) ); 10309 10310 nodeidx = SCIPgetSymgraphNegatedVarnodeidx(scip, graph, locvars[0]); 10311 if( allownegation ) 10312 { 10313 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, nodeidx, TRUE, 1.0) ); 10314 } 10315 else 10316 { 10317 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, nodeidx, TRUE, -1.0) ); 10318 } 10319 } 10320 else 10321 { 10322 int sumnodeidx; 10323 int j; 10324 10325 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &sumnodeidx) ); /*lint !e641*/ 10326 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, sumnodeidx, FALSE, 0.0) ); 10327 10328 /* add nodes and edges for variables in aggregation, do not add edges to negated variables 10329 * since this might not necessarily be a symmetry of the SOS1 constraint; therefore, 10330 * do not use SCIPaddSymgraphVarAggegration() */ 10331 for( j = 0; j < nlocvars; ++j ) 10332 { 10333 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, locvars[j]); 10334 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, locvals[j]) ); 10335 } 10336 10337 /* possibly add node for constant */ 10338 if( ! SCIPisZero(scip, constant) ) 10339 { 10340 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, constant, &nodeidx) ); 10341 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, FALSE, 0.0) ); 10342 } 10343 } 10344 } 10345 10346 SCIPfreeBufferArray(scip, &locvals); 10347 SCIPfreeBufferArray(scip, &locvars); 10348 10349 return SCIP_OKAY; 10350 } 10351 10352 10353 /* ---------------- Constraint specific interface methods ---------------- */ 10354 10355 /** creates the handler for SOS1 constraints and includes it in SCIP */ 10356 SCIP_RETCODE SCIPincludeConshdlrSOS1( 10357 SCIP* scip /**< SCIP data structure */ 10358 ) 10359 { 10360 SCIP_CONSHDLRDATA* conshdlrdata; 10361 SCIP_CONSHDLR* conshdlr; 10362 10363 /* create constraint handler data */ 10364 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) ); 10365 conshdlrdata->branchsos = TRUE; 10366 conshdlrdata->switchsos1branch = FALSE; 10367 conshdlrdata->switchcutsfromsos1 = FALSE; 10368 conshdlrdata->eventhdlr = NULL; 10369 conshdlrdata->fixnonzerovars = NULL; 10370 conshdlrdata->maxnfixnonzerovars = 0; 10371 conshdlrdata->nfixnonzerovars = 0; 10372 conshdlrdata->conflictgraph = NULL; 10373 conshdlrdata->localconflicts = NULL; 10374 conshdlrdata->isconflocal = FALSE; 10375 conshdlrdata->implgraph = NULL; 10376 conshdlrdata->nimplnodes = 0; 10377 conshdlrdata->nboundcuts = 0; 10378 conshdlrdata->tcliquegraph = NULL; 10379 conshdlrdata->tcliquedata = NULL; 10380 conshdlrdata->cntextsos1 = -1; 10381 conshdlrdata->varhash = NULL; 10382 10383 /* create event handler for bound change events */ 10384 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecSOS1, NULL) ); 10385 if ( conshdlrdata->eventhdlr == NULL ) 10386 { 10387 SCIPerrorMessage("event handler for SOS1 constraints not found.\n"); 10388 return SCIP_PLUGINNOTFOUND; 10389 } 10390 10391 /* include constraint handler */ 10392 SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC, 10393 CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS, 10394 consEnfolpSOS1, consEnfopsSOS1, consCheckSOS1, consLockSOS1, conshdlrdata) ); 10395 assert(conshdlr != NULL); 10396 10397 /* set non-fundamental callbacks via specific setter functions */ 10398 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySOS1, consCopySOS1) ); 10399 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSOS1) ); 10400 SCIP_CALL( SCIPsetConshdlrGetDiveBdChgs(scip, conshdlr, consGetDiveBdChgsSOS1) ); 10401 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolSOS1) ); 10402 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSOS1) ); 10403 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSOS1) ); 10404 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSOS1) ); 10405 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSOS1) ); 10406 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSOS1) ); 10407 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSOS1) ); 10408 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSOS1, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) ); 10409 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSOS1) ); 10410 SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropSOS1, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP, CONSHDLR_PROP_TIMING) ); 10411 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSOS1) ); 10412 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSOS1, consSepasolSOS1, CONSHDLR_SEPAFREQ, CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) ); 10413 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSOS1) ); 10414 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSOS1) ); 10415 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphSOS1) ); 10416 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphSOS1) ); 10417 10418 /* add SOS1 constraint handler parameters */ 10419 10420 /* adjacency matrix parameters */ 10421 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxsosadjacency", 10422 "do not create an adjacency matrix if number of SOS1 variables is larger than predefined value (-1: no limit)", 10423 &conshdlrdata->maxsosadjacency, TRUE, DEFAULT_MAXSOSADJACENCY, -1, INT_MAX, NULL, NULL) ); 10424 10425 /* presolving parameters */ 10426 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxextensions", 10427 "maximal number of extensions that will be computed for each SOS1 constraint (-1: no limit)", 10428 &conshdlrdata->maxextensions, TRUE, DEFAULT_MAXEXTENSIONS, -1, INT_MAX, NULL, NULL) ); 10429 10430 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxtightenbds", 10431 "maximal number of bound tightening rounds per presolving round (-1: no limit)", 10432 &conshdlrdata->maxtightenbds, TRUE, DEFAULT_MAXTIGHTENBDS, -1, INT_MAX, NULL, NULL) ); 10433 10434 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/perfimplanalysis", 10435 "if TRUE then perform implication graph analysis (might add additional SOS1 constraints)", 10436 &conshdlrdata->perfimplanalysis, TRUE, DEFAULT_PERFIMPLANALYSIS, NULL, NULL) ); 10437 10438 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/depthimplanalysis", 10439 "number of recursive calls of implication graph analysis (-1: no limit)", 10440 &conshdlrdata->depthimplanalysis, TRUE, DEFAULT_DEPTHIMPLANALYSIS, -1, INT_MAX, NULL, NULL) ); 10441 10442 /* propagation parameters */ 10443 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/conflictprop", 10444 "whether to use conflict graph propagation", 10445 &conshdlrdata->conflictprop, TRUE, DEFAULT_CONFLICTPROP, NULL, NULL) ); 10446 10447 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/implprop", 10448 "whether to use implication graph propagation", 10449 &conshdlrdata->implprop, TRUE, DEFAULT_IMPLPROP, NULL, NULL) ); 10450 10451 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/sosconsprop", 10452 "whether to use SOS1 constraint propagation", 10453 &conshdlrdata->sosconsprop, TRUE, DEFAULT_SOSCONSPROP, NULL, NULL) ); 10454 10455 /* branching parameters */ 10456 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchingrule", 10457 "which branching rule should be applied ? ('n': neighborhood, 'b': bipartite, 's': SOS1/clique) (note: in some cases an automatic switching to SOS1 branching is possible)", 10458 &conshdlrdata->branchingrule, TRUE, DEFAULT_BRANCHINGRULE, DEFAULT_BRANCHSTRATEGIES, NULL, NULL) ); 10459 10460 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/autosos1branch", 10461 "if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap", 10462 &conshdlrdata->autosos1branch, TRUE, DEFAULT_AUTOSOS1BRANCH, NULL, NULL) ); 10463 10464 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/fixnonzero", 10465 "if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the feasibility tolerance", 10466 &conshdlrdata->fixnonzero, TRUE, DEFAULT_FIXNONZERO, NULL, NULL) ); 10467 10468 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/addcomps", 10469 "if TRUE then add complementarity constraints to the branching nodes (can be used in combination with neighborhood or bipartite branching)", 10470 &conshdlrdata->addcomps, TRUE, DEFAULT_ADDCOMPS, NULL, NULL) ); 10471 10472 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxaddcomps", 10473 "maximal number of complementarity constraints added per branching node (-1: no limit)", 10474 &conshdlrdata->maxaddcomps, TRUE, DEFAULT_MAXADDCOMPS, -1, INT_MAX, NULL, NULL) ); 10475 10476 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/addcompsfeas", 10477 "minimal feasibility value for complementarity constraints in order to be added to the branching node", 10478 &conshdlrdata->addcompsfeas, TRUE, DEFAULT_ADDCOMPSFEAS, -SCIP_REAL_MAX, SCIP_REAL_MAX, NULL, NULL) ); 10479 10480 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/addbdsfeas", 10481 "minimal feasibility value for bound inequalities in order to be added to the branching node", 10482 &conshdlrdata->addbdsfeas, TRUE, DEFAULT_ADDBDSFEAS, -SCIP_REAL_MAX, SCIP_REAL_MAX, NULL, NULL) ); 10483 10484 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/addextendedbds", 10485 "should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities", 10486 &conshdlrdata->addextendedbds, TRUE, DEFAULT_ADDEXTENDEDBDS, NULL, NULL) ); 10487 10488 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchsos", 10489 "Use SOS1 branching in enforcing (otherwise leave decision to branching rules)? This value can only be set to false if all SOS1 variables are binary", 10490 &conshdlrdata->branchsos, FALSE, TRUE, NULL, NULL) ); 10491 10492 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchnonzeros", 10493 "Branch on SOS constraint with most number of nonzeros?", 10494 &conshdlrdata->branchnonzeros, FALSE, FALSE, NULL, NULL) ); 10495 10496 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchweight", 10497 "Branch on SOS cons. with highest nonzero-variable weight for branching (needs branchnonzeros = false)?", 10498 &conshdlrdata->branchweight, FALSE, FALSE, NULL, NULL) ); 10499 10500 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/addcompsdepth", 10501 "only add complementarity constraints to branching nodes for predefined depth (-1: no limit)", 10502 &conshdlrdata->addcompsdepth, TRUE, DEFAULT_ADDCOMPSDEPTH, -1, INT_MAX, NULL, NULL) ); 10503 10504 /* selection rule parameters */ 10505 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/nstrongrounds", 10506 "maximal number of strong branching rounds to perform for each node (-1: auto); only available for neighborhood and bipartite branching", 10507 &conshdlrdata->nstrongrounds, TRUE, DEFAULT_NSTRONGROUNDS, -1, INT_MAX, NULL, NULL) ); 10508 10509 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/nstrongiter", 10510 "maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit)", 10511 &conshdlrdata->nstrongiter, TRUE, DEFAULT_NSTRONGITER, -2, INT_MAX, NULL, NULL) ); 10512 10513 /* separation parameters */ 10514 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfromsos1", 10515 "if TRUE separate bound inequalities from initial SOS1 constraints", 10516 &conshdlrdata->boundcutsfromsos1, TRUE, DEFAULT_BOUNDCUTSFROMSOS1, NULL, NULL) ); 10517 10518 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfromgraph", 10519 "if TRUE separate bound inequalities from the conflict graph", 10520 &conshdlrdata->boundcutsfromgraph, TRUE, DEFAULT_BOUNDCUTSFROMGRAPH, NULL, NULL) ); 10521 10522 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/autocutsfromsos1", 10523 "if TRUE then automatically switch to separating initial SOS1 constraints if the SOS1 constraints do not overlap", 10524 &conshdlrdata->autocutsfromsos1, TRUE, DEFAULT_AUTOCUTSFROMSOS1, NULL, NULL) ); 10525 10526 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfreq", 10527 "frequency for separating bound cuts; zero means to separate only in the root node", 10528 &conshdlrdata->boundcutsfreq, TRUE, DEFAULT_BOUNDCUTSFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) ); 10529 10530 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsdepth", 10531 "node depth of separating bound cuts (-1: no limit)", 10532 &conshdlrdata->boundcutsdepth, TRUE, DEFAULT_BOUNDCUTSDEPTH, -1, INT_MAX, NULL, NULL) ); 10533 10534 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxboundcuts", 10535 "maximal number of bound cuts separated per branching node", 10536 &conshdlrdata->maxboundcuts, TRUE, DEFAULT_MAXBOUNDCUTS, 0, INT_MAX, NULL, NULL) ); 10537 10538 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxboundcutsroot", 10539 "maximal number of bound cuts separated per iteration in the root node", 10540 &conshdlrdata->maxboundcutsroot, TRUE, DEFAULT_MAXBOUNDCUTSROOT, 0, INT_MAX, NULL, NULL) ); 10541 10542 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strthenboundcuts", 10543 "if TRUE then bound cuts are strengthened in case bound variables are available", 10544 &conshdlrdata->strthenboundcuts, TRUE, DEFAULT_STRTHENBOUNDCUTS, NULL, NULL) ); 10545 10546 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/implcutsfreq", 10547 "frequency for separating implied bound cuts; zero means to separate only in the root node", 10548 &conshdlrdata->implcutsfreq, TRUE, DEFAULT_IMPLCUTSFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) ); 10549 10550 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/implcutsdepth", 10551 "node depth of separating implied bound cuts (-1: no limit)", 10552 &conshdlrdata->implcutsdepth, TRUE, DEFAULT_IMPLCUTSDEPTH, -1, INT_MAX, NULL, NULL) ); 10553 10554 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maximplcuts", 10555 "maximal number of implied bound cuts separated per branching node", 10556 &conshdlrdata->maximplcuts, TRUE, DEFAULT_MAXIMPLCUTS, 0, INT_MAX, NULL, NULL) ); 10557 10558 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maximplcutsroot", 10559 "maximal number of implied bound cuts separated per iteration in the root node", 10560 &conshdlrdata->maximplcutsroot, TRUE, DEFAULT_MAXIMPLCUTSROOT, 0, INT_MAX, NULL, NULL) ); 10561 10562 return SCIP_OKAY; 10563 } 10564 10565 10566 /** creates and captures a SOS1 constraint 10567 * 10568 * We set the constraint to not be modifable. If the weights are non NULL, the variables are ordered according to these 10569 * weights (in ascending order). 10570 * 10571 * @note The constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons(). 10572 */ 10573 SCIP_RETCODE SCIPcreateConsSOS1( 10574 SCIP* scip, /**< SCIP data structure */ 10575 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 10576 const char* name, /**< name of constraint */ 10577 int nvars, /**< number of variables in the constraint */ 10578 SCIP_VAR** vars, /**< array with variables of constraint entries */ 10579 SCIP_Real* weights, /**< weights determining the variable order, or NULL if natural order should be used */ 10580 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? 10581 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ 10582 SCIP_Bool separate, /**< should the constraint be separated during LP processing? 10583 * Usually set to TRUE. */ 10584 SCIP_Bool enforce, /**< should the constraint be enforced during node processing? 10585 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 10586 SCIP_Bool check, /**< should the constraint be checked for feasibility? 10587 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 10588 SCIP_Bool propagate, /**< should the constraint be propagated during node processing? 10589 * Usually set to TRUE. */ 10590 SCIP_Bool local, /**< is constraint only valid locally? 10591 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ 10592 SCIP_Bool dynamic, /**< is constraint subject to aging? 10593 * Usually set to FALSE. Set to TRUE for own cuts which 10594 * are separated as constraints. */ 10595 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup? 10596 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */ 10597 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even 10598 * if it may be moved to a more global node? 10599 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */ 10600 ) 10601 { 10602 SCIP_CONSHDLR* conshdlr; 10603 SCIP_CONSDATA* consdata; 10604 SCIP_Bool modifiable; 10605 SCIP_Bool transformed; 10606 int v; 10607 10608 modifiable = FALSE; 10609 10610 /* find the SOS1 constraint handler */ 10611 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME); 10612 if ( conshdlr == NULL ) 10613 { 10614 SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME); 10615 return SCIP_PLUGINNOTFOUND; 10616 } 10617 10618 /* are we in the transformed problem? */ 10619 transformed = SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED; 10620 10621 /* create constraint data */ 10622 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) ); 10623 consdata->vars = NULL; 10624 consdata->nvars = nvars; 10625 consdata->maxvars = nvars; 10626 consdata->rowub = NULL; 10627 consdata->rowlb = NULL; 10628 consdata->nfixednonzeros = transformed ? 0 : -1; 10629 consdata->weights = NULL; 10630 consdata->local = local; 10631 10632 if ( nvars > 0 ) 10633 { 10634 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->vars, vars, nvars) ); 10635 10636 /* check weights */ 10637 if ( weights != NULL ) 10638 { 10639 /* store weights */ 10640 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, weights, nvars) ); 10641 10642 /* sort variables - ascending order */ 10643 SCIPsortRealPtr(consdata->weights, (void**)consdata->vars, nvars); 10644 } 10645 } 10646 else 10647 { 10648 assert( weights == NULL ); 10649 } 10650 10651 /* branching on multiaggregated variables does not seem to work well, so avoid it */ 10652 for (v = 0; v < nvars; ++v) 10653 { 10654 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->vars[v]) ); 10655 } 10656 10657 /* create constraint */ 10658 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate, 10659 local, modifiable, dynamic, removable, stickingatnode) ); 10660 assert( transformed == SCIPconsIsTransformed(*cons) ); 10661 10662 /* replace original variables by transformed variables in transformed constraint, add locks, and catch events */ 10663 for (v = nvars - 1; v >= 0; --v) 10664 { 10665 SCIP_CONSHDLRDATA* conshdlrdata; 10666 10667 /* always use transformed variables in transformed constraints */ 10668 if ( transformed ) 10669 { 10670 SCIP_CALL( SCIPgetTransformedVar(scip, consdata->vars[v], &(consdata->vars[v])) ); 10671 } 10672 assert( consdata->vars[v] != NULL ); 10673 assert( transformed == SCIPvarIsTransformed(consdata->vars[v]) ); 10674 10675 /* get constraint handler data */ 10676 conshdlrdata = SCIPconshdlrGetData(conshdlr); 10677 assert( conshdlrdata != NULL ); 10678 10679 /* handle the new variable */ 10680 SCIP_CALL( handleNewVariableSOS1(scip, *cons, consdata, conshdlrdata, consdata->vars[v], transformed) ); 10681 } 10682 10683 return SCIP_OKAY; 10684 } 10685 10686 10687 /** creates and captures a SOS1 constraint with all constraint flags set to their default values. 10688 * 10689 * @warning Do NOT set the constraint to be modifiable manually, because this might lead 10690 * to wrong results as the variable array will not be resorted 10691 * 10692 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons() 10693 */ 10694 SCIP_RETCODE SCIPcreateConsBasicSOS1( 10695 SCIP* scip, /**< SCIP data structure */ 10696 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 10697 const char* name, /**< name of constraint */ 10698 int nvars, /**< number of variables in the constraint */ 10699 SCIP_VAR** vars, /**< array with variables of constraint entries */ 10700 SCIP_Real* weights /**< weights determining the variable order, or NULL if natural order should be used */ 10701 ) 10702 { 10703 SCIP_CALL( SCIPcreateConsSOS1( scip, cons, name, nvars, vars, weights, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) ); 10704 10705 return SCIP_OKAY; 10706 } 10707 10708 10709 /** adds variable to SOS1 constraint, the position is determined by the given weight */ 10710 SCIP_RETCODE SCIPaddVarSOS1( 10711 SCIP* scip, /**< SCIP data structure */ 10712 SCIP_CONS* cons, /**< constraint */ 10713 SCIP_VAR* var, /**< variable to add to the constraint */ 10714 SCIP_Real weight /**< weight determining position of variable */ 10715 ) 10716 { 10717 SCIP_CONSHDLRDATA* conshdlrdata; 10718 SCIP_CONSHDLR* conshdlr; 10719 10720 assert( scip != NULL ); 10721 assert( var != NULL ); 10722 assert( cons != NULL ); 10723 10724 SCIPdebugMsg(scip, "adding variable <%s> to constraint <%s> with weight %g\n", SCIPvarGetName(var), SCIPconsGetName(cons), weight); 10725 10726 conshdlr = SCIPconsGetHdlr(cons); 10727 assert( conshdlr != NULL ); 10728 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 ) 10729 { 10730 SCIPerrorMessage("constraint is not an SOS1 constraint.\n"); 10731 return SCIP_INVALIDDATA; 10732 } 10733 10734 conshdlrdata = SCIPconshdlrGetData(conshdlr); 10735 assert( conshdlrdata != NULL ); 10736 10737 SCIP_CALL( addVarSOS1(scip, cons, conshdlrdata, var, weight) ); 10738 10739 return SCIP_OKAY; 10740 } 10741 10742 10743 /** appends variable to SOS1 constraint */ 10744 SCIP_RETCODE SCIPappendVarSOS1( 10745 SCIP* scip, /**< SCIP data structure */ 10746 SCIP_CONS* cons, /**< constraint */ 10747 SCIP_VAR* var /**< variable to add to the constraint */ 10748 ) 10749 { 10750 SCIP_CONSHDLRDATA* conshdlrdata; 10751 SCIP_CONSHDLR* conshdlr; 10752 10753 assert( scip != NULL ); 10754 assert( var != NULL ); 10755 assert( cons != NULL ); 10756 10757 SCIPdebugMsg(scip, "appending variable <%s> to constraint <%s>\n", SCIPvarGetName(var), SCIPconsGetName(cons)); 10758 10759 conshdlr = SCIPconsGetHdlr(cons); 10760 assert( conshdlr != NULL ); 10761 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 ) 10762 { 10763 SCIPerrorMessage("constraint is not an SOS1 constraint.\n"); 10764 return SCIP_INVALIDDATA; 10765 } 10766 10767 conshdlrdata = SCIPconshdlrGetData(conshdlr); 10768 assert( conshdlrdata != NULL ); 10769 10770 SCIP_CALL( appendVarSOS1(scip, cons, conshdlrdata, var) ); 10771 10772 return SCIP_OKAY; 10773 } 10774 10775 10776 /** gets number of variables in SOS1 constraint */ 10777 int SCIPgetNVarsSOS1( 10778 SCIP* scip, /**< SCIP data structure */ 10779 SCIP_CONS* cons /**< constraint */ 10780 ) 10781 { 10782 SCIP_CONSDATA* consdata; 10783 10784 assert( scip != NULL ); 10785 assert( cons != NULL ); 10786 10787 if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 10788 { 10789 SCIPerrorMessage("constraint is not an SOS1 constraint.\n"); 10790 SCIPABORT(); 10791 return -1; /*lint !e527*/ 10792 } 10793 10794 consdata = SCIPconsGetData(cons); 10795 assert( consdata != NULL ); 10796 10797 return consdata->nvars; 10798 } 10799 10800 10801 /** gets array of variables in SOS1 constraint */ 10802 SCIP_VAR** SCIPgetVarsSOS1( 10803 SCIP* scip, /**< SCIP data structure */ 10804 SCIP_CONS* cons /**< constraint data */ 10805 ) 10806 { 10807 SCIP_CONSDATA* consdata; 10808 10809 assert( scip != NULL ); 10810 assert( cons != NULL ); 10811 10812 if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 10813 { 10814 SCIPerrorMessage("constraint is not an SOS1 constraint.\n"); 10815 SCIPABORT(); 10816 return NULL; /*lint !e527*/ 10817 } 10818 10819 consdata = SCIPconsGetData(cons); 10820 assert( consdata != NULL ); 10821 10822 return consdata->vars; 10823 } 10824 10825 10826 /** gets array of weights in SOS1 constraint (or NULL if not existent) */ 10827 SCIP_Real* SCIPgetWeightsSOS1( 10828 SCIP* scip, /**< SCIP data structure */ 10829 SCIP_CONS* cons /**< constraint data */ 10830 ) 10831 { 10832 SCIP_CONSDATA* consdata; 10833 10834 assert( scip != NULL ); 10835 assert( cons != NULL ); 10836 10837 if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 10838 { 10839 SCIPerrorMessage("constraint is not an SOS1 constraint.\n"); 10840 SCIPABORT(); 10841 return NULL; /*lint !e527*/ 10842 } 10843 10844 consdata = SCIPconsGetData(cons); 10845 assert( consdata != NULL ); 10846 10847 return consdata->weights; 10848 } 10849 10850 10851 /** gets conflict graph of SOS1 constraints (or NULL if not existent) 10852 * 10853 * @note The conflict graph is globally valid; local changes are not taken into account. 10854 */ 10855 SCIP_DIGRAPH* SCIPgetConflictgraphSOS1( 10856 SCIP_CONSHDLR* conshdlr /**< SOS1 constraint handler */ 10857 ) 10858 { 10859 SCIP_CONSHDLRDATA* conshdlrdata; 10860 10861 assert( conshdlr != NULL ); 10862 10863 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 ) 10864 { 10865 SCIPerrorMessage("not an SOS1 constraint handler.\n"); 10866 SCIPABORT(); 10867 return NULL; /*lint !e527*/ 10868 } 10869 conshdlrdata = SCIPconshdlrGetData(conshdlr); 10870 assert( conshdlrdata != NULL ); 10871 10872 return conshdlrdata->conflictgraph; 10873 } 10874 10875 10876 /** gets number of problem variables that are part of the SOS1 conflict graph */ 10877 int SCIPgetNSOS1Vars( 10878 SCIP_CONSHDLR* conshdlr /**< SOS1 constraint handler */ 10879 ) 10880 { 10881 SCIP_CONSHDLRDATA* conshdlrdata; 10882 10883 assert( conshdlr != NULL ); 10884 10885 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 ) 10886 { 10887 SCIPerrorMessage("not an SOS1 constraint handler.\n"); 10888 SCIPABORT(); 10889 return -1; /*lint !e527*/ 10890 } 10891 conshdlrdata = SCIPconshdlrGetData(conshdlr); 10892 assert( conshdlrdata != NULL ); 10893 10894 return conshdlrdata->nsos1vars; 10895 } 10896 10897 10898 /** returns whether variable is part of the SOS1 conflict graph */ 10899 SCIP_Bool SCIPvarIsSOS1( 10900 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */ 10901 SCIP_VAR* var /**< variable */ 10902 ) 10903 { 10904 SCIP_CONSHDLRDATA* conshdlrdata; 10905 10906 assert( var != NULL ); 10907 assert( conshdlr != NULL ); 10908 10909 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 ) 10910 { 10911 SCIPerrorMessage("not an SOS1 constraint handler.\n"); 10912 SCIPABORT(); 10913 return FALSE; /*lint !e527*/ 10914 } 10915 conshdlrdata = SCIPconshdlrGetData(conshdlr); 10916 assert( conshdlrdata != NULL ); 10917 10918 return varIsSOS1(conshdlrdata, var); 10919 } 10920 10921 10922 /** returns SOS1 index of variable or -1 if variable is not part of the SOS1 conflict graph */ 10923 int SCIPvarGetNodeSOS1( 10924 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */ 10925 SCIP_VAR* var /**< variable */ 10926 ) 10927 { 10928 SCIP_CONSHDLRDATA* conshdlrdata; 10929 10930 assert( conshdlr != NULL ); 10931 assert( var != NULL ); 10932 10933 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 ) 10934 { 10935 SCIPerrorMessage("Not an SOS1 constraint handler.\n"); 10936 SCIPABORT(); 10937 return -1; /*lint !e527*/ 10938 } 10939 conshdlrdata = SCIPconshdlrGetData(conshdlr); 10940 assert( conshdlrdata != NULL ); 10941 10942 if ( conshdlrdata->varhash == NULL ) 10943 { 10944 SCIPerrorMessage("Hashmap not yet initialized.\n"); 10945 SCIPABORT(); 10946 return -1; /*lint !e527*/ 10947 } 10948 10949 return varGetNodeSOS1(conshdlrdata, var); 10950 } 10951 10952 10953 /** returns variable that belongs to a given node from the conflict graph */ 10954 SCIP_VAR* SCIPnodeGetVarSOS1( 10955 SCIP_DIGRAPH* conflictgraph, /**< conflict graph */ 10956 int node /**< node from the conflict graph */ 10957 ) 10958 { 10959 SCIP_NODEDATA* nodedata; 10960 10961 assert( conflictgraph != NULL ); 10962 assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) ); 10963 10964 /* get node data */ 10965 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node); 10966 10967 if ( nodedata == NULL ) 10968 { 10969 SCIPerrorMessage("variable is not assigned to an index.\n"); 10970 SCIPABORT(); 10971 return NULL; /*lint !e527*/ 10972 } 10973 10974 return nodedata->var; 10975 } 10976 10977 10978 /** based on solution values of the variables, fixes variables to zero to turn all SOS1 constraints feasible */ 10979 SCIP_RETCODE SCIPmakeSOS1sFeasible( 10980 SCIP* scip, /**< SCIP pointer */ 10981 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */ 10982 SCIP_SOL* sol, /**< solution */ 10983 SCIP_Bool* changed, /**< pointer to store whether the solution has been changed */ 10984 SCIP_Bool* success /**< pointer to store whether SOS1 constraints have been turned feasible and 10985 * solution was good enough */ 10986 ) 10987 { 10988 SCIP_CONSHDLRDATA* conshdlrdata; 10989 SCIP_Real roundobjval; 10990 SCIP_Bool allroundable; 10991 10992 assert( scip != NULL ); 10993 assert( conshdlr != NULL ); 10994 assert( sol != NULL ); 10995 assert( changed != NULL ); 10996 assert( success != NULL ); 10997 10998 if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 ) 10999 { 11000 SCIPerrorMessage("Not an SOS1 constraint handler.\n"); 11001 return SCIP_PARAMETERWRONGVAL; 11002 } 11003 conshdlrdata = SCIPconshdlrGetData(conshdlr); 11004 assert( conshdlrdata != NULL ); 11005 11006 *changed = FALSE; 11007 *success = FALSE; 11008 allroundable = FALSE; 11009 11010 /* check number of SOS1 constraints */ 11011 if ( SCIPconshdlrGetNConss(conshdlr) < 1 ) 11012 { 11013 *success = TRUE; 11014 return SCIP_OKAY; 11015 } 11016 11017 /* if the SOS1 constraints do not overlap, we apply a faster method makeSOS1constraintsFeasible() that does not make use of the conflict graph; 11018 * for overlapping SOS1 constraints we apply the method makeSOS1conflictgraphFeasible(), which then may produce better feasible solutions */ 11019 if ( conshdlrdata->switchsos1branch ) 11020 { 11021 SCIP_CALL( makeSOS1constraintsFeasible(scip, conshdlr, sol, changed, &allroundable) ); 11022 } 11023 else 11024 { 11025 SCIP_CALL( makeSOS1conflictgraphFeasible(scip, conshdlr, sol, changed, &allroundable) ); 11026 } 11027 11028 if ( ! allroundable ) /*lint !e774*/ 11029 return SCIP_OKAY; 11030 11031 /* check whether objective value of rounded solution is good enough */ 11032 roundobjval = SCIPgetSolOrigObj(scip, sol); 11033 if ( SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE ) 11034 roundobjval *= -1; 11035 11036 if ( SCIPisLT(scip, roundobjval, SCIPgetUpperbound(scip) ) ) 11037 *success = TRUE; 11038 11039 return SCIP_OKAY; 11040 } 11041