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_setppc.c 26 * @ingroup DEFPLUGINS_CONS 27 * @brief Constraint handler for the set partitioning / packing / covering constraints \f$1^T x\ \{=, \le, \ge\}\ 1\f$. 28 * @author Tobias Achterberg 29 * @author Michael Winkler 30 */ 31 32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 33 34 #include "blockmemshell/memory.h" 35 #include "scip/cons_nonlinear.h" 36 #include "scip/cons_linear.h" 37 #include "scip/cons_setppc.h" 38 #include "scip/pub_conflict.h" 39 #include "scip/pub_cons.h" 40 #include "scip/pub_event.h" 41 #include "scip/pub_lp.h" 42 #include "scip/pub_message.h" 43 #include "scip/pub_misc.h" 44 #include "scip/pub_misc_sort.h" 45 #include "scip/pub_var.h" 46 #include "scip/scip_conflict.h" 47 #include "scip/scip_cons.h" 48 #include "scip/scip_cut.h" 49 #include "scip/scip_event.h" 50 #include "scip/scip_general.h" 51 #include "scip/scip_lp.h" 52 #include "scip/scip_mem.h" 53 #include "scip/scip_message.h" 54 #include "scip/scip_nlp.h" 55 #include "scip/scip_numerics.h" 56 #include "scip/scip_param.h" 57 #include "scip/scip_prob.h" 58 #include "scip/scip_probing.h" 59 #include "scip/scip_randnumgen.h" 60 #include "scip/scip_sol.h" 61 #include "scip/scip_solvingstats.h" 62 #include "scip/scip_var.h" 63 #include "scip/symmetry_graph.h" 64 #include "symmetry/struct_symmetry.h" 65 #include <string.h> 66 67 68 #define CONSHDLR_NAME "setppc" 69 #define CONSHDLR_DESC "set partitioning / packing / covering constraints" 70 #define CONSHDLR_SEPAPRIORITY +700000 /**< priority of the constraint handler for separation */ 71 #define CONSHDLR_ENFOPRIORITY -700000 /**< priority of the constraint handler for constraint enforcing */ 72 #define CONSHDLR_CHECKPRIORITY -700000 /**< priority of the constraint handler for checking feasibility */ 73 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */ 74 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */ 75 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation, 76 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */ 77 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */ 78 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */ 79 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */ 80 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */ 81 82 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS 83 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP 84 85 #define LINCONSUPGD_PRIORITY +700000 /**< priority of the constraint handler for upgrading of linear constraints */ 86 #define NONLINCONSUPGD_PRIORITY +700000 /**< priority of the constraint handler for upgrading of nonlinear constraints */ 87 88 #define EVENTHDLR_NAME "setppc" 89 #define EVENTHDLR_DESC "bound change event handler for set partitioning / packing / covering constraints" 90 91 #define CONFLICTHDLR_NAME "setppc" 92 #define CONFLICTHDLR_DESC "conflict handler creating set covering constraints" 93 #define CONFLICTHDLR_PRIORITY LINCONSUPGD_PRIORITY 94 95 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */ 96 97 #define HASHSIZE_SETPPCCONS 500 /**< minimal size of hash table in setppc constraint tables */ 98 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */ 99 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */ 100 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise comparison round */ 101 102 #define DEFAULT_RANDSEED 3 103 104 /*#define VARUSES*/ /* activate variable usage counting, that is necessary for LP and pseudo branching */ 105 /*#define BRANCHLP*/ /* BRANCHLP is only useful if the ENFOPRIORITY is set to a positive value */ 106 #ifdef BRANCHLP 107 #define MINBRANCHWEIGHT 0.3 /**< minimum weight of both sets in binary set branching */ 108 #define MAXBRANCHWEIGHT 0.7 /**< maximum weight of both sets in binary set branching */ 109 #endif 110 #define DEFAULT_NPSEUDOBRANCHES 2 /**< number of children created in pseudo branching (0: disable branching) */ 111 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */ 112 113 #define DEFAULT_CLIQUELIFTING FALSE /**< should we try to lift variables into other clique constraints, fix 114 * variables, aggregate them, and also shrink the amount of variables in 115 * clique constraints 116 */ 117 #define DEFAULT_ADDVARIABLESASCLIQUES FALSE/**< should we try to generate extra clique constraint out of all binary 118 * variables to hopefully fasten the detection of redundant clique 119 * constraints */ 120 #define DEFAULT_CLIQUESHRINKING TRUE /**< should we try to shrink the number of variables in a clique constraints, by 121 * replacing more than one variable by only one 122 */ 123 124 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */ 125 126 /* 127 * Data structures 128 */ 129 130 /** constraint handler data */ 131 struct SCIP_ConshdlrData 132 { 133 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */ 134 SCIP_CONSHDLR* conshdlrlinear; /**< pointer to linear constraint handler or NULL if not included */ 135 #ifdef VARUSES 136 SCIP_INTARRAY* varuses; /**< number of times a var is used in the active setppc constraints */ 137 #endif 138 SCIP_Longint nsetpart; /**< number of set partitioning constraints in transformed problem */ 139 int npseudobranches; /**< number of children created in pseudo branching (0 to disable branching) */ 140 int noldfixedvars; /**< number of fixed variables after last clique lifting run */ 141 int noldimpls; /**< number of implication before last clique lifting run */ 142 int noldcliques; /**< number of cliques before last clique lifting run */ 143 int noldupgrs; /**< number of setppc constraints since the last clique lifting run */ 144 int nclqpresolve; /**< number of setppc clique lifting runs */ 145 SCIP_Bool updatedsetppctype; /**< remember whether we upgraded a constraint type */ 146 SCIP_Bool cliquelifting; /**< should we perform the clique lifting procedure */ 147 SCIP_Bool enablecliquelifting;/**< check whether we have enough changes to run the lifting procedure again */ 148 SCIP_Bool cliqueshrinking; /**< should we try to shrink the number of variables in a clique 149 * constraints, by replacing more than one variable by only one 150 */ 151 SCIP_Bool addvariablesascliques;/**< should we try to generate extra clique constraint out of all binary 152 * variables to hopefully fasten the detection of redundant clique 153 * constraints */ 154 SCIP_RANDNUMGEN* randnumgen; /**< random number generator */ 155 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */ 156 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */ 157 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */ 158 }; 159 160 /** constraint data for set partitioning / packing / covering constraints */ 161 struct SCIP_ConsData 162 { 163 uint64_t signature; /**< bit signature of vars array */ 164 SCIP_ROW* row; /**< LP row, if constraint is already stored in LP row format */ 165 SCIP_NLROW* nlrow; /**< NLP row, if constraint has been added to NLP relaxation */ 166 SCIP_VAR** vars; /**< variables of the constraint */ 167 int varssize; /**< size of vars array */ 168 int nvars; /**< number of variables in the constraint */ 169 int nfixedzeros; /**< current number of variables fixed to zero in the constraint */ 170 int nfixedones; /**< current number of variables fixed to one in the constraint */ 171 unsigned int setppctype:2; /**< type of constraint: set partitioning, packing or covering */ 172 unsigned int sorted:1; /**< are the constraint's variables sorted? */ 173 unsigned int cliqueadded:1; /**< was the set partitioning / packing constraint already added as clique? */ 174 unsigned int validsignature:1; /**< is the bit signature valid? */ 175 unsigned int changed:1; /**< was constraint changed since last redundancy round in preprocessing? */ 176 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */ 177 unsigned int merged:1; /**< are the constraint's equal/negated variables already merged? */ 178 unsigned int presolpropagated:1; /**< was the constraint already propagated in presolving w.r.t. the current domains? */ 179 unsigned int existmultaggr:1; /**< does this constraint contain aggregations */ 180 unsigned int catchevents:1; /**< are events installed for this constraint? */ 181 }; 182 183 184 185 186 /* 187 * Local methods 188 */ 189 190 /** compares two active constraints of type set partitioning or set packing such that a "-1" is return if 191 * 1. the first constraint is a set partitioning constraint and the second is a set packing or 192 * 2. both constraints are set partitioning constraints and the second has more! variables than the first or 193 * 3. both constraints are set packing constraints and the second has less! variables than the first 194 * a "0" is return if 195 * 1. both constraint are of the same type and have the amount of variables or 196 * and a "1" is returned otherwise 197 */ 198 static 199 int setppcCompare( 200 SCIP_CONS*const cons1, /**< first problem variable */ 201 SCIP_CONS*const cons2 /**< second problem variable */ 202 ) 203 { 204 SCIP_CONSDATA* consdata1; 205 SCIP_CONSDATA* consdata2; 206 207 assert(cons1 != NULL); 208 assert(cons2 != NULL); 209 assert(SCIPconsIsActive(cons1)); 210 assert(SCIPconsIsActive(cons2)); 211 212 /* the partitioning type should be the smallest value and the packing the second smallest */ 213 assert(SCIP_SETPPCTYPE_PARTITIONING < SCIP_SETPPCTYPE_PACKING); /*lint !e506*/ 214 215 consdata1 = SCIPconsGetData(cons1); 216 assert(consdata1 != NULL); 217 assert(consdata1->setppctype != SCIP_SETPPCTYPE_COVERING); /*lint !e641*/ 218 consdata2 = SCIPconsGetData(cons2); 219 assert(consdata2 != NULL); 220 assert(consdata2->setppctype != SCIP_SETPPCTYPE_COVERING); /*lint !e641*/ 221 222 if( consdata1->setppctype < consdata2->setppctype || 223 (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars < consdata2->nvars) || /*lint !e641*/ 224 (consdata2->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars > consdata2->nvars) ) /*lint !e641*/ 225 return -1; 226 else if( (consdata1->setppctype == consdata2->setppctype && consdata1->nvars == consdata2->nvars) ) /*lint !e641*/ 227 return 0; 228 else 229 { 230 assert(consdata1->setppctype > consdata2->setppctype || (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->setppctype == consdata2->setppctype && consdata1->nvars > consdata2->nvars) || (consdata1->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->setppctype == consdata2->setppctype && consdata1->nvars < consdata2->nvars)); /*lint !e641*/ 231 return +1; 232 } 233 } 234 235 /** sort constraints first after type (partitioning before packing before covering) and second after number of 236 * variables such that the partitioning constraints have increasing number of variables and the packing constraints 237 * have decreasing number of variables */ 238 static 239 SCIP_DECL_SORTPTRCOMP(setppcConssSort) 240 { 241 return setppcCompare((SCIP_CONS*)elem1, (SCIP_CONS*)elem2); 242 } 243 244 /** compares two setppc constraints such that a "-1" is return if the first constraint is active and 245 * 1. the second constraint is deleted 246 * 2. the first constraint is a set partitioning constraint and the second is a set packing or 247 * 3. both constraints are set partitioning constraints and the second has more! variables than the first or 248 * 4. both constraints are set packing constraints and the second has less! variables than the first 249 * a "0" is return if 250 * 1. both constraint are set-covering constraints 251 * 2. both constraint are of the same type and have the amount of variables or 252 * and a "1" is returned otherwise 253 */ 254 static 255 int setppcCompare2( 256 SCIP_CONS*const cons1, /**< first problem variable */ 257 SCIP_CONS*const cons2 /**< second problem variable */ 258 ) 259 { 260 SCIP_CONSDATA* consdata1; 261 SCIP_CONSDATA* consdata2; 262 263 assert(cons1 != NULL); 264 assert(cons2 != NULL); 265 266 if( SCIPconsIsDeleted(cons1) ) 267 { 268 if( SCIPconsIsDeleted(cons2) ) 269 return 0; 270 else 271 return +1; 272 } 273 else if( SCIPconsIsDeleted(cons2) ) 274 return -1; 275 276 consdata1 = SCIPconsGetData(cons1); 277 assert(consdata1 != NULL); 278 consdata2 = SCIPconsGetData(cons2); 279 assert(consdata2 != NULL); 280 281 /* the partitioning type should be the smallest value and the packing the second smallest */ 282 assert(SCIP_SETPPCTYPE_PARTITIONING < SCIP_SETPPCTYPE_PACKING && SCIP_SETPPCTYPE_PACKING < SCIP_SETPPCTYPE_COVERING); /*lint !e506*//*lint !e1564*/ 283 284 if( consdata1->setppctype < consdata2->setppctype || 285 ((SCIP_SETPPCTYPE)consdata1->setppctype != SCIP_SETPPCTYPE_COVERING && 286 (((SCIP_SETPPCTYPE)consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars < consdata2->nvars) || 287 ((SCIP_SETPPCTYPE)consdata2->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars > consdata2->nvars))) ) 288 return -1; 289 else if( ((SCIP_SETPPCTYPE)consdata2->setppctype == SCIP_SETPPCTYPE_COVERING || (consdata1->setppctype == consdata2->setppctype && consdata1->nvars == consdata2->nvars)) ) 290 return 0; 291 else 292 { 293 assert(consdata1->setppctype > consdata2->setppctype || ((consdata1->setppctype == consdata2->setppctype) && 294 ((consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars > consdata2->nvars) 295 || (consdata1->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars < consdata2->nvars)))); /*lint !e641*/ 296 return +1; 297 } 298 } 299 300 /** sort constraints first after type (partitioning before packing before covering) and second after number of 301 * variables such that the partitioning constraints have increasing number of variables and the packing constraints 302 * have decreasing number of variables */ 303 static 304 SCIP_DECL_SORTPTRCOMP(setppcConssSort2) 305 { 306 return setppcCompare2((SCIP_CONS*)elem1, (SCIP_CONS*)elem2); 307 } 308 309 310 /** installs rounding locks for the given variable in the given setppc constraint */ 311 static 312 SCIP_RETCODE lockRounding( 313 SCIP* scip, /**< SCIP data structure */ 314 SCIP_CONS* cons, /**< setppc constraint */ 315 SCIP_VAR* var /**< variable of constraint entry */ 316 ) 317 { 318 SCIP_CONSDATA* consdata; 319 320 consdata = SCIPconsGetData(cons); 321 assert(consdata != NULL); 322 323 switch( consdata->setppctype ) 324 { 325 case SCIP_SETPPCTYPE_PARTITIONING: 326 SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) ); 327 break; 328 case SCIP_SETPPCTYPE_PACKING: 329 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) ); 330 break; 331 case SCIP_SETPPCTYPE_COVERING: 332 SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, FALSE) ); 333 break; 334 default: 335 SCIPerrorMessage("unknown setppc type\n"); 336 return SCIP_INVALIDDATA; 337 } 338 339 return SCIP_OKAY; 340 } 341 342 /** removes rounding locks for the given variable in the given setppc constraint */ 343 static 344 SCIP_RETCODE unlockRounding( 345 SCIP* scip, /**< SCIP data structure */ 346 SCIP_CONS* cons, /**< setppc constraint */ 347 SCIP_VAR* var /**< variable of constraint entry */ 348 ) 349 { 350 SCIP_CONSDATA* consdata; 351 352 consdata = SCIPconsGetData(cons); 353 assert(consdata != NULL); 354 355 switch( consdata->setppctype ) 356 { 357 case SCIP_SETPPCTYPE_PARTITIONING: 358 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) ); 359 break; 360 case SCIP_SETPPCTYPE_PACKING: 361 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) ); 362 break; 363 case SCIP_SETPPCTYPE_COVERING: 364 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) ); 365 break; 366 default: 367 SCIPerrorMessage("unknown setppc type\n"); 368 return SCIP_INVALIDDATA; 369 } 370 371 return SCIP_OKAY; 372 } 373 374 /** creates constraint handler data for set partitioning / packing / covering constraint handler */ 375 static 376 SCIP_RETCODE conshdlrdataCreate( 377 SCIP* scip, /**< SCIP data structure */ 378 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */ 379 SCIP_EVENTHDLR* eventhdlr /**< event handler */ 380 ) 381 { 382 assert(scip != NULL); 383 assert(conshdlrdata != NULL); 384 assert(eventhdlr != NULL); 385 386 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) ); 387 #ifdef VARUSES 388 SCIP_CALL( SCIPcreateIntarray(scip, &(*conshdlrdata)->varuses) ); 389 #endif 390 (*conshdlrdata)->npseudobranches = DEFAULT_NPSEUDOBRANCHES; 391 392 /* set event handler for bound change events */ 393 (*conshdlrdata)->eventhdlr = eventhdlr; 394 (*conshdlrdata)->nsetpart = 0; 395 396 /* create a random number generator */ 397 SCIP_CALL( SCIPcreateRandom(scip, &(*conshdlrdata)->randnumgen, 398 DEFAULT_RANDSEED, TRUE) ); 399 400 return SCIP_OKAY; 401 } 402 403 /** frees constraint handler data for set partitioning / packing / covering constraint handler */ 404 static 405 SCIP_RETCODE conshdlrdataFree( 406 SCIP* scip, /**< SCIP data structure */ 407 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */ 408 ) 409 { 410 assert(conshdlrdata != NULL); 411 assert(*conshdlrdata != NULL); 412 413 #ifdef VARUSES 414 SCIP_CALL( SCIPfreeIntarray(scip, &(*conshdlrdata)->varuses) ); 415 #endif 416 417 /* free random number generator */ 418 SCIPfreeRandom(scip, &(*conshdlrdata)->randnumgen); 419 420 SCIPfreeBlockMemory(scip, conshdlrdata); 421 422 return SCIP_OKAY; 423 } 424 425 #ifdef VARUSES 426 /** adds the given value to the usage counter of the given variable */ 427 static 428 SCIP_RETCODE conshdlrdataAddVaruses( 429 SCIP* scip, /**< SCIP data structure */ 430 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 431 SCIP_VAR* var, /**< variable to increase usage counter for */ 432 int addval /**< value to add to the usage counter */ 433 ) 434 { 435 SCIP_INTARRAY* varuses; 436 437 assert(conshdlrdata != NULL); 438 assert(var != NULL); 439 440 varuses = conshdlrdata->varuses; 441 assert(varuses != NULL); 442 443 /* if the variable is the negation of a problem variable, count the varuses in the problem variable */ 444 if( SCIPvarIsNegated(var) ) 445 { 446 SCIP_VAR* negvar; 447 int varindex; 448 449 /* move the varuses value of the negated variable to the active problem variable */ 450 varindex = SCIPvarGetIndex(var); 451 addval += SCIPgetIntarrayVal(scip, varuses, varindex); 452 SCIP_CALL( SCIPsetIntarrayVal(scip, varuses, varindex, 0) ); 453 SCIP_CALL( SCIPgetNegatedVar(scip, var, &negvar) ); 454 var = negvar; 455 } 456 457 /* increase varuses counter */ 458 SCIP_CALL( SCIPincIntarrayVal(scip, varuses, SCIPvarGetIndex(var), addval) ); 459 460 SCIPdebugMsg(scip, "added %d to varuses of <%s>: %d\n", 461 addval, SCIPvarGetName(var), SCIPgetIntarrayVal(scip, varuses, SCIPvarGetIndex(var))); 462 463 return SCIP_OKAY; 464 } 465 466 /** increases the usage counter of the given variable */ 467 static 468 SCIP_RETCODE conshdlrdataIncVaruses( 469 SCIP* scip, /**< SCIP data structure */ 470 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 471 SCIP_VAR* var /**< variable to increase usage counter for */ 472 ) 473 { 474 assert(conshdlrdata != NULL); 475 476 SCIPdebugMsg(scip, "increasing varuses of <%s>: %d\n", 477 SCIPvarGetName(var), SCIPgetIntarrayVal(scip, conshdlrdata->varuses, SCIPvarGetIndex(var))); 478 479 SCIP_CALL( conshdlrdataAddVaruses(scip, conshdlrdata, var, +1) ); 480 481 return SCIP_OKAY; 482 } 483 484 /** decreases the usage counter of the given variable */ 485 static 486 SCIP_RETCODE conshdlrdataDecVaruses( 487 SCIP* scip, /**< SCIP data structure */ 488 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 489 SCIP_VAR* var /**< variable to increase usage counter for */ 490 ) 491 { 492 assert(conshdlrdata != NULL); 493 494 SCIPdebugMsg(scip, "decreasing varuses of <%s>: %d\n", 495 SCIPvarGetName(var), SCIPgetIntarrayVal(scip, conshdlrdata->varuses, SCIPvarGetIndex(var))); 496 497 SCIP_CALL( conshdlrdataAddVaruses(scip, conshdlrdata, var, -1) ); 498 499 return SCIP_OKAY; 500 } 501 502 /** increases the usage counter of all variable in the constraint */ 503 static 504 SCIP_RETCODE consdataIncVaruses( 505 SCIP* scip, /**< SCIP data structure */ 506 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 507 SCIP_CONSDATA* consdata /**< setppc constraint data */ 508 ) 509 { 510 int v; 511 512 assert(consdata != NULL); 513 514 for( v = 0; v < consdata->nvars; ++v ) 515 { 516 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, consdata->vars[v]) ); 517 } 518 519 return SCIP_OKAY; 520 } 521 522 /** decreases the usage counter of all variable in the constraint */ 523 static 524 SCIP_RETCODE consdataDecVaruses( 525 SCIP* scip, /**< SCIP data structure */ 526 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 527 SCIP_CONSDATA* consdata /**< setppc constraint data */ 528 ) 529 { 530 int v; 531 532 assert(consdata != NULL); 533 534 for( v = 0; v < consdata->nvars; ++v ) 535 { 536 SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, consdata->vars[v]) ); 537 } 538 539 return SCIP_OKAY; 540 } 541 #endif 542 543 /** ensures, that the vars array can store at least num entries */ 544 static 545 SCIP_RETCODE consdataEnsureVarsSize( 546 SCIP* scip, /**< SCIP data structure */ 547 SCIP_CONSDATA* consdata, /**< setppc constraint data */ 548 int num /**< minimum number of entries to store */ 549 ) 550 { 551 assert(consdata != NULL); 552 assert(consdata->nvars <= consdata->varssize); 553 554 if( num > consdata->varssize ) 555 { 556 int newsize; 557 558 newsize = SCIPcalcMemGrowSize(scip, num); 559 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) ); 560 consdata->varssize = newsize; 561 } 562 assert(num <= consdata->varssize); 563 564 return SCIP_OKAY; 565 } 566 567 /** creates a set partitioning / packing / covering constraint data object */ 568 static 569 SCIP_RETCODE consdataCreate( 570 SCIP* scip, /**< SCIP data structure */ 571 SCIP_CONSDATA** consdata, /**< pointer to store the set partitioning / packing / covering constraint */ 572 int nvars, /**< number of variables in the constraint */ 573 SCIP_VAR** vars, /**< variables of the constraint */ 574 SCIP_SETPPCTYPE setppctype /**< type of constraint: set partitioning, packing, or covering constraint */ 575 ) 576 { 577 assert(consdata != NULL); 578 assert(nvars == 0 || vars != NULL); 579 580 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) ); 581 582 (*consdata)->signature = 0; 583 (*consdata)->row = NULL; 584 (*consdata)->nlrow = NULL; 585 (*consdata)->existmultaggr = FALSE; 586 (*consdata)->catchevents = FALSE; 587 (*consdata)->nfixedzeros = 0; 588 (*consdata)->nfixedones = 0; 589 590 if( nvars > 0 ) 591 { 592 int v; 593 594 /* @todo the setppc constraint handler does not remove fixed variables from its var array; removing those 595 * variables is only possible if we consider the values of nfixedones and nfixedzeros in all propagation methods 596 */ 597 #ifdef SCIP_DISABLED_CODE 598 599 if( SCIPisConsCompressionEnabled(scip) ) 600 { 601 SCIP_VAR** varsbuffer; 602 int k; 603 604 /* allocate temporary buffer storage for active variables */ 605 SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) ); 606 607 k = 0; 608 /* collect fixed variables to compress the required memory */ 609 for( v = 0; v < nvars; ++v ) 610 { 611 assert(SCIPvarIsBinary(vars[v])); 612 613 /* already fixed variables account as fixed ones or zero, only unfixed are appended */ 614 if( SCIPvarGetLbGlobal(vars[v]) > 0.5 ) 615 (*consdata)->nfixedones++; 616 else if( SCIPvarGetUbGlobal(vars[v]) < 0.5 ) 617 (*consdata)->nfixedzeros++; 618 else 619 varsbuffer[k++] = vars[v]; 620 } 621 622 (*consdata)->varssize = k; 623 (*consdata)->nvars = k; 624 /* copy unfixed variables into constraint data */ 625 if( k > 0 ) 626 { 627 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) ); 628 } 629 630 /* free temporary storage */ 631 SCIPfreeBufferArray(scip, &varsbuffer); 632 } 633 else 634 #endif 635 { 636 /* for uncompressed copies, simply duplicate the whole array */ 637 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) ); 638 (*consdata)->varssize = nvars; 639 (*consdata)->nvars = nvars; 640 } 641 642 if( SCIPisTransformed(scip) ) 643 { 644 /* get transformed variables */ 645 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) ); 646 647 /* check for multi-aggregations and capture variables */ 648 for( v = 0; v < (*consdata)->nvars; v++ ) 649 { 650 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]); 651 assert(var != NULL); 652 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); 653 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) ); 654 } 655 } 656 else 657 { 658 /* capture variables */ 659 for( v = 0; v < (*consdata)->nvars; v++ ) 660 { 661 assert((*consdata)->vars[v] != NULL); 662 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) ); 663 } 664 } 665 } 666 else 667 { 668 (*consdata)->vars = NULL; 669 (*consdata)->varssize = 0; 670 (*consdata)->nvars = 0; 671 } 672 (*consdata)->setppctype = setppctype; /*lint !e641*/ 673 (*consdata)->sorted = (nvars <= 1); 674 (*consdata)->cliqueadded = FALSE; 675 (*consdata)->validsignature = FALSE; 676 (*consdata)->changed = TRUE; 677 (*consdata)->varsdeleted = FALSE; 678 (*consdata)->merged = FALSE; 679 (*consdata)->presolpropagated = FALSE; 680 681 return SCIP_OKAY; 682 } 683 684 /** creates a transformed set partitioning / packing / covering constraint data object */ 685 static 686 SCIP_RETCODE consdataCreateTransformed( 687 SCIP* scip, /**< SCIP data structure */ 688 SCIP_CONSDATA** consdata, /**< pointer to store the set partitioning / packing / covering constraint */ 689 int nvars, /**< number of variables in the constraint */ 690 SCIP_VAR** vars, /**< variables of the constraint */ 691 SCIP_SETPPCTYPE setppctype /**< type of constraint: set partitioning, packing, or covering constraint */ 692 ) 693 { 694 assert(consdata != NULL); 695 assert(nvars == 0 || vars != NULL); 696 697 /* create constraint data */ 698 SCIP_CALL( consdataCreate(scip, consdata, nvars, vars, setppctype) ); 699 700 /* transform the variables */ 701 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) ); 702 703 return SCIP_OKAY; 704 } 705 706 /** frees a set partitioning / packing / covering constraint data */ 707 static 708 SCIP_RETCODE consdataFree( 709 SCIP* scip, /**< SCIP data structure */ 710 SCIP_CONSDATA** consdata /**< pointer to store the set partitioning / packing / covering constraint */ 711 ) 712 { 713 int v; 714 715 assert(consdata != NULL); 716 assert(*consdata != NULL); 717 718 /* release the row */ 719 if( (*consdata)->row != NULL ) 720 { 721 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) ); 722 } 723 724 /* release the nlrow */ 725 if( (*consdata)->nlrow != NULL ) 726 { 727 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) ); 728 } 729 730 /* release variables */ 731 for( v = 0; v < (*consdata)->nvars; v++ ) 732 { 733 assert((*consdata)->vars[v] != NULL); 734 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) ); 735 } 736 737 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->vars, (*consdata)->varssize); 738 SCIPfreeBlockMemory(scip, consdata); 739 740 return SCIP_OKAY; 741 } 742 743 /** prints set partitioning / packing / covering constraint to file stream */ 744 static 745 SCIP_RETCODE consdataPrint( 746 SCIP* scip, /**< SCIP data structure */ 747 SCIP_CONSDATA* consdata, /**< set partitioning / packing / covering constraint data */ 748 FILE* file /**< output file (or NULL for standard output) */ 749 ) 750 { 751 assert(consdata != NULL); 752 753 /* print coefficients */ 754 if( consdata->nvars == 0 ) 755 SCIPinfoMessage(scip, file, "0 "); 756 757 /* write linear sum */ 758 SCIP_CALL( SCIPwriteVarsLinearsum(scip, file, consdata->vars, NULL, consdata->nvars, TRUE) ); 759 760 /* print right hand side */ 761 switch( consdata->setppctype ) 762 { 763 case SCIP_SETPPCTYPE_PARTITIONING: 764 SCIPinfoMessage(scip, file, " == 1"); 765 break; 766 case SCIP_SETPPCTYPE_PACKING: 767 SCIPinfoMessage(scip, file, " <= 1"); 768 break; 769 case SCIP_SETPPCTYPE_COVERING: 770 SCIPinfoMessage(scip, file, " >= 1"); 771 break; 772 default: 773 SCIPerrorMessage("unknown setppc type\n"); 774 return SCIP_ERROR; 775 } 776 777 return SCIP_OKAY; 778 } 779 780 /** returns the bit signature of the given constraint data */ 781 static 782 uint64_t consdataGetSignature( 783 SCIP_CONSDATA* consdata /**< set partitioning / packing / covering constraint data */ 784 ) 785 { 786 assert(consdata != NULL); 787 788 if( !consdata->validsignature ) 789 { 790 int i; 791 792 consdata->signature = 0; 793 for( i = 0; i < consdata->nvars; ++i ) 794 consdata->signature |= SCIPhashSignature64(SCIPvarGetIndex(consdata->vars[i])); 795 consdata->validsignature = TRUE; 796 } 797 798 return consdata->signature; 799 } 800 801 /** sorts setppc constraint's variables by non-decreasing variable index */ 802 static 803 void consdataSort( 804 SCIP_CONSDATA* consdata /**< linear constraint data */ 805 ) 806 { 807 assert(consdata != NULL); 808 809 if( !consdata->sorted ) 810 { 811 if( consdata->nvars <= 1 ) 812 consdata->sorted = TRUE; 813 else 814 { 815 SCIPsortPtr((void**)consdata->vars, SCIPvarComp, consdata->nvars); 816 consdata->sorted = TRUE; 817 } 818 } 819 assert(consdata->sorted); 820 #ifdef SCIP_DEBUG 821 /* check sorting */ 822 { 823 int v; 824 825 for( v = 0; v < consdata->nvars; ++v ) 826 { 827 assert(v == consdata->nvars-1 || SCIPvarCompare(consdata->vars[v], consdata->vars[v+1]) <= 0); 828 } 829 } 830 #endif 831 } 832 833 /** changes the type of a setppc constraint */ 834 static 835 SCIP_RETCODE setSetppcType( 836 SCIP* scip, /**< SCIP data structure */ 837 SCIP_CONS* cons, /**< setppc constraint */ 838 SCIP_SETPPCTYPE setppctype /**< new type of constraint */ 839 ) 840 { 841 SCIP_CONSHDLR* conshdlr; 842 SCIP_CONSHDLRDATA* conshdlrdata; 843 SCIP_CONSDATA* consdata; 844 SCIP_Bool locked; 845 int i; 846 847 consdata = SCIPconsGetData(cons); 848 assert(consdata != NULL); 849 850 if( (SCIP_SETPPCTYPE)consdata->setppctype == setppctype ) 851 return SCIP_OKAY; 852 853 SCIPdebugMsg(scip, " -> converting <%s> into setppc type %d\n", SCIPconsGetName(cons), setppctype); 854 855 /* remove rounding locks */ 856 locked = FALSE; 857 for( i = 0; i < NLOCKTYPES && !locked; i++ ) 858 locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) i); 859 860 if( locked ) 861 { 862 for( i = 0; i < consdata->nvars; ++i ) 863 { 864 SCIP_CALL( unlockRounding(scip, cons, consdata->vars[i]) ); 865 } 866 } 867 868 conshdlr = SCIPconsGetHdlr(cons); 869 assert(conshdlr != NULL); 870 conshdlrdata = SCIPconshdlrGetData(conshdlr); 871 assert(conshdlrdata != NULL); 872 873 if( SCIPisTransformed(scip) ) 874 { 875 if( setppctype == SCIP_SETPPCTYPE_PARTITIONING ) 876 { 877 ++(conshdlrdata->nsetpart); 878 assert(conshdlrdata->nsetpart >= 0); 879 } 880 else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) 881 { 882 --(conshdlrdata->nsetpart); 883 assert(conshdlrdata->nsetpart >= 0); 884 } 885 } 886 887 /* change the constraint type */ 888 consdata->setppctype = setppctype; /*lint !e641*/ 889 890 /* reinstall rounding locks again */ 891 if( locked ) 892 { 893 for( i = 0; i < consdata->nvars; ++i ) 894 { 895 SCIP_CALL( lockRounding(scip, cons, consdata->vars[i]) ); 896 } 897 } 898 899 /* remember that we changed a constraint type for clique lifting procedure */ 900 if( setppctype != SCIP_SETPPCTYPE_COVERING ) 901 conshdlrdata->updatedsetppctype = TRUE; 902 903 return SCIP_OKAY; 904 } 905 906 /** catches events for variable at given position */ 907 static 908 SCIP_RETCODE catchEvent( 909 SCIP* scip, /**< SCIP data structure */ 910 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */ 911 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */ 912 int pos /**< array position of variable to catch bound change events for */ 913 ) 914 { 915 SCIP_CONSDATA* consdata; 916 SCIP_EVENTTYPE eventtype; 917 SCIP_VAR* var; 918 919 consdata = SCIPconsGetData(cons); 920 assert(consdata != NULL); 921 assert(eventhdlr != NULL); 922 assert(0 <= pos && pos < consdata->nvars); 923 assert(consdata->vars != NULL); 924 925 var = consdata->vars[pos]; 926 assert(var != NULL); 927 928 /* we are catching the following events: 929 * 930 * - SCIP_EVENTTYPE_BOUNDCHANGED: Is used to count the number of variable fixed locally to zero and one. That helps 931 * to speed up the propagation 932 * 933 * - SCIP_EVENTTYPE_VARDELETED: Is caught to remove a deleted variable from the constraint 934 * 935 * - SCIP_EVENTTYPE_VARFIXED: Is used to get informed if a variable of the constraint was aggregated which means was 936 * detected to be equal or a negated variable of on other variable. in case of a negation 937 * this could lead to a redundant constraint if the (other) active variable is also part 938 * of the constraint. 939 */ 940 eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARDELETED | SCIP_EVENTTYPE_VARFIXED; 941 942 /* catch bound change events on variable */ 943 SCIP_CALL( SCIPcatchVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, NULL) ); 944 945 /* update the fixed variables counters for this variable */ 946 if( SCIPisEQ(scip, SCIPvarGetUbLocal(var), 0.0) ) 947 { 948 consdata->nfixedzeros++; 949 950 /* during presolving, we may fix the last unfixed variable or do an aggregation if there are two unfixed variables */ 951 if( SCIPconsIsActive(cons) && ((SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE) && (consdata->nfixedzeros >= consdata->nvars - 2)) ) 952 { 953 consdata->presolpropagated = FALSE; 954 955 /* during solving, we only propagate again if there is only one unfixed variable left */ 956 if( consdata->nfixedzeros >= consdata->nvars - 1 ) 957 { 958 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) ); 959 } 960 } 961 } 962 else if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), 1.0) ) 963 { 964 consdata->nfixedones++; 965 966 if( SCIPconsIsActive(cons) ) 967 { 968 consdata->presolpropagated = FALSE; 969 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) ); 970 } 971 } 972 973 return SCIP_OKAY; 974 } 975 976 /** drops events for variable at given position */ 977 static 978 SCIP_RETCODE dropEvent( 979 SCIP* scip, /**< SCIP data structure */ 980 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */ 981 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */ 982 int pos /**< array position of variable to catch bound change events for */ 983 ) 984 { 985 SCIP_CONSDATA* consdata; 986 SCIP_EVENTTYPE eventtype; 987 SCIP_VAR* var; 988 989 consdata = SCIPconsGetData(cons); 990 assert(consdata != NULL); 991 assert(eventhdlr != NULL); 992 assert(0 <= pos && pos < consdata->nvars); 993 assert(consdata->vars != NULL); 994 995 var = consdata->vars[pos]; 996 assert(var != NULL); 997 998 eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARDELETED | SCIP_EVENTTYPE_VARFIXED; 999 1000 /* drop events on variable */ 1001 SCIP_CALL( SCIPdropVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, -1) ); 1002 1003 /* update the fixed variables counters for this variable */ 1004 if( SCIPisEQ(scip, SCIPvarGetUbLocal(var), 0.0) ) 1005 consdata->nfixedzeros--; 1006 else if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), 1.0) ) 1007 consdata->nfixedones--; 1008 1009 return SCIP_OKAY; 1010 } 1011 1012 /** catches bound change events for all variables in transformed setppc constraint */ 1013 static 1014 SCIP_RETCODE catchAllEvents( 1015 SCIP* scip, /**< SCIP data structure */ 1016 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */ 1017 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */ 1018 ) 1019 { 1020 SCIP_CONSDATA* consdata; 1021 int i; 1022 1023 consdata = SCIPconsGetData(cons); 1024 assert(consdata != NULL); 1025 1026 if( consdata->catchevents == TRUE ) 1027 return SCIP_OKAY; 1028 1029 /* catch event for every single variable */ 1030 for( i = 0; i < consdata->nvars; ++i ) 1031 { 1032 SCIP_CALL( catchEvent(scip, cons, eventhdlr, i) ); 1033 } 1034 1035 consdata->catchevents = TRUE; 1036 1037 return SCIP_OKAY; 1038 } 1039 1040 /** drops bound change events for all variables in transformed setppc constraint */ 1041 static 1042 SCIP_RETCODE dropAllEvents( 1043 SCIP* scip, /**< SCIP data structure */ 1044 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */ 1045 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */ 1046 ) 1047 { 1048 SCIP_CONSDATA* consdata; 1049 int i; 1050 1051 consdata = SCIPconsGetData(cons); 1052 assert(consdata != NULL); 1053 1054 if( consdata->catchevents == FALSE ) 1055 return SCIP_OKAY; 1056 1057 /* drop event of every single variable */ 1058 for( i = 0; i < consdata->nvars; ++i ) 1059 { 1060 SCIP_CALL( dropEvent(scip, cons, eventhdlr, i) ); 1061 } 1062 1063 consdata->catchevents = FALSE; 1064 1065 return SCIP_OKAY; 1066 } 1067 1068 /** adds coefficient in setppc constraint */ 1069 static 1070 SCIP_RETCODE addCoef( 1071 SCIP* scip, /**< SCIP data structure */ 1072 SCIP_CONS* cons, /**< setppc constraint */ 1073 SCIP_VAR* var /**< variable to add to the constraint */ 1074 ) 1075 { 1076 SCIP_CONSDATA* consdata; 1077 SCIP_Bool transformed; 1078 1079 assert(var != NULL); 1080 1081 consdata = SCIPconsGetData(cons); 1082 assert(consdata != NULL); 1083 1084 /* are we in the transformed problem? */ 1085 transformed = SCIPconsIsTransformed(cons); 1086 1087 /* always use transformed variables in transformed constraints */ 1088 if( transformed ) 1089 { 1090 SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) ); 1091 } 1092 assert(var != NULL); 1093 assert(transformed == SCIPvarIsTransformed(var)); 1094 1095 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1) ); 1096 consdata->vars[consdata->nvars] = var; 1097 consdata->nvars++; 1098 if( consdata->validsignature ) 1099 consdata->signature |= SCIPhashSignature64(SCIPvarGetIndex(var)); 1100 consdata->sorted = (consdata->nvars == 1); 1101 consdata->changed = TRUE; 1102 1103 /* capture the variable */ 1104 SCIP_CALL( SCIPcaptureVar(scip, var) ); 1105 1106 /* if we are in transformed problem, catch the variable's events */ 1107 if( transformed ) 1108 { 1109 SCIP_CONSHDLR* conshdlr; 1110 SCIP_CONSHDLRDATA* conshdlrdata; 1111 1112 /* get event handler */ 1113 conshdlr = SCIPconsGetHdlr(cons); 1114 assert(conshdlr != NULL); 1115 conshdlrdata = SCIPconshdlrGetData(conshdlr); 1116 assert(conshdlrdata != NULL); 1117 assert(conshdlrdata->eventhdlr != NULL); 1118 1119 /* catch bound change events of variable */ 1120 if( consdata->catchevents ) 1121 { 1122 SCIP_CALL( catchEvent(scip, cons, conshdlrdata->eventhdlr, consdata->nvars-1) ); 1123 } 1124 1125 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR ) 1126 consdata->existmultaggr = TRUE; 1127 1128 #ifdef VARUSES 1129 /* if the constraint is currently active, increase the variable usage counter */ 1130 if( SCIPconsIsActive(cons) ) 1131 { 1132 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var) ); 1133 } 1134 #endif 1135 } 1136 1137 /* install the rounding locks for the new variable */ 1138 SCIP_CALL( lockRounding(scip, cons, var) ); 1139 1140 /* add the new coefficient to the LP row */ 1141 if( consdata->row != NULL ) 1142 { 1143 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, 1.0) ); 1144 } 1145 1146 consdata->merged = FALSE; 1147 consdata->cliqueadded = FALSE; 1148 1149 return SCIP_OKAY; 1150 } 1151 1152 /** deletes coefficient at given position from setppc constraint data */ 1153 static 1154 SCIP_RETCODE delCoefPos( 1155 SCIP* scip, /**< SCIP data structure */ 1156 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */ 1157 int pos /**< position of coefficient to delete */ 1158 ) 1159 { 1160 SCIP_CONSDATA* consdata; 1161 SCIP_VAR* var; 1162 1163 assert(scip != NULL); 1164 assert(cons != NULL); 1165 1166 consdata = SCIPconsGetData(cons); 1167 assert(consdata != NULL); 1168 assert(0 <= pos && pos < consdata->nvars); 1169 1170 var = consdata->vars[pos]; 1171 assert(var != NULL); 1172 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var)); 1173 1174 /* remove the rounding locks for the deleted variable */ 1175 SCIP_CALL( unlockRounding(scip, cons, var) ); 1176 1177 /* if we are in transformed problem, delete the event data of the variable */ 1178 if( SCIPconsIsTransformed(cons) ) 1179 { 1180 SCIP_CONSHDLR* conshdlr; 1181 SCIP_CONSHDLRDATA* conshdlrdata; 1182 1183 /* get event handler */ 1184 conshdlr = SCIPconsGetHdlr(cons); 1185 conshdlrdata = SCIPconshdlrGetData(conshdlr); 1186 assert(conshdlrdata != NULL); 1187 assert(conshdlrdata->eventhdlr != NULL); 1188 1189 /* drop bound change events of variable */ 1190 if( consdata->catchevents ) 1191 { 1192 SCIP_CALL( dropEvent(scip, cons, conshdlrdata->eventhdlr, pos) ); 1193 } 1194 1195 /* the last variable of the constraint was deleted; mark it for propagation (so that it can be deleted) */ 1196 if( consdata->nvars == 1 ) 1197 { 1198 consdata->presolpropagated = FALSE; 1199 } 1200 } 1201 1202 /* delete coefficient from the LP row */ 1203 if( consdata->row != NULL ) 1204 { 1205 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -1.0) ); 1206 } 1207 1208 /* move the last variable to the free slot */ 1209 if( pos != consdata->nvars - 1 ) 1210 { 1211 consdata->vars[pos] = consdata->vars[consdata->nvars-1]; 1212 consdata->sorted = FALSE; 1213 } 1214 consdata->nvars--; 1215 consdata->validsignature = FALSE; 1216 consdata->changed = TRUE; 1217 1218 /* release variable */ 1219 SCIP_CALL( SCIPreleaseVar(scip, &var) ); 1220 1221 return SCIP_OKAY; 1222 } 1223 1224 /** preform dual presolving 1225 * 1226 * In case a part (more than one variable) in the setppc constraint is independent of everything else (is locked only by 1227 * this constraint), we can perform dual reductions: 1228 * 1229 * (1) set covering 1230 * 1231 * - fix all independent variables with negative object coefficient to one 1232 * - fix all remaining independent variables to zero 1233 * 1234 * (i) all variables are independent and the constraint is not modifiable 1235 * 1236 * - fix the variable with the smallest object coefficient to one 1237 * 1238 * (ii) a variable x has exactly 0 uplocks and arbitrary downlocks and a variable y has exactly 1 downlock and 1239 * arbitrary uplocks and obj(x) <= obj(y) and obj(y) >= 0 1240 * 1241 * - fix y to 0, because it is dominated by x 1242 * 1243 * (2) set partitioning 1244 * 1245 * (i) all variables are independent and the constraint is not modifiable 1246 * 1247 * - fix the variable with the smallest object coefficient to one 1248 * - fix all remaining independent variables to zero 1249 * 1250 * (ii) a variable x has exactly 1 uplock and arbitrary downlocks and a variable y has exactly 1 downlock and 1251 * arbitrary uplocks and obj(x) <= obj(y) 1252 * 1253 * - fix y to 0, because it is dominated by x 1254 * 1255 * (3) set packing 1256 * 1257 * (i) all variables are independent and the constraint is not modifiable 1258 * 1259 * - fix the variable with the smallest object coefficient to one if the object coefficient is negative or zero 1260 * - fix all remaining independent variables to zero 1261 * 1262 * (ii) a variable x has exactly 1 uplock and arbitrary downlocks and a variable y has exactly 0 downlocks and 1263 * arbitrary uplocks and obj(x) <= obj(y) 1264 * 1265 * - fix y to 0, because it is dominated by x 1266 * 1267 * 1268 * Note: the following dual reduction for set covering and set packing constraints is already performed by the presolver 1269 * "dualfix" 1270 * (1) in case of a set covering constraint the following dual reduction can be performed: 1271 * - if a variable in a set covering constraint is only locked by that constraint and has negative or zero 1272 * objective coefficient than it can be fixed to one 1273 * (2) in case of a set packing constraint the following dual reduction can be performed: 1274 * - if a variable in a set packing constraint is only locked by that constraint and has positive or zero 1275 * objective coefficient than it can be fixed to zero 1276 * 1277 * Note: all dual reduction (ii) could also be performed by the "domcol" presolver, but because the pairwise comparison of 1278 * columns is only done heuristically (and here it should be even cheaper) we perform them here (too). 1279 * 1280 * Moreover, if there exists a variable that is only locked by a covering or packing constraint with two variables, one 1281 * can aggregate variables. 1282 */ 1283 static 1284 SCIP_RETCODE dualPresolving( 1285 SCIP* scip, /**< SCIP data structure */ 1286 SCIP_CONS* cons, /**< setppc constraint */ 1287 int* nfixedvars, /**< pointer to count number of fixings */ 1288 int* ndelconss, /**< pointer to count number of deleted constraints */ 1289 int* naggrvars, /**< pointer to count number of variables aggregated */ 1290 SCIP_RESULT* result /**< pointer to store the result SCIP_SUCCESS, if presolving was performed */ 1291 ) 1292 { 1293 SCIP_CONSDATA* consdata; 1294 SCIP_SETPPCTYPE setppctype; 1295 SCIP_VAR** vars; 1296 SCIP_VAR* activevar; 1297 SCIP_VAR* var; 1298 SCIP_Real bestobjval; 1299 SCIP_Real objval; 1300 SCIP_Real objsign; 1301 SCIP_Real fixval; 1302 SCIP_Bool infeasible; 1303 SCIP_Bool fixed; 1304 SCIP_Bool negated; 1305 int noldfixed; 1306 int nposfixings; 1307 int nlockdowns; 1308 int nlockups; 1309 int nvars; 1310 int indepidx = -1; 1311 int idx; 1312 int v; 1313 1314 assert(scip != NULL); 1315 assert(cons != NULL); 1316 assert(nfixedvars != NULL); 1317 assert(ndelconss != NULL); 1318 assert(result != NULL); 1319 1320 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot 1321 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are 1322 * added to the problems have the check flag set to FALSE 1323 */ 1324 if( !SCIPconsIsChecked(cons) ) 1325 return SCIP_OKAY; 1326 1327 assert(SCIPconsIsActive(cons)); 1328 1329 consdata = SCIPconsGetData(cons); 1330 assert(consdata != NULL); 1331 1332 /* modifiable non-covering constraints cannot be deleted if one variable is fixed to one, because the propagation for 1333 * newly inserted variables must be considered later 1334 */ 1335 if( consdata->nfixedones == 1 && SCIPconsIsModifiable(cons) ) 1336 return SCIP_OKAY; 1337 1338 /* all fixed variables should be removed at that point */ 1339 assert(consdata->nfixedones == 0); 1340 assert(consdata->nfixedzeros == 0); 1341 1342 nvars = consdata->nvars; 1343 1344 /* we don't want to consider small constraints (note that the constraints can be modifiable, so we can't delete this 1345 * constraint) 1346 */ 1347 if( nvars < 2 ) 1348 return SCIP_OKAY; 1349 1350 setppctype = (SCIP_SETPPCTYPE)consdata->setppctype; 1351 vars = consdata->vars; 1352 idx = -1; 1353 bestobjval = SCIP_INVALID; 1354 1355 /* collect the rounding locks depending on the setppc type */ 1356 switch( setppctype ) 1357 { 1358 case SCIP_SETPPCTYPE_PARTITIONING: 1359 nlockdowns = 1; 1360 nlockups = 1; 1361 objsign = 0.0; 1362 break; 1363 case SCIP_SETPPCTYPE_PACKING: 1364 nlockdowns = 0; 1365 nlockups = 1; 1366 objsign = -1.0; 1367 break; 1368 case SCIP_SETPPCTYPE_COVERING: 1369 nlockdowns = 1; 1370 nlockups = 0; 1371 objsign = 1.0; 1372 break; 1373 default: 1374 SCIPerrorMessage("unknown setppc type\n"); 1375 SCIPABORT(); 1376 return SCIP_INVALIDDATA; /*lint !e527*/ 1377 } 1378 1379 nposfixings = 0; 1380 1381 /* check if we can apply the dual reduction; therefore count the number of variables where the setppc has the only 1382 * locks on this constraint 1383 */ 1384 for( v = 0; v < nvars; ++v ) 1385 { 1386 var = vars[v]; 1387 assert(var != NULL); 1388 1389 /* the variable should not be (globally) fixed */ 1390 assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5); 1391 1392 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) >= nlockdowns 1393 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == nlockups ) 1394 { 1395 activevar = var; 1396 negated = FALSE; 1397 1398 /* get the active variable */ 1399 SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) ); 1400 assert(SCIPvarIsActive(activevar)); 1401 1402 if( negated ) 1403 objval = -SCIPvarGetObj(activevar); 1404 else 1405 objval = SCIPvarGetObj(activevar); 1406 1407 /* check if the current variable has a smaller objective coefficient */ 1408 if( idx == -1 || objval < bestobjval ) 1409 { 1410 idx = v; 1411 bestobjval = objval; 1412 } 1413 1414 /* determine independent variable, i.e., only locked by the current constraint */ 1415 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns ) 1416 { 1417 assert(SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == nlockups); 1418 1419 /* store variables that have the right objective sign */ 1420 if ( objval * objsign >= 0.0 ) 1421 indepidx = v; 1422 } 1423 } 1424 1425 /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these 1426 * variables 1427 */ 1428 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns 1429 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups ) 1430 ++nposfixings; 1431 } 1432 1433 if( idx == -1 || nposfixings == 0 ) 1434 return SCIP_OKAY; 1435 1436 SCIPdebugMsg(scip, "dual fixing constraint: \n"); 1437 SCIPdebug( SCIP_CALL( SCIPprintCons(scip, cons, NULL) ) ); 1438 SCIPdebug( SCIPinfoMessage(scip, NULL, "\n") ); 1439 1440 assert(idx >= 0 && idx < nvars); 1441 assert(bestobjval < SCIPinfinity(scip)); 1442 1443 noldfixed = *nfixedvars; 1444 1445 /* In the special case of two variables, where one variable is independent and will be minimized for covering or 1446 * maximized for packing or does not appear in the objective, we can aggregate variables: 1447 * - Covering: var1 + var2 >= 1 and the objective of var1 is non-negative. 1448 * - Packing: var1 + var2 <= 1 and the objective of var1 is non-positive. 1449 * In both cases, var1 + var2 = 1 holds in every optimal solution. 1450 */ 1451 if( setppctype != SCIP_SETPPCTYPE_PARTITIONING && nvars == 2 && indepidx >= 0 ) 1452 { 1453 SCIP_Bool redundant; 1454 SCIP_Bool aggregated; 1455 int idx2; 1456 1457 idx2 = 1 - indepidx; 1458 assert( 0 <= idx2 && idx2 < 2 ); 1459 1460 SCIP_CALL( SCIPaggregateVars(scip, vars[indepidx], vars[idx2], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) ); 1461 assert(!infeasible); 1462 assert(redundant); 1463 assert(aggregated); 1464 ++(*naggrvars); 1465 1466 /* remove constraint since it is redundant */ 1467 SCIP_CALL( SCIPdelCons(scip, cons) ); 1468 ++(*ndelconss); 1469 1470 *result = SCIP_SUCCESS; 1471 1472 return SCIP_OKAY; 1473 } 1474 1475 /* in case of set packing and set partitioning we fix the dominated variables to zero */ 1476 if( setppctype != SCIP_SETPPCTYPE_COVERING ) 1477 { 1478 /* first part of all variables */ 1479 for( v = nvars - 1; v >= 0; --v ) 1480 { 1481 if( v == idx ) 1482 continue; 1483 1484 var = vars[v]; 1485 assert(var != NULL); 1486 1487 /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these 1488 * variables 1489 */ 1490 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns 1491 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups ) 1492 { 1493 activevar = var; 1494 negated = FALSE; 1495 1496 /* get the active variable */ 1497 SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) ); 1498 assert(SCIPvarIsActive(activevar)); 1499 1500 if( negated ) 1501 objval = -SCIPvarGetObj(activevar); 1502 else 1503 objval = SCIPvarGetObj(activevar); 1504 1505 if( objval >= bestobjval ) 1506 { 1507 SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) ); 1508 assert(!infeasible); 1509 assert(fixed); 1510 1511 SCIPdebugMsg(scip, " -> dual-fixed dominated variable <%s> == 0.0\n", SCIPvarGetName(var)); 1512 ++(*nfixedvars); 1513 } 1514 } 1515 } 1516 } 1517 /* if we got a set covering constraint and not all variables are locked from this constraint it might not get 1518 * redundant (which is case if it is not possible to fix at least one variable to one), we fix all redundant 1519 * variables to their best bound 1520 */ 1521 else 1522 { 1523 /* first part of all variables */ 1524 for( v = nvars - 1; v >= 0; --v ) 1525 { 1526 if( v == idx ) 1527 continue; 1528 1529 var = vars[v]; 1530 assert(var != NULL); 1531 1532 /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these 1533 * variables 1534 */ 1535 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns 1536 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups ) 1537 { 1538 activevar = var; 1539 negated = FALSE; 1540 1541 /* get the active variable */ 1542 SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) ); 1543 assert(SCIPvarIsActive(activevar)); 1544 assert(negated 1545 || (SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksDownType(activevar, SCIP_LOCKTYPE_MODEL) 1546 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksUpType(activevar, SCIP_LOCKTYPE_MODEL))); 1547 assert(!negated 1548 || (SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksUpType(activevar, SCIP_LOCKTYPE_MODEL) 1549 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksDownType(activevar, SCIP_LOCKTYPE_MODEL))); 1550 1551 if( negated ) 1552 objval = -SCIPvarGetObj(activevar); 1553 else 1554 objval = SCIPvarGetObj(activevar); 1555 1556 if( objval > 0.0 ) 1557 fixval = 0.0; 1558 else 1559 fixval = 1.0; 1560 1561 /* if variables has a negative objective contribution, and is uplocked by another constraint we cannot fix 1562 * the variables to 1 1563 */ 1564 if( (fixval == 1.0 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > nlockups) || objval < bestobjval ) 1565 continue; 1566 1567 SCIP_CALL( SCIPfixVar(scip, var, fixval, &infeasible, &fixed) ); 1568 assert(!infeasible); 1569 assert(fixed); 1570 1571 SCIPdebugMsg(scip, " -> dual-fixed dominated variable <%s> == %g\n", SCIPvarGetName(var), fixval); 1572 ++(*nfixedvars); 1573 } 1574 } 1575 } 1576 1577 /* if all variables but the domination variable is fixed and the constraint is not modifiable or the constraint is a 1578 * covering constraint and the bestobjval is less than or equal to zero, we can fix the domination variable (with best 1579 * objective coefficient) and the constraint gets redundant 1580 */ 1581 if( ((*nfixedvars - noldfixed == nvars - 1) && !SCIPconsIsModifiable(cons)) || (setppctype == SCIP_SETPPCTYPE_COVERING && bestobjval <= 0.0) ) 1582 { 1583 /* in case of a set packing constraint with positive objective values, all variables can be fixed to zero; in all 1584 * other cases the variable with the smallest objective values is fixed to one 1585 */ 1586 if( (setppctype == SCIP_SETPPCTYPE_PACKING && bestobjval > 0.0 1587 && SCIPvarGetNLocksDownType(vars[idx], SCIP_LOCKTYPE_MODEL) == 0) 1588 || setppctype != SCIP_SETPPCTYPE_PACKING || bestobjval <= 0.0 ) 1589 { 1590 if( setppctype == SCIP_SETPPCTYPE_PACKING && bestobjval > 0.0 ) 1591 fixval = 0.0; 1592 else 1593 fixval = 1.0; 1594 1595 SCIP_CALL( SCIPfixVar(scip, vars[idx], fixval, &infeasible, &fixed) ); 1596 assert(!infeasible); 1597 assert(fixed); 1598 1599 SCIPdebugMsg(scip, " -> dual-fixed best variable <%s> == %g\n", SCIPvarGetName(vars[idx]), fixval); 1600 ++(*nfixedvars); 1601 } 1602 1603 /* check that we really have a non-violated constraint in hand before deleting */ 1604 assert((setppctype == SCIP_SETPPCTYPE_PACKING && consdata->nfixedones <= 1) || 1605 (setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedones == 1) || 1606 (setppctype == SCIP_SETPPCTYPE_COVERING && consdata->nfixedones >= 1)); 1607 1608 /* remove constraint since it is redundant */ 1609 SCIP_CALL( SCIPdelCons(scip, cons) ); 1610 ++(*ndelconss); 1611 } 1612 1613 assert(*nfixedvars >= noldfixed); 1614 1615 /* set result pointer to SCIP_SUCCESS, if variables could be fixed */ 1616 if( *nfixedvars != noldfixed ) 1617 *result = SCIP_SUCCESS; 1618 1619 return SCIP_OKAY; 1620 } 1621 1622 /** find pairs of negated variables in constraint: 1623 * partitioning/packing: all other variables must be zero, constraint is redundant 1624 * covering: constraint is redundant 1625 * 1626 * find sets of equal variables in constraint: 1627 * partitioning/packing: variable must be zero 1628 * covering: multiple entries of variable can be replaced by single entry 1629 */ 1630 static 1631 SCIP_RETCODE mergeMultiples( 1632 SCIP* scip, /**< SCIP data structure */ 1633 SCIP_CONS* cons, /**< knapsack constraint */ 1634 int* nfixedvars, /**< pointer to store number of fixed variables */ 1635 int* ndelconss, /**< pointer to store number of deleted constraints */ 1636 int* nchgcoefs, /**< pointer to store number of changed coefficients */ 1637 SCIP_Bool* cutoff /**< pointer to store whether a fixing leads to a cutoff */ 1638 ) 1639 { 1640 SCIP_CONSDATA* consdata; 1641 int v; 1642 1643 assert(scip != NULL); 1644 assert(cons != NULL); 1645 assert(nfixedvars != NULL); 1646 assert(ndelconss != NULL); 1647 assert(nchgcoefs != NULL); 1648 assert(cutoff != NULL); 1649 1650 consdata = SCIPconsGetData(cons); 1651 assert(consdata != NULL); 1652 1653 if( consdata->merged || SCIPconsIsDeleted(cons) ) 1654 return SCIP_OKAY; 1655 1656 if( consdata->nvars <= 1 ) 1657 { 1658 consdata->merged = TRUE; 1659 return SCIP_OKAY; 1660 } 1661 1662 assert(consdata->vars != NULL || consdata->nvars == 0); 1663 1664 /* sorting array after indices of variables, that's only for faster merging */ 1665 SCIPsortPtr((void**)consdata->vars, SCIPvarCompActiveAndNegated, consdata->nvars); 1666 /* setppc sorting now lost */ 1667 consdata->sorted = FALSE; 1668 1669 /* loop backwards through the items: deletion only affects rear items */ 1670 for( v = consdata->nvars - 1; v > 0; --v ) 1671 { 1672 SCIP_VAR* var1; 1673 SCIP_VAR* var2; 1674 SCIP_Bool negated1; 1675 SCIP_Bool negated2; 1676 1677 negated1 = FALSE; 1678 negated2 = FALSE; 1679 1680 var1 = consdata->vars[v]; 1681 assert(SCIPvarIsBinary(var1)); 1682 assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_FIXED); 1683 if( SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED ) 1684 { 1685 var1 = SCIPvarGetNegatedVar(var1); 1686 negated1 = TRUE; 1687 } 1688 assert(var1 != NULL); 1689 1690 var2 = consdata->vars[v-1]; 1691 assert(SCIPvarIsBinary(var2)); 1692 assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_FIXED); 1693 if( SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED ) 1694 { 1695 var2 = SCIPvarGetNegatedVar(var2); 1696 negated2 = TRUE; 1697 } 1698 assert(var2 != NULL); 1699 1700 if( var1 == var2 ) 1701 { 1702 SCIP_Bool infeasible; 1703 SCIP_Bool fixed; 1704 1705 /* one variables is active and the other is the same negated variable */ 1706 if( negated1 != negated2 ) 1707 { 1708 /* all other variable have to be zero if it's a partitioning or packing constraint */ 1709 if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 1710 { 1711 int i; 1712 1713 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING 1714 || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/ 1715 1716 for( i = consdata->nvars - 1; i >= 0; --i ) 1717 if( i != v && i != (v-1) ) 1718 { 1719 SCIP_CALL( SCIPfixVar(scip, consdata->vars[i], 0.0, &infeasible, &fixed) ); 1720 if( infeasible ) 1721 { 1722 SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n", 1723 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i])); 1724 *cutoff = TRUE; 1725 return SCIP_OKAY; 1726 } 1727 1728 if( fixed ) 1729 ++(*nfixedvars); 1730 } 1731 } 1732 /* all setppc-type constraints are redundant */ 1733 SCIP_CALL( SCIPdelCons(scip, cons) ); 1734 ++(*ndelconss); 1735 return SCIP_OKAY; 1736 } 1737 /* both variables are either active or negated */ 1738 else 1739 { 1740 /* this variable can be fixed to zero if it's a partitioning or packing constraint */ 1741 if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 1742 { 1743 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING 1744 || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/ 1745 1746 SCIP_CALL( SCIPfixVar(scip, var1, negated1 ? 1.0 : 0.0, &infeasible, &fixed) ); 1747 if( infeasible ) 1748 { 1749 SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == %g\n", 1750 SCIPconsGetName(cons), SCIPvarGetName(var1), negated1 ? 1.0 : 0.0); 1751 *cutoff = TRUE; 1752 return SCIP_OKAY; 1753 } 1754 1755 if( fixed ) 1756 ++(*nfixedvars); 1757 } 1758 /* multiple entries of variable can be replaced by single entry */ 1759 else 1760 { 1761 SCIP_CALL( delCoefPos(scip, cons, v) ); /* only some changed behind position v-1, so it's okay */ 1762 ++(*nchgcoefs); 1763 } 1764 } 1765 consdata->changed = TRUE; 1766 } 1767 } 1768 consdata->merged = TRUE; 1769 1770 return SCIP_OKAY; 1771 } 1772 1773 /** deletes all zero-fixed variables and replace aggregated variables */ 1774 static 1775 SCIP_RETCODE applyFixings( 1776 SCIP* scip, /**< SCIP data structure */ 1777 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */ 1778 int* naddconss, /**< pointer to count number of added constraints, or NULL indicating we 1779 * can not resolve multi-aggregations 1780 */ 1781 int* ndelconss, /**< pointer to count number of deleted constraints, or NULL indicating we 1782 * can not resolve multi-aggregations 1783 */ 1784 int* nfixedvars, /**< pointer to store number of fixed variables, or NULL indicating we can 1785 * not resolve multi-aggregations 1786 */ 1787 SCIP_Bool* cutoff /**< pointer to store whether a fixing leads to a cutoff, or NULL 1788 * indicating we can not resolve multi-aggregations 1789 */ 1790 ) 1791 { 1792 SCIP_CONSDATA* consdata; 1793 int v; 1794 1795 assert(scip != NULL); 1796 assert(cons != NULL); 1797 1798 consdata = SCIPconsGetData(cons); 1799 assert(consdata != NULL); 1800 1801 /* all multi-aggregations should be resolved */ 1802 consdata->existmultaggr = FALSE; 1803 1804 v = 0; 1805 while( v < consdata->nvars ) 1806 { 1807 SCIP_VAR* var; 1808 1809 var = consdata->vars[v]; 1810 assert(SCIPvarIsBinary(var)); 1811 1812 if( SCIPvarGetUbGlobal(var) < 0.5 ) 1813 { 1814 assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0)); 1815 SCIP_CALL( delCoefPos(scip, cons, v) ); 1816 } 1817 else 1818 { 1819 SCIP_VAR* repvar; 1820 SCIP_Bool negated; 1821 1822 /* get binary representative of variable */ 1823 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) ); 1824 1825 /* resolve multi-aggregation */ 1826 if( SCIPvarGetStatus(repvar) == SCIP_VARSTATUS_MULTAGGR || (SCIPvarGetStatus(repvar) == SCIP_VARSTATUS_NEGATED && SCIPvarGetStatus(SCIPvarGetNegatedVar(repvar)) == SCIP_VARSTATUS_MULTAGGR) ) 1827 { 1828 SCIP_VAR** consvars; 1829 SCIP_Real* consvals; 1830 SCIP_Real constant = 0.0; 1831 SCIP_Bool easycase; 1832 int nconsvars; 1833 int requiredsize; 1834 int v2; 1835 1836 nconsvars = 1; 1837 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 1) ); 1838 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 1) ); 1839 consvars[0] = repvar; 1840 consvals[0] = 1.0; 1841 1842 /* get active variables for new constraint */ 1843 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize, TRUE) ); 1844 /* if space was not enough we need to resize the buffers */ 1845 if( requiredsize > nconsvars ) 1846 { 1847 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); 1848 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); 1849 1850 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) ); 1851 assert(requiredsize <= nconsvars); 1852 } 1853 1854 easycase = FALSE; 1855 1856 if( SCIPisZero(scip, constant) ) 1857 { 1858 /* add active representation */ 1859 for( v2 = nconsvars - 1; v2 >= 0; --v2 ) 1860 { 1861 if( !SCIPvarIsBinary(consvars[v2]) ) 1862 break; 1863 1864 if( !SCIPisEQ(scip, consvals[v2], 1.0) ) 1865 break; 1866 } 1867 1868 if( v2 < 0 ) 1869 easycase = TRUE; 1870 } 1871 else if( SCIPisFeasEQ(scip, constant, 1.0) ) 1872 { 1873 /* check for another multi-aggregation */ 1874 for( v2 = consdata->nvars - 1; v2 > v; --v2 ) 1875 { 1876 if( SCIPvarGetStatus(SCIPvarGetProbvar(consdata->vars[v])) == SCIP_VARSTATUS_MULTAGGR ) 1877 break; 1878 } 1879 1880 /* constraint is redundant */ 1881 if( v2 == v && nconsvars == 0 ) 1882 { 1883 /* we can fix */ 1884 if( consdata->nvars > 1 && (SCIP_SETPPCTYPE)consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) 1885 { 1886 if( nfixedvars != NULL ) 1887 { 1888 SCIP_Bool fixed; 1889 1890 assert(cutoff != NULL); 1891 1892 for( v2 = consdata->nvars - 1; v2 >= 0; --v2 ) 1893 { 1894 if( consdata->vars[v2] != var ) 1895 { 1896 SCIPdebugMsg(scip, "trying to fix <%s> to 0 due to at least one variable is already fixed to 1\n", SCIPvarGetName(consdata->vars[v2])); 1897 1898 /* fix all remaining variables to zero, constraint is already feasible or infeasible */ 1899 SCIP_CALL( SCIPfixVar(scip, consdata->vars[v2], 0.0, cutoff, &fixed) ); 1900 if( *cutoff ) 1901 { 1902 SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n", 1903 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[v2])); 1904 1905 SCIPfreeBufferArray(scip, &consvals); 1906 SCIPfreeBufferArray(scip, &consvars); 1907 1908 goto TERMINATE; 1909 } 1910 1911 if( fixed ) 1912 ++(*nfixedvars); 1913 } 1914 } 1915 } 1916 } 1917 1918 if( ndelconss != NULL && (nfixedvars != NULL || consdata->nvars == 1 || (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING) ) 1919 { 1920 /* delete old constraint */ 1921 SCIP_CALL( SCIPdelCons(scip, cons) ); 1922 ++(*ndelconss); 1923 } 1924 SCIPfreeBufferArray(scip, &consvals); 1925 SCIPfreeBufferArray(scip, &consvars); 1926 1927 goto TERMINATE; 1928 } 1929 } 1930 1931 /* we can easily add the coefficients and still have a setppc constraint */ 1932 if( easycase ) 1933 { 1934 /* delete old (multi-aggregated) variable */ 1935 SCIP_CALL( delCoefPos(scip, cons, v) ); 1936 1937 /* add active representation */ 1938 for( v2 = nconsvars - 1; v2 >= 0; --v2 ) 1939 { 1940 assert(SCIPvarIsBinary(consvars[v2])); 1941 assert(SCIPvarIsActive(consvars[v2]) || (SCIPvarGetStatus(consvars[v2]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(consvars[v2])))); 1942 1943 SCIP_CALL( addCoef(scip, cons, consvars[v2]) ); 1944 } 1945 } 1946 /* we need to degrade this setppc constraint to a linear constraint */ 1947 else if( (ndelconss != NULL && naddconss != NULL) || SCIPconsIsAdded(cons) ) 1948 { 1949 char name[SCIP_MAXSTRLEN]; 1950 SCIP_CONS* newcons; 1951 SCIP_Real lhs; 1952 SCIP_Real rhs; 1953 int size; 1954 int k; 1955 1956 /* it might happen that there are more than one multi-aggregated variable, so we need to get the whole 1957 * probvar sum over all variables 1958 */ 1959 1960 size = MAX(nconsvars, 1) + consdata->nvars - 1; 1961 1962 /* memory needed is at least old number of variables - 1 + number of variables in first multi-aggregation */ 1963 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, size) ); 1964 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, size) ); 1965 1966 nconsvars = consdata->nvars; 1967 1968 /* add constraint variables to new linear variables */ 1969 for( k = consdata->nvars - 1; k >= 0; --k ) 1970 { 1971 consvars[k] = consdata->vars[k]; 1972 consvals[k] = 1.0; 1973 } 1974 1975 constant = 0.0; 1976 1977 /* get active variables for new constraint */ 1978 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize, TRUE) ); 1979 1980 /* if space was not enough (we found another multi-aggregation), we need to resize the buffers */ 1981 if( requiredsize > nconsvars ) 1982 { 1983 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); 1984 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); 1985 1986 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) ); 1987 assert(requiredsize <= nconsvars); 1988 } 1989 1990 /* compute sides */ 1991 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) 1992 { 1993 lhs = -SCIPinfinity(scip); 1994 rhs = 1.0 - constant; 1995 } 1996 else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) 1997 { 1998 lhs = 1.0 - constant; 1999 rhs = 1.0 - constant; 2000 } 2001 else 2002 { 2003 assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING); 2004 lhs = 1.0 - constant; 2005 rhs = SCIPinfinity(scip); 2006 } 2007 2008 /* create linear constraint */ 2009 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons)); 2010 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, nconsvars, consvars, consvals, lhs, rhs, 2011 SCIPconsIsInitial(cons), 2012 SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), 2013 SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), 2014 SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) ); 2015 SCIP_CALL( SCIPaddCons(scip, newcons) ); 2016 2017 SCIPdebugMsg(scip, "added linear constraint: "); 2018 SCIPdebugPrintCons(scip, newcons, NULL); 2019 SCIP_CALL( SCIPreleaseCons(scip, &newcons) ); 2020 2021 SCIPfreeBufferArray(scip, &consvals); 2022 SCIPfreeBufferArray(scip, &consvars); 2023 2024 /* delete old constraint */ 2025 SCIP_CALL( SCIPdelCons(scip, cons) ); 2026 if( ndelconss != NULL && naddconss != NULL ) 2027 { 2028 ++(*ndelconss); 2029 ++(*naddconss); 2030 } 2031 2032 goto TERMINATE; 2033 } 2034 /* we need to degrade this setppc constraint to a linear constraint*/ 2035 else 2036 { 2037 /* check, if the variable should be replaced with the representative */ 2038 if( repvar != var ) 2039 { 2040 /* delete old (aggregated) variable */ 2041 SCIP_CALL( delCoefPos(scip, cons, v) ); 2042 2043 /* add representative instead */ 2044 SCIP_CALL( addCoef(scip, cons, repvar) ); 2045 } 2046 2047 SCIPwarningMessage(scip, "setppc constraint <%s> has a multi-aggregated variable, which was not resolved and therefore could lead to aborts\n", SCIPconsGetName(cons)); 2048 ++v; 2049 } 2050 2051 SCIPfreeBufferArray(scip, &consvals); 2052 SCIPfreeBufferArray(scip, &consvars); 2053 } 2054 else 2055 { 2056 /* check, if the variable should be replaced with the representative */ 2057 if( repvar != var ) 2058 { 2059 /* delete old (aggregated) variable */ 2060 SCIP_CALL( delCoefPos(scip, cons, v) ); 2061 2062 /* add representative instead */ 2063 SCIP_CALL( addCoef(scip, cons, repvar) ); 2064 } 2065 else 2066 ++v; 2067 } 2068 } 2069 } 2070 2071 TERMINATE: 2072 /* all multi-aggregations should be resolved */ 2073 consdata->existmultaggr = FALSE; 2074 2075 return SCIP_OKAY; 2076 } 2077 2078 /** analyzes conflicting assignment on given constraint where all of the variables where assigned to zero, 2079 * and adds conflict constraint to problem 2080 */ 2081 static 2082 SCIP_RETCODE analyzeConflictZero( 2083 SCIP* scip, /**< SCIP data structure */ 2084 SCIP_CONS* cons /**< set partitioning / packing / covering constraint that detected the conflict */ 2085 ) 2086 { 2087 SCIP_CONSDATA* consdata; 2088 int v; 2089 2090 /* conflict analysis can only be applied in solving stage and if it is applicable */ 2091 if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) ) 2092 return SCIP_OKAY; 2093 2094 consdata = SCIPconsGetData(cons); 2095 assert(consdata != NULL); 2096 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING 2097 || consdata->setppctype == SCIP_SETPPCTYPE_COVERING); /*lint !e641*/ 2098 2099 /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */ 2100 SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) ); 2101 2102 for( v = 0; v < consdata->nvars; ++v ) 2103 { 2104 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) ); 2105 } 2106 2107 /* analyze the conflict */ 2108 SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) ); 2109 2110 return SCIP_OKAY; 2111 } 2112 2113 /** analyzes conflicting assignment on given constraint where two of the variables where assigned to one, 2114 * and adds conflict constraint to problem 2115 */ 2116 static 2117 SCIP_RETCODE analyzeConflictOne( 2118 SCIP* scip, /**< SCIP data structure */ 2119 SCIP_CONS* cons /**< set partitioning / packing / covering constraint that detected the conflict */ 2120 ) 2121 { 2122 SCIP_CONSDATA* consdata; 2123 int v; 2124 int n; 2125 2126 /* conflict analysis can only be applied in solving stage and if it is applicable */ 2127 if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) ) 2128 return SCIP_OKAY; 2129 2130 consdata = SCIPconsGetData(cons); 2131 assert(consdata != NULL); 2132 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING 2133 || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/ 2134 2135 /* initialize conflict analysis, and add the two variables assigned to one to conflict candidate queue */ 2136 SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) ); 2137 2138 n = 0; 2139 for( v = 0; v < consdata->nvars && n < 2; ++v ) 2140 { 2141 if( SCIPvarGetLbLocal(consdata->vars[v]) > 0.5 ) 2142 { 2143 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) ); 2144 n++; 2145 } 2146 } 2147 assert(n == 2); 2148 2149 /* analyze the conflict */ 2150 SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) ); 2151 2152 return SCIP_OKAY; 2153 } 2154 2155 /** checks constraint for violation only looking at the fixed variables, applies further fixings if possible */ 2156 static 2157 SCIP_RETCODE processFixings( 2158 SCIP* scip, /**< SCIP data structure */ 2159 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint to be processed */ 2160 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */ 2161 int* nfixedvars, /**< pointer to count number of deleted variables */ 2162 SCIP_Bool* addcut, /**< pointer to store whether this constraint must be added as a cut */ 2163 SCIP_Bool* mustcheck /**< pointer to store whether this constraint must be checked for feasibility */ 2164 ) 2165 { 2166 SCIP_CONSDATA* consdata; 2167 #ifndef NDEBUG 2168 int oldnfixedvars; 2169 #endif 2170 2171 assert(cons != NULL); 2172 assert(SCIPconsGetHdlr(cons) != NULL); 2173 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0); 2174 assert(cutoff != NULL); 2175 assert(nfixedvars != NULL); 2176 assert(addcut != NULL); 2177 assert(mustcheck != NULL); 2178 2179 #ifndef NDEBUG 2180 oldnfixedvars = *nfixedvars; 2181 #endif 2182 2183 consdata = SCIPconsGetData(cons); 2184 assert(consdata != NULL); 2185 assert(consdata->nvars == 0 || consdata->vars != NULL); 2186 assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars); 2187 assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars); 2188 2189 *addcut = FALSE; 2190 *mustcheck = TRUE; 2191 2192 /*SCIPdebugMsg(scip, "processing constraint <%s> with respect to fixed variables (%d fixed to 0.0, %d fixed to 1.0)\n", 2193 SCIPconsGetName(cons), consdata->nfixedzeros, consdata->nfixedones);*/ 2194 2195 if( consdata->nfixedones == 1 ) 2196 { 2197 /* exactly one variable is fixed to 1: 2198 * - a set covering constraint is feasible anyway and can be disabled 2199 * - all other variables in a set partitioning or packing constraint must be zero 2200 */ 2201 if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 2202 { 2203 SCIPdebugMsg(scip, " -> disabling set covering constraint <%s>\n", SCIPconsGetName(cons)); 2204 SCIP_CALL( SCIPdelConsLocal(scip, cons) ); 2205 } 2206 else 2207 { 2208 if( consdata->nfixedzeros < consdata->nvars - 1 ) 2209 { 2210 SCIP_VAR** vars; 2211 SCIP_VAR* var; 2212 #ifndef NDEBUG 2213 SCIP_Bool fixedonefound; 2214 #endif 2215 SCIP_Bool infeasible; 2216 SCIP_Bool tightened; 2217 int nvars; 2218 int v; 2219 int oneidx = -1; 2220 2221 SCIPdebugMsg(scip, " -> fixing all other variables to zero in set packing/partitioning constraint <%s>\n", 2222 SCIPconsGetName(cons)); 2223 2224 /* unfixed variables exist: fix them to zero; 2225 * this could result in additional variables fixed to one due to aggregations; in this case, the 2226 * constraint is infeasible in local bounds 2227 */ 2228 vars = consdata->vars; 2229 nvars = consdata->nvars; 2230 #ifndef NDEBUG 2231 fixedonefound = FALSE; 2232 #endif 2233 for( v = 0; v < nvars && consdata->nfixedones == 1; ++v ) 2234 { 2235 var = vars[v]; 2236 assert(SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || SCIPisFeasEQ(scip, SCIPvarGetUbLocal(var), 1.0)); 2237 if( SCIPvarGetLbLocal(var) < 0.5 ) 2238 { 2239 SCIP_CALL( SCIPinferBinvarCons(scip, var, FALSE, cons, oneidx, &infeasible, &tightened) ); 2240 assert(!infeasible); 2241 2242 if( tightened ) 2243 ++(*nfixedvars); 2244 2245 SCIPdebugMsg(scip, " -> fixed <%s> to zero (tightened=%u)\n", SCIPvarGetName(var), tightened); 2246 } 2247 else 2248 { 2249 #ifndef NDEBUG 2250 fixedonefound = TRUE; 2251 #endif 2252 oneidx = v; 2253 } 2254 } 2255 /* the fixed to one variable must have been found, and at least one variable must have been fixed */ 2256 assert(consdata->nfixedones >= 2 || (fixedonefound && *nfixedvars > oldnfixedvars)); 2257 2258 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 2259 } 2260 2261 /* now all other variables are fixed to zero: 2262 * the constraint is feasible, and if it's not modifiable, it is redundant 2263 */ 2264 if( !SCIPconsIsModifiable(cons) && consdata->nfixedones == 1 ) 2265 { 2266 SCIPdebugMsg(scip, " -> disabling set packing/partitioning constraint <%s>\n", SCIPconsGetName(cons)); 2267 SCIP_CALL( SCIPdelConsLocal(scip, cons) ); 2268 } 2269 } 2270 *mustcheck = FALSE; 2271 } 2272 2273 if( consdata->nfixedones >= 2 ) 2274 { 2275 /* at least two variables are fixed to 1: 2276 * - a set covering constraint is feasible anyway and can be disabled 2277 * - a set partitioning or packing constraint is infeasible 2278 */ 2279 if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 2280 { 2281 SCIPdebugMsg(scip, " -> disabling set covering constraint <%s>\n", SCIPconsGetName(cons)); 2282 SCIP_CALL( SCIPdelConsLocal(scip, cons) ); 2283 } 2284 else 2285 { 2286 SCIPdebugMsg(scip, " -> conflict on set packing/partitioning constraint <%s>\n", SCIPconsGetName(cons)); 2287 2288 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 2289 2290 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */ 2291 SCIP_CALL( analyzeConflictOne(scip, cons) ); 2292 2293 *cutoff = TRUE; 2294 } 2295 *mustcheck = FALSE; 2296 } 2297 else if( consdata->nfixedzeros == consdata->nvars ) 2298 { 2299 /* all variables are fixed to zero: 2300 * - a set packing constraint is feasible anyway, and if it's unmodifiable, it can be disabled 2301 * - a set partitioning or covering constraint is infeasible, and if it's unmodifiable, the node 2302 * can be cut off -- otherwise, the constraint must be added as a cut and further pricing must 2303 * be performed 2304 */ 2305 assert(consdata->nfixedones == 0); 2306 2307 if( consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) /*lint !e641*/ 2308 { 2309 if( !SCIPconsIsModifiable(cons) ) 2310 { 2311 SCIPdebugMsg(scip, " -> disabling set packing constraint <%s>\n", SCIPconsGetName(cons)); 2312 SCIP_CALL( SCIPdelConsLocal(scip, cons) ); 2313 } 2314 } 2315 else 2316 { 2317 SCIPdebugMsg(scip, " -> set covering/partitioning constraint <%s> is infeasible\n", SCIPconsGetName(cons)); 2318 2319 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 2320 if( SCIPconsIsModifiable(cons) ) 2321 *addcut = TRUE; 2322 else 2323 { 2324 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */ 2325 SCIP_CALL( analyzeConflictZero(scip, cons) ); 2326 2327 *cutoff = TRUE; 2328 } 2329 } 2330 *mustcheck = FALSE; 2331 } 2332 else if( consdata->nfixedzeros == consdata->nvars - 1 && consdata->nfixedones == 0 ) 2333 { 2334 /* all variables except one are fixed to zero: 2335 * - a set packing constraint is feasible anyway, and if it's unmodifiable, it can be disabled 2336 * - an unmodifiable set partitioning or covering constraint is feasible and can be disabled after the 2337 * remaining variable is fixed to one 2338 * - a modifiable set partitioning or covering constraint must be checked manually 2339 */ 2340 if( consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) /*lint !e641*/ 2341 { 2342 if( !SCIPconsIsModifiable(cons) ) 2343 { 2344 SCIPdebugMsg(scip, " -> disabling set packing constraint <%s>\n", SCIPconsGetName(cons)); 2345 SCIP_CALL( SCIPdelConsLocal(scip, cons) ); 2346 } 2347 *mustcheck = FALSE; 2348 } 2349 else if( !SCIPconsIsModifiable(cons) ) 2350 { 2351 SCIP_VAR** vars; 2352 SCIP_VAR* var; 2353 SCIP_Bool infeasible; 2354 SCIP_Bool tightened; 2355 int nvars; 2356 int v; 2357 2358 /* search the single variable that can be fixed */ 2359 vars = consdata->vars; 2360 nvars = consdata->nvars; 2361 for( v = 0; v < nvars; ++v ) 2362 { 2363 var = vars[v]; 2364 assert(SCIPisFeasZero(scip, SCIPvarGetLbLocal(var))); 2365 assert(SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || SCIPisFeasEQ(scip, SCIPvarGetUbLocal(var), 1.0)); 2366 if( SCIPvarGetUbLocal(var) > 0.5 ) 2367 { 2368 SCIPdebugMsg(scip, " -> fixing remaining variable <%s> to one in set covering/partitioning constraint <%s>\n", 2369 SCIPvarGetName(var), SCIPconsGetName(cons)); 2370 SCIP_CALL( SCIPinferBinvarCons(scip, var, TRUE, cons, 0, &infeasible, &tightened) ); 2371 assert(!infeasible); 2372 assert(tightened); 2373 2374 ++(*nfixedvars); 2375 break; 2376 } 2377 } 2378 assert(v < nvars); 2379 assert(consdata->nfixedzeros == consdata->nvars - 1); 2380 assert(consdata->nfixedones == 1); 2381 2382 SCIP_CALL( SCIPdelConsLocal(scip, cons) ); 2383 *mustcheck = FALSE; 2384 } 2385 } 2386 assert(consdata->nfixedzeros + consdata->nfixedones <= consdata->nvars); 2387 2388 return SCIP_OKAY; 2389 } 2390 2391 /** checks constraint for violation, returns TRUE iff constraint is feasible */ 2392 static 2393 SCIP_Bool checkCons( 2394 SCIP* scip, /**< SCIP data structure */ 2395 SCIP_CONSDATA* consdata, /**< set partitioning / packing / covering constraint to be checked */ 2396 SCIP_SOL* sol /**< primal CIP solution */ 2397 ) 2398 { 2399 SCIP_VAR** vars; 2400 SCIP_Real solval; 2401 SCIP_Real sum; 2402 SCIP_Real sumbound; 2403 SCIP_Real absviol; 2404 SCIP_Real relviol; 2405 SCIP_Bool check; 2406 int nvars; 2407 int v; 2408 2409 /* calculate the constraint's activity */ 2410 vars = consdata->vars; 2411 nvars = consdata->nvars; 2412 sum = 0.0; 2413 sumbound = ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING ? 1.0 : 1.0 + 2*SCIPfeastol(scip)); 2414 for( v = 0; v < nvars && sum < sumbound; ++v ) /* if sum >= sumbound, the feasibility is clearly decided */ 2415 { 2416 assert(SCIPvarIsBinary(vars[v])); 2417 2418 solval = SCIPgetSolVal(scip, sol, vars[v]); 2419 assert(SCIPisFeasGE(scip, solval, 0.0) && SCIPisFeasLE(scip, solval, 1.0)); 2420 2421 sum += solval; 2422 } 2423 2424 absviol = sum - 1.0; 2425 relviol = SCIPrelDiff(sum, 1.0); 2426 switch( consdata->setppctype ) 2427 { 2428 case SCIP_SETPPCTYPE_PARTITIONING: 2429 /* in case of partitioning, the violation is equal to the absolute difference between sum and 1 */ 2430 absviol = REALABS(absviol); 2431 relviol = REALABS(relviol); 2432 check = SCIPisFeasEQ(scip, sum, 1.0); 2433 break; 2434 case SCIP_SETPPCTYPE_PACKING: 2435 /* in case of packing, the violation is equal to how much sum exceeds 1 */ 2436 check = SCIPisFeasLE(scip, sum, 1.0); 2437 break; 2438 case SCIP_SETPPCTYPE_COVERING: 2439 /* in case of covering, the violation is equal to how much 1 exceeds sum */ 2440 absviol = -absviol; 2441 relviol = -relviol; 2442 check = SCIPisFeasGE(scip, sum, 1.0); 2443 break; 2444 default: 2445 SCIPerrorMessage("unknown setppc type\n"); 2446 SCIPABORT(); 2447 return FALSE; /*lint !e527*/ 2448 } 2449 2450 if( sol != NULL ) 2451 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol); 2452 2453 return check; 2454 } 2455 2456 /** creates an LP row in a set partitioning / packing / covering constraint data object */ 2457 static 2458 SCIP_RETCODE createRow( 2459 SCIP* scip, /**< SCIP data structure */ 2460 SCIP_CONS* cons /**< set partitioning / packing / covering constraint */ 2461 ) 2462 { 2463 SCIP_CONSDATA* consdata; 2464 SCIP_Real lhs; 2465 SCIP_Real rhs; 2466 2467 consdata = SCIPconsGetData(cons); 2468 assert(consdata != NULL); 2469 assert(consdata->row == NULL); 2470 2471 switch( consdata->setppctype ) 2472 { 2473 case SCIP_SETPPCTYPE_PARTITIONING: 2474 lhs = 1.0; 2475 rhs = 1.0; 2476 break; 2477 case SCIP_SETPPCTYPE_PACKING: 2478 lhs = -SCIPinfinity(scip); 2479 rhs = 1.0; 2480 break; 2481 case SCIP_SETPPCTYPE_COVERING: 2482 lhs = 1.0; 2483 rhs = SCIPinfinity(scip); 2484 break; 2485 default: 2486 SCIPerrorMessage("unknown setppc type\n"); 2487 return SCIP_INVALIDDATA; 2488 } 2489 2490 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons), lhs, rhs, 2491 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsRemovable(cons)) ); 2492 2493 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->row, consdata->nvars, consdata->vars, 1.0) ); 2494 2495 return SCIP_OKAY; 2496 } 2497 2498 /** adds setppc constraint as cut to the LP */ 2499 static 2500 SCIP_RETCODE addCut( 2501 SCIP* scip, /**< SCIP data structure */ 2502 SCIP_CONS* cons, /**< setppc constraint */ 2503 SCIP_Bool* cutoff /**< whether a cutoff has been detected */ 2504 ) 2505 { 2506 SCIP_CONSDATA* consdata; 2507 2508 assert( cutoff != NULL ); 2509 *cutoff = FALSE; 2510 2511 consdata = SCIPconsGetData(cons); 2512 assert(consdata != NULL); 2513 2514 if( consdata->row == NULL ) 2515 { 2516 /* convert set partitioning constraint data into LP row */ 2517 SCIP_CALL( createRow(scip, cons) ); 2518 } 2519 assert(consdata->row != NULL); 2520 2521 /* insert LP row as cut */ 2522 if( !SCIProwIsInLP(consdata->row) ) 2523 { 2524 SCIPdebugMsg(scip, "adding constraint <%s> as cut to the LP\n", SCIPconsGetName(cons)); 2525 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) ); 2526 } 2527 2528 return SCIP_OKAY; 2529 } 2530 2531 /** adds setppc constraint as row to the NLP, if not added yet */ 2532 static 2533 SCIP_RETCODE addNlrow( 2534 SCIP* scip, /**< SCIP data structure */ 2535 SCIP_CONS* cons /**< setppc constraint */ 2536 ) 2537 { 2538 SCIP_CONSDATA* consdata; 2539 2540 assert(SCIPisNLPConstructed(scip)); 2541 2542 /* skip deactivated, redundant, or local constraints (the NLP does not allow for local rows at the moment) */ 2543 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) ) 2544 return SCIP_OKAY; 2545 2546 consdata = SCIPconsGetData(cons); 2547 assert(consdata != NULL); 2548 2549 if( consdata->nlrow == NULL ) 2550 { 2551 SCIP_Real lhs, rhs; 2552 SCIP_Real* coefs; 2553 int i; 2554 2555 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) ); 2556 for( i = 0; i < consdata->nvars; ++i ) 2557 coefs[i] = 1.0; 2558 2559 switch( SCIPgetTypeSetppc(scip, cons) ) 2560 { 2561 case SCIP_SETPPCTYPE_PARTITIONING: 2562 lhs = 1.0; 2563 rhs = 1.0; 2564 break; 2565 2566 case SCIP_SETPPCTYPE_PACKING: 2567 lhs = -SCIPinfinity(scip); 2568 rhs = 1.0; 2569 break; 2570 2571 case SCIP_SETPPCTYPE_COVERING: 2572 lhs = 1.0; 2573 rhs = SCIPinfinity(scip); 2574 break; 2575 2576 default: 2577 SCIPerrorMessage("unexpected setppc type\n"); 2578 return SCIP_ERROR; 2579 } 2580 2581 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 2582 0.0, consdata->nvars, consdata->vars, coefs, NULL, lhs, rhs, SCIP_EXPRCURV_LINEAR) ); 2583 assert(consdata->nlrow != NULL); 2584 2585 SCIPfreeBufferArray(scip, &coefs); 2586 } 2587 2588 if( !SCIPnlrowIsInNLP(consdata->nlrow) ) 2589 { 2590 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) ); 2591 } 2592 2593 return SCIP_OKAY; 2594 } 2595 2596 /** checks constraint for violation, and adds it as a cut if possible */ 2597 static 2598 SCIP_RETCODE separateCons( 2599 SCIP* scip, /**< SCIP data structure */ 2600 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint to be separated */ 2601 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */ 2602 SCIP_Bool lpfeas, /**< is the given solution feasible for the current LP ? */ 2603 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */ 2604 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */ 2605 SCIP_Bool* reduceddom /**< pointer to store TRUE, if a domain reduction was found */ 2606 ) 2607 { 2608 SCIP_CONSDATA* consdata; 2609 SCIP_Bool addcut; 2610 SCIP_Bool mustcheck; 2611 2612 assert(cons != NULL); 2613 assert(SCIPconsGetHdlr(cons) != NULL); 2614 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0); 2615 assert(cutoff != NULL); 2616 assert(separated != NULL); 2617 assert(reduceddom != NULL); 2618 2619 *cutoff = FALSE; 2620 2621 consdata = SCIPconsGetData(cons); 2622 assert(consdata != NULL); 2623 assert(consdata->nvars == 0 || consdata->vars != NULL); 2624 assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars); 2625 assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars); 2626 2627 /* skip constraints already in the LP */ 2628 if( lpfeas && consdata->row != NULL && SCIProwIsInLP(consdata->row) ) 2629 return SCIP_OKAY; 2630 2631 SCIPdebugMsg(scip, "separating constraint <%s>\n", SCIPconsGetName(cons)); 2632 2633 /* check constraint for violation only looking at the fixed variables, apply further fixings if possible */ 2634 if( lpfeas ) 2635 { 2636 int nfixedvars = 0; 2637 2638 SCIP_CALL( processFixings(scip, cons, cutoff, &nfixedvars, &addcut, &mustcheck) ); 2639 2640 *reduceddom = (nfixedvars > 0); 2641 } 2642 else 2643 { 2644 mustcheck = TRUE; 2645 addcut = FALSE; 2646 } 2647 2648 if( mustcheck ) 2649 { 2650 assert(!addcut); 2651 2652 /* variable's fixings didn't give us any information -> we have to check the constraint */ 2653 if( lpfeas && consdata->row != NULL ) 2654 { 2655 SCIP_Real feasibility; 2656 2657 assert(!SCIProwIsInLP(consdata->row)); 2658 feasibility = SCIPgetRowSolFeasibility(scip, consdata->row, sol); 2659 addcut = SCIPisFeasNegative(scip, feasibility); 2660 } 2661 else 2662 addcut = !checkCons(scip, consdata, sol); 2663 2664 if( !addcut ) 2665 { 2666 /* constraint was feasible -> increase age */ 2667 SCIP_CALL( SCIPincConsAge(scip, cons) ); 2668 } 2669 } 2670 2671 if( addcut ) 2672 { 2673 /* insert LP row as cut */ 2674 SCIP_CALL( addCut(scip, cons, cutoff) ); 2675 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 2676 *separated = TRUE; 2677 } 2678 2679 return SCIP_OKAY; 2680 } 2681 2682 /** enforces the pseudo solution on the given constraint */ 2683 static 2684 SCIP_RETCODE enforcePseudo( 2685 SCIP* scip, /**< SCIP data structure */ 2686 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint to be separated */ 2687 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */ 2688 SCIP_Bool* infeasible, /**< pointer to store TRUE, if the constraint was infeasible */ 2689 SCIP_Bool* reduceddom, /**< pointer to store TRUE, if a domain reduction was found */ 2690 SCIP_Bool* solvelp /**< pointer to store TRUE, if the LP has to be solved */ 2691 ) 2692 { 2693 SCIP_Bool addcut; 2694 SCIP_Bool mustcheck; 2695 int nfixedvars = 0; 2696 2697 assert(!SCIPhasCurrentNodeLP(scip)); 2698 assert(cons != NULL); 2699 assert(SCIPconsGetHdlr(cons) != NULL); 2700 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0); 2701 assert(cutoff != NULL); 2702 assert(infeasible != NULL); 2703 assert(reduceddom != NULL); 2704 assert(solvelp != NULL); 2705 2706 /* check constraint for violation only looking at the fixed variables, apply further fixings if possible */ 2707 SCIP_CALL( processFixings(scip, cons, cutoff, &nfixedvars, &addcut, &mustcheck) ); 2708 2709 *reduceddom = (nfixedvars > 0); 2710 2711 if( mustcheck ) 2712 { 2713 SCIP_CONSDATA* consdata; 2714 2715 assert(!addcut); 2716 2717 consdata = SCIPconsGetData(cons); 2718 assert(consdata != NULL); 2719 2720 if( checkCons(scip, consdata, NULL) ) 2721 { 2722 /* constraint was feasible -> increase age */ 2723 SCIP_CALL( SCIPincConsAge(scip, cons) ); 2724 } 2725 else 2726 { 2727 /* constraint was infeasible -> reset age */ 2728 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 2729 *infeasible = TRUE; 2730 } 2731 } 2732 2733 if( addcut ) 2734 { 2735 /* a cut must be added to the LP -> we have to solve the LP immediately */ 2736 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 2737 *solvelp = TRUE; 2738 } 2739 2740 return SCIP_OKAY; 2741 } 2742 2743 /** gets the key of the given element */ 2744 static 2745 SCIP_DECL_HASHGETKEY(hashGetKeySetppccons) 2746 { /*lint --e{715}*/ 2747 /* the key is the element itself */ 2748 return elem; 2749 } 2750 2751 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables */ 2752 static 2753 SCIP_DECL_HASHKEYEQ(hashKeyEqSetppccons) 2754 { 2755 #ifndef NDEBUG 2756 SCIP* scip; 2757 #endif 2758 SCIP_CONSDATA* consdata1; 2759 SCIP_CONSDATA* consdata2; 2760 SCIP_Bool coefsequal; 2761 int i; 2762 2763 consdata1 = SCIPconsGetData((SCIP_CONS*)key1); 2764 consdata2 = SCIPconsGetData((SCIP_CONS*)key2); 2765 assert(consdata1->sorted); 2766 assert(consdata2->sorted); 2767 #ifndef NDEBUG 2768 scip = (SCIP*)userptr; 2769 assert(scip != NULL); 2770 #endif 2771 2772 /* checks trivial case */ 2773 if( consdata1->nvars != consdata2->nvars ) 2774 return FALSE; 2775 2776 coefsequal = TRUE; 2777 2778 for( i = 0; i < consdata1->nvars; ++i ) 2779 { 2780 /* tests if variables are equal */ 2781 if( consdata1->vars[i] != consdata2->vars[i] ) 2782 { 2783 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 || 2784 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1); 2785 coefsequal = FALSE; 2786 break; 2787 } 2788 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0); 2789 } 2790 2791 return coefsequal; 2792 } 2793 2794 /** returns the hash value of the key */ 2795 static 2796 SCIP_DECL_HASHKEYVAL(hashKeyValSetppccons) 2797 { 2798 SCIP_CONSDATA* consdata; 2799 int minidx; 2800 int mididx; 2801 int maxidx; 2802 #ifndef NDEBUG 2803 SCIP* scip; 2804 2805 scip = (SCIP*)userptr; 2806 assert(scip != NULL); 2807 #endif 2808 2809 consdata = SCIPconsGetData((SCIP_CONS*)key); 2810 assert(consdata != NULL); 2811 assert(consdata->nvars > 0); 2812 2813 /* sorts the constraints */ 2814 consdataSort(consdata); 2815 2816 minidx = SCIPvarGetIndex(consdata->vars[0]); 2817 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]); 2818 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]); 2819 assert(minidx >= 0 && minidx <= maxidx); 2820 2821 return SCIPhashFour(consdata->nvars, minidx, mididx, maxidx); 2822 } 2823 2824 /** add extra clique-constraints resulting from a given cliquepartition to SCIP */ 2825 static 2826 SCIP_RETCODE addExtraCliques( 2827 SCIP*const scip, /**< SCIP data structure */ 2828 SCIP_VAR**const binvars, /**< binary variables to create clique constraints */ 2829 int const nbinvars, /**< number of binary variables to create clique constraints */ 2830 int*const cliquepartition, /**< clique partition of binary variables */ 2831 int const ncliques, /**< number of cliques in cliquepartition */ 2832 SCIP_CONS**const usefulconss, /**< storage for created constraints */ 2833 int*const nusefulconss, /**< pointer to store number of useful created constraints */ 2834 int const nrounds, /**< actual presolving round */ 2835 int*const nfixedvars, /**< pointer to count number of deleted variables */ 2836 int*const naddconss, /**< pointer to count number of added constraints */ 2837 int*const ndelconss, /**< pointer to count number of deleted constraints */ 2838 int*const nchgcoefs, /**< pointer to count number of deleted coefficients */ 2839 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */ 2840 ) 2841 { 2842 SCIP_CONS* cliquecons; 2843 char name[SCIP_MAXSTRLEN]; 2844 int lastclqidx; 2845 int nadded; 2846 int c; 2847 int v; 2848 2849 assert(scip != NULL); 2850 assert(binvars != NULL || nbinvars == 0); 2851 assert(cliquepartition != NULL || nbinvars == 0); 2852 assert(ncliques >= 0 && ncliques <= nbinvars); 2853 assert(usefulconss != NULL); 2854 assert(nusefulconss != NULL); 2855 assert(nfixedvars != NULL); 2856 assert(naddconss != NULL); 2857 assert(ndelconss != NULL); 2858 assert(nchgcoefs != NULL); 2859 assert(cutoff != NULL); 2860 2861 /* no given binary variables */ 2862 if( nbinvars == 0 || ncliques == 0 ) 2863 return SCIP_OKAY; 2864 2865 assert(binvars != NULL); 2866 assert(cliquepartition != NULL); 2867 2868 /* no useful clique information */ 2869 if( ncliques == nbinvars ) 2870 return SCIP_OKAY; 2871 2872 lastclqidx = 0; 2873 2874 /* @todo: maybe sort cliques and accordingly the variables so it will be faster to add the constraints */ 2875 for( c = 0; c < ncliques - 1; ++c ) 2876 { 2877 if( lastclqidx >= cliquepartition[c] ) 2878 continue; 2879 2880 nadded = 0; 2881 2882 /* name the clique constraint */ 2883 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "extra_clq_%d_round_%d", cliquepartition[c], nrounds); 2884 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, 0, NULL, 2885 TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); 2886 2887 /* add variables to clique constraint */ 2888 for( v = c; v < nbinvars - 1; ++v ) 2889 { 2890 if( cliquepartition[c] == cliquepartition[v] ) 2891 { 2892 SCIP_CALL( addCoef(scip, cliquecons, binvars[v]) ); 2893 ++nadded; 2894 } 2895 } 2896 2897 /* @todo: try to find a good value for what are enough variables to create this constraint, maybe at least 2898 * (nmaxvars(over all conss)-nminvars(over all conss))/2 */ 2899 if( nadded >= 2 ) 2900 { 2901 SCIP_CONSDATA* cliqueconsdata; 2902 2903 SCIPdebugMsg(scip, " -> adding clique constraint: "); 2904 SCIPdebugPrintCons(scip, cliquecons, NULL); 2905 SCIP_CALL( SCIPaddCons(scip, cliquecons) ); 2906 ++(*naddconss); 2907 2908 /* we only want to consider merged constraints */ 2909 SCIP_CALL( mergeMultiples(scip, cliquecons, nfixedvars, ndelconss, nchgcoefs, cutoff) ); 2910 if( *cutoff ) 2911 { 2912 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) ); 2913 2914 return SCIP_OKAY; 2915 } 2916 2917 cliqueconsdata = SCIPconsGetData(cliquecons); 2918 assert(cliqueconsdata != NULL); 2919 2920 /* the artificial constraints could be deleted while merging */ 2921 if( !SCIPconsIsDeleted(cliquecons) && nadded - cliqueconsdata->nfixedzeros >= 2 ) 2922 { 2923 assert(cliqueconsdata->nfixedones == 0); 2924 2925 /* save the type and constraint */ 2926 usefulconss[*nusefulconss] = cliquecons; 2927 ++(*nusefulconss); 2928 } 2929 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) ); 2930 } 2931 else 2932 { 2933 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) ); 2934 } 2935 lastclqidx = cliquepartition[c]; 2936 } 2937 2938 return SCIP_OKAY; 2939 } 2940 2941 2942 /** start to collect setpartitioning and setpacking constraints, and try to remove fixed variables and merged these 2943 * constraints 2944 */ 2945 static 2946 SCIP_RETCODE collectCliqueConss( 2947 SCIP*const scip, /**< SCIP data structure */ 2948 SCIP_CONS**const conss, /**< constraint set */ 2949 int const nconss, /**< number of constraints in constraint set */ 2950 SCIP_CONS**const usefulconss, /**< storage for created constraints */ 2951 int*const nusefulconss, /**< pointer to store number of useful created constraints */ 2952 int*const nfixedvars, /**< pointer to count number of deleted variables */ 2953 int*const ndelconss, /**< pointer to count number of deleted constraints */ 2954 int*const nchgcoefs, /**< pointer to count number of deleted coefficients */ 2955 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */ 2956 ) 2957 { 2958 SCIP_CONS* cons; 2959 SCIP_CONSDATA* consdata; 2960 SCIP_Bool addcut; 2961 SCIP_Bool mustcheck; 2962 int nlocaladdconss = 0; 2963 int c; 2964 2965 assert(scip != NULL); 2966 assert(conss != NULL || nconss == 0); 2967 assert(usefulconss != NULL); 2968 assert(nusefulconss != NULL); 2969 assert(nfixedvars != NULL); 2970 assert(ndelconss != NULL); 2971 assert(nchgcoefs != NULL); 2972 assert(cutoff != NULL); 2973 2974 if( nconss == 0 ) 2975 return SCIP_OKAY; 2976 2977 assert(conss != NULL); 2978 2979 for( c = nconss - 1; c >= 0; --c ) 2980 { 2981 cons = conss[c]; 2982 2983 /* we only want to consider constraints with either active or negated of active variables, applyfixings removes 2984 * aggregated and fixed variables to zero, processFixings removes fixings to one but no aggregation 2985 * 2986 * @todo: maybe write a new method for deleting aggregations and all fixings 2987 */ 2988 SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) ); 2989 if( *cutoff ) 2990 return SCIP_OKAY; 2991 2992 if( SCIPconsIsDeleted(cons) ) 2993 { 2994 /* reset nlocaladdconss and continue */ 2995 nlocaladdconss = 0; 2996 continue; 2997 } 2998 assert(nlocaladdconss == 0); 2999 3000 SCIP_CALL( processFixings(scip, cons, cutoff, nfixedvars, &addcut, &mustcheck) ); 3001 if( *cutoff ) 3002 return SCIP_OKAY; 3003 3004 consdata = SCIPconsGetData(cons); 3005 assert(consdata != NULL); 3006 3007 /* we only want to consider merged constraints */ 3008 SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, cutoff) ); 3009 if( *cutoff ) 3010 return SCIP_OKAY; 3011 3012 if( SCIPconsIsModifiable(cons) || !SCIPconsIsActive(cons) ) 3013 continue; 3014 3015 assert(consdata->nfixedones == 0); 3016 3017 if( consdata->nvars == 0 ) 3018 continue; 3019 3020 /* @todo: check for covering constraints with only two variables which are equal to a packing constraint with 3021 * negated variables */ 3022 if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 3023 { 3024 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/ 3025 3026 usefulconss[*nusefulconss] = cons; 3027 ++(*nusefulconss); 3028 } 3029 } 3030 3031 return SCIP_OKAY; /*lint !e438*/ 3032 } 3033 3034 /** creating all necessary data in array structure, collect all clique constraint variables and occurrences, 3035 * @note works only with merged and active not set-covering constraints 3036 */ 3037 static 3038 SCIP_RETCODE collectCliqueData( 3039 SCIP*const scip, /**< SCIP data structure */ 3040 SCIP_CONS**const usefulconss, /**< clique constraints */ 3041 int const nusefulconss, /**< number of clique constraints */ 3042 SCIP_VAR**const usefulvars, /**< storage for all found variables */ 3043 int*const nusefulvars, /**< pointer to store number of added variables */ 3044 SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */ 3045 int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */ 3046 int*const maxnvarconsidx, /**< storage for the maximal number of occurrences of a variable */ 3047 int**const varconsidxs, /**< storage for constraint indices in which the corresponding variable exists */ 3048 int*const maxnvars /**< pointer to store maximal number of variables of a constraint */ 3049 ) 3050 { 3051 SCIP_CONS* cons; 3052 SCIP_CONSDATA* consdata; 3053 int varindex; 3054 int c; 3055 int v; 3056 3057 assert(scip != NULL); 3058 assert(usefulconss != NULL || nusefulconss == 0); 3059 assert(usefulvars != NULL); 3060 assert(nusefulvars != NULL); 3061 assert(vartoindex != NULL); 3062 assert(varnconss != NULL); 3063 assert(maxnvarconsidx != NULL); 3064 assert(varconsidxs != NULL); 3065 assert(maxnvars != NULL); 3066 3067 if( nusefulconss == 0 ) 3068 return SCIP_OKAY; 3069 3070 assert(usefulconss != NULL); 3071 3072 for( c = nusefulconss - 1; c >= 0; --c ) 3073 { 3074 cons = usefulconss[c]; 3075 3076 assert(SCIPconsIsActive(cons)); 3077 3078 consdata = SCIPconsGetData(cons); 3079 assert(consdata != NULL); 3080 3081 /* here we should have no covering constraints anymore and the constraint data should be merged */ 3082 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/ 3083 assert(consdata->merged); 3084 3085 /* save maximal number of vars */ 3086 if( consdata->nvars > *maxnvars ) 3087 *maxnvars = consdata->nvars; 3088 3089 /* adding variables and information about occurrences to local data structure */ 3090 for( v = consdata->nvars - 1; v >= 0; --v ) 3091 { 3092 SCIP_VAR* var; 3093 3094 var = consdata->vars[v]; 3095 assert(var != NULL); 3096 3097 /* don't remember fixed vars */ 3098 if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 ) 3099 continue; 3100 3101 /* only collect active or negated active variables */ 3102 assert(SCIPvarIsActive(var) || (SCIPvarIsNegated(var) && SCIPvarIsActive(SCIPvarGetNegationVar(var)))); 3103 3104 if( !SCIPhashmapExists(vartoindex, (void*) var) ) 3105 { 3106 SCIP_VAR* tmpvar; 3107 3108 usefulvars[*nusefulvars] = var; 3109 ++(*nusefulvars); 3110 varindex = *nusefulvars; 3111 SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) var, varindex) ); 3112 3113 /* get the maximal number of occurrences of this variable, if this variables */ 3114 tmpvar = SCIPvarIsNegated(var) ? SCIPvarGetNegatedVar(var) : var; 3115 maxnvarconsidx[varindex] = SCIPvarGetNLocksDownType(tmpvar, SCIP_LOCKTYPE_MODEL) 3116 + SCIPvarGetNLocksUpType(tmpvar, SCIP_LOCKTYPE_MODEL); 3117 SCIP_CALL( SCIPallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/ 3118 } 3119 else 3120 { 3121 assert(SCIPhashmapExists(vartoindex, (void*) var)); 3122 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var); 3123 } 3124 3125 /* the number of occurrences of a variable is not limited by the locks (so maybe we have to increase memory), 3126 * because for examples converted cuts are not check and therefore they have no locks on their variables */ 3127 if( varnconss[varindex] == maxnvarconsidx[varindex] ) 3128 { 3129 maxnvarconsidx[varindex] = SCIPcalcMemGrowSize(scip, maxnvarconsidx[varindex] + 1); 3130 SCIP_CALL( SCIPreallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/ 3131 } 3132 3133 assert(varnconss[varindex] < maxnvarconsidx[varindex]); 3134 /* add the constraint number to the variable list */ 3135 varconsidxs[varindex][varnconss[varindex]] = c; 3136 /* increase number of occurrences for variables */ 3137 ++(varnconss[varindex]); 3138 } 3139 } /* data structure created */ 3140 3141 return SCIP_OKAY; 3142 } 3143 3144 /** correct clique data due to an aggregation */ 3145 static 3146 void deleteCliqueDataEntry( 3147 SCIP_VAR*const var, /**< variable which appears less */ 3148 int const considx, /**< constraint index which to remove */ 3149 SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */ 3150 int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */ 3151 int**const varconsidxs /**< storage for constraint indices in which the corresponding variable exists */ 3152 ) 3153 { 3154 int varindex; 3155 int i; 3156 #ifndef NDEBUG 3157 SCIP_Bool found = FALSE; 3158 #endif 3159 3160 assert(var != NULL); 3161 assert(SCIPvarGetLbLocal(var) < 0.5 && SCIPvarGetUbLocal(var) > 0.5); 3162 assert(considx >= 0); 3163 assert(vartoindex != NULL); 3164 assert(varnconss != NULL); 3165 assert(varconsidxs != NULL); 3166 3167 assert(SCIPhashmapExists(vartoindex, (void*) var)); 3168 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var); 3169 3170 /* remove entry of variable at the given position */ 3171 for( i = 0; i < varnconss[varindex]; ++i ) 3172 { 3173 if( varconsidxs[varindex][i] == considx ) 3174 { 3175 varconsidxs[varindex][i] = varconsidxs[varindex][varnconss[varindex] - 1]; 3176 #ifndef NDEBUG 3177 found = TRUE; 3178 #endif 3179 --(varnconss[varindex]); 3180 break; 3181 } 3182 } 3183 assert(found); 3184 } 3185 3186 /* correct local data structure, add constraint entry to variable data */ 3187 static 3188 SCIP_RETCODE addCliqueDataEntry( 3189 SCIP*const scip, /**< SCIP data structure */ 3190 SCIP_VAR*const addvar, /**< variable which was added */ 3191 int const considx, /**< constraint index which to add */ 3192 SCIP_Bool const maybenew, /**< could be a new variables, a negated of an already existing */ 3193 SCIP_VAR**const usefulvars, /**< storage for all found variables */ 3194 int*const nusefulvars, /**< pointer to store number of added variables */ 3195 SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */ 3196 int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */ 3197 int*const maxnvarconsidx, /**< storage for the maximal number of occurrences of a variable */ 3198 int**const varconsidxs /**< storage for constraint indices in which the corresponding variable exists */ 3199 ) 3200 { 3201 int varindex; 3202 3203 assert(scip != NULL); 3204 assert(addvar != NULL); 3205 assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5); 3206 assert(usefulvars != NULL); 3207 assert(nusefulvars != NULL); 3208 assert(vartoindex != NULL); 3209 assert(varnconss != NULL); 3210 assert(maxnvarconsidx != NULL); 3211 assert(varconsidxs != NULL); 3212 3213 /* we add the variable to the hashmap if its new */ 3214 if( maybenew && !SCIPhashmapExists(vartoindex, (void*) addvar) ) 3215 { 3216 assert(SCIPvarIsActive(addvar) || SCIPvarIsNegated(addvar)); 3217 assert(SCIPvarGetNegatedVar(addvar) != NULL && SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(addvar))); 3218 3219 /* @note because we can only have created a negated variable, and we already allocated enough memory for 3220 * all (even not existing) negated variables the usefulvars array should be big enough 3221 */ 3222 SCIPsortedvecInsertDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, addvar, nusefulvars, NULL); 3223 varindex = *nusefulvars; 3224 SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) addvar, varindex) ); 3225 3226 assert(varconsidxs[varindex] == NULL); 3227 3228 maxnvarconsidx[varindex] = 1; 3229 SCIP_CALL( SCIPallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/ 3230 varnconss[varindex] = 0; 3231 } 3232 else 3233 { 3234 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) addvar); 3235 3236 /* grow the needed memory if we added a variable */ 3237 if( varnconss[varindex] == maxnvarconsidx[varindex] ) 3238 { 3239 maxnvarconsidx[varindex] = SCIPcalcMemGrowSize(scip, maxnvarconsidx[varindex] + 1); 3240 SCIP_CALL( SCIPreallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/ 3241 } 3242 } 3243 assert(varnconss[varindex] < maxnvarconsidx[varindex]); 3244 varconsidxs[varindex][varnconss[varindex]] = considx; 3245 3246 /* increase number of occurrences for variables */ 3247 ++(varnconss[varindex]); 3248 3249 return SCIP_OKAY; 3250 } 3251 3252 3253 /** check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if 3254 * possible 3255 */ 3256 static 3257 SCIP_RETCODE presolvePropagateCons( 3258 SCIP*const scip, /**< SCIP data structure */ 3259 SCIP_CONS*const cons, /**< constraint */ 3260 SCIP_Bool const aggregate, /**< try to aggregate if possible */ 3261 SCIP_VAR** undoneaggrvars, /**< array to store aggregation variables, if aggregation is not performed 3262 * yet; both variables are standing next to each other; or NULL if 3263 * aggregate == TRUE 3264 */ 3265 SCIP_Bool* undoneaggrtypes, /**< array to store aggregation type, if aggregation is not performed yet; 3266 * type FALSE means the aggregation is of the form x + y = 1; type TRUE means 3267 * the aggregation is of the form x = y; or NULL if aggregate == TRUE 3268 */ 3269 int*const naggregations, /**< pointer to store number of aggregations which are not yet performed; 3270 * or NULL if aggregate == TRUE 3271 */ 3272 int*const saggregations, /**< pointer to store size of the array for aggregation type and two times 3273 * the value is the size of the array for the aggregation variables which 3274 * are not yet performed; or NULL if aggregate == TRUE 3275 */ 3276 int*const nfixedvars, /**< pointer to count number of deleted variables */ 3277 int*const naggrvars, /**< pointer to count number of aggregated variables */ 3278 int*const ndelconss, /**< pointer to count number of deleted constraints */ 3279 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */ 3280 ) 3281 { 3282 SCIP_CONSDATA* consdata; 3283 SCIP_VAR** vars; 3284 int nvars; 3285 int v; 3286 SCIP_Bool fixed; 3287 3288 assert(scip != NULL); 3289 assert(cons != NULL); 3290 assert(nfixedvars != NULL); 3291 assert(naggrvars != NULL); 3292 assert(ndelconss != NULL); 3293 assert(cutoff != NULL); 3294 3295 if( !SCIPconsIsActive(cons) ) 3296 return SCIP_OKAY; 3297 3298 consdata = SCIPconsGetData(cons); 3299 assert(consdata != NULL); 3300 3301 if( consdata->presolpropagated ) 3302 return SCIP_OKAY; 3303 3304 consdata->presolpropagated = TRUE; 3305 3306 vars = consdata->vars; 3307 nvars = consdata->nvars; 3308 3309 /* no variables left */ 3310 if( nvars == 0 && !SCIPconsIsModifiable(cons) ) 3311 { 3312 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 3313 { 3314 SCIPdebugMsg(scip, "empty set-partition/-covering constraint <%s> found -> cutoff\n", SCIPconsGetName(cons)); 3315 *cutoff = TRUE; 3316 3317 return SCIP_OKAY; 3318 } 3319 else 3320 { 3321 assert(consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/ 3322 3323 /* delete constraint */ 3324 SCIPdebugMsg(scip, " -> deleting constraint <%s>, no variables left\n", SCIPconsGetName(cons)); 3325 SCIP_CALL( SCIPdelCons(scip, cons) ); 3326 ++(*ndelconss); 3327 3328 return SCIP_OKAY; 3329 } 3330 } 3331 3332 /* more then two variables are fixed */ 3333 if( consdata->nfixedones > 1 ) 3334 { 3335 /* at least two variables are fixed to 1: 3336 * - a set covering constraint is feasible anyway and can be deleted 3337 * - a set partitioning or packing constraint is infeasible 3338 */ 3339 if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 3340 { 3341 /* delete constraint */ 3342 SCIPdebugMsg(scip, " -> deleting set-covering constraint <%s>, at least two variables are fixed to 1\n", SCIPconsGetName(cons)); 3343 SCIP_CALL( SCIPdelCons(scip, cons) ); 3344 ++(*ndelconss); 3345 3346 return SCIP_OKAY; 3347 } 3348 3349 SCIPdebugMsg(scip, "set partitioning / packing constraint <%s> is infeasible, %d variables fixed to one\n", SCIPconsGetName(cons), consdata->nfixedones); 3350 *cutoff = TRUE; 3351 3352 return SCIP_OKAY; 3353 } 3354 3355 if( consdata->nfixedones == 1 ) 3356 { 3357 /* exactly one variable is fixed to 1: 3358 * - a set covering constraint is feasible anyway and can be disabled 3359 * - all other variables in a set partitioning or packing constraint must be zero 3360 */ 3361 if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING && consdata->nfixedzeros < nvars - 1 ) /*lint !e641*/ 3362 { 3363 assert(vars != NULL); 3364 3365 for( v = nvars - 1; v >= 0; --v ) 3366 { 3367 if( SCIPvarGetLbLocal(vars[v]) + 0.5 < SCIPvarGetUbLocal(vars[v]) ) 3368 { 3369 SCIPdebugMsg(scip, "trying to fix <%s> to 0 due to at least one variable is already fixed to 1\n", SCIPvarGetName(vars[v])); 3370 3371 /* fix all remaining variables to zero, constraint is already feasible or infeasible */ 3372 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) ); 3373 if( *cutoff ) 3374 { 3375 SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n", 3376 SCIPconsGetName(cons), SCIPvarGetName(vars[v])); 3377 3378 return SCIP_OKAY; 3379 } 3380 3381 assert(fixed); 3382 ++(*nfixedvars); 3383 } 3384 } 3385 } 3386 3387 if( !SCIPconsIsModifiable(cons) || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 3388 { 3389 /* delete constraint */ 3390 SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons)); 3391 assert(SCIPconsIsActive(cons)); 3392 SCIP_CALL( SCIPdelCons(scip, cons) ); 3393 ++(*ndelconss); 3394 } 3395 3396 return SCIP_OKAY; 3397 } 3398 3399 /* other propagations can only be done on not modifiable constraints */ 3400 if( SCIPconsIsModifiable(cons) ) 3401 return SCIP_OKAY; 3402 3403 assert(vars != NULL); 3404 3405 /* all variables were fixed to zero then either delete the constraint or stop with infeasibility */ 3406 if( consdata->nfixedzeros == nvars ) 3407 { 3408 assert(consdata->nfixedones == 0); 3409 3410 /* all variables are fixed to zero: 3411 * - a set packing constraint is feasible anyway and can be deleted 3412 * - a set partitioning or covering constraint is infeasible, and so is the whole problem 3413 */ 3414 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 3415 { 3416 SCIPdebugMsg(scip, "set partitioning / covering constraint <%s> is infeasible\n", SCIPconsGetName(cons)); 3417 *cutoff = TRUE; 3418 3419 return SCIP_OKAY; 3420 } 3421 3422 /* delete constraint */ 3423 SCIPdebugMsg(scip, " -> deleting set-packing constraint <%s>, all variables are fixed to zero\n", SCIPconsGetName(cons)); 3424 assert(SCIPconsIsActive(cons)); 3425 SCIP_CALL( SCIPdelCons(scip, cons) ); 3426 ++(*ndelconss); 3427 3428 return SCIP_OKAY; 3429 } 3430 3431 /* all but one variable were fixed to zero then delete the constraint and for setpartition fix the remaining variable to 1 */ 3432 if( consdata->nfixedzeros + 1 == nvars ) 3433 { 3434 assert(consdata->nfixedones == 0); 3435 3436 /* all variables except one are fixed to zero: 3437 * - a set packing constraint is feasible anyway, and can be deleted 3438 * - a set partitioning or covering constraint is feasible and can be deleted after the 3439 * remaining variable is fixed to one 3440 */ 3441 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 3442 { 3443 fixed = FALSE; 3444 for( v = nvars - 1; v >= 0; --v ) 3445 { 3446 assert(SCIPvarGetLbLocal(vars[v]) < 0.5); 3447 if( SCIPvarGetUbLocal(vars[v]) > 0.5 ) 3448 { 3449 SCIPdebugMsg(scip, "trying to fix <%s> to 1 due to it's the last unfixed variable is the set-partitioning/covering constraint\n", SCIPvarGetName(vars[v])); 3450 3451 /* fix the remaining set partition variable */ 3452 SCIP_CALL( SCIPfixVar(scip, vars[v], 1.0, cutoff, &fixed) ); 3453 if( *cutoff ) 3454 { 3455 SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 1\n", 3456 SCIPconsGetName(cons), SCIPvarGetName(vars[v])); 3457 3458 return SCIP_OKAY; 3459 } 3460 3461 assert(fixed); 3462 ++(*nfixedvars); 3463 break; 3464 } 3465 } 3466 assert(fixed); 3467 } 3468 3469 /* delete constraint */ 3470 SCIPdebugMsg(scip, " -> deleting constraint <%s>, all %svariables are fixed\n", SCIPconsGetName(cons), consdata->setppctype == (int) SCIP_SETPPCTYPE_PACKING ? "but one " : ""); 3471 assert(SCIPconsIsActive(cons)); 3472 SCIP_CALL( SCIPdelCons(scip, cons) ); 3473 ++(*ndelconss); 3474 3475 return SCIP_OKAY; 3476 } 3477 3478 /* all but two variable were fixed to zero in a setpartitioning constraint then delete the constraint and 3479 * aggregate the remaining two variables 3480 */ 3481 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedzeros + 2 == nvars ) /*lint !e641*/ 3482 { 3483 SCIP_VAR* var; 3484 3485 var = NULL; 3486 for( v = nvars - 1; v >= 0; --v ) 3487 { 3488 assert(SCIPvarGetLbLocal(vars[v]) < 0.5); 3489 3490 if( SCIPvarGetUbLocal(vars[v]) > 0.5 ) 3491 { 3492 if( var == NULL ) 3493 var = vars[v]; 3494 else 3495 { 3496 SCIP_Bool redundant; 3497 SCIP_Bool aggregated; 3498 #ifdef VARUSES 3499 SCIP_CONSHDLR* conshdlr; 3500 SCIP_CONSHDLRDATA* conshdlrdata; 3501 3502 /* get event handler and event handler data */ 3503 conshdlr = SCIPconsGetHdlr(cons); 3504 assert(conshdlr != NULL); 3505 conshdlrdata = SCIPconshdlrGetData(conshdlr); 3506 assert(conshdlrdata != NULL); 3507 #endif 3508 if( aggregate ) 3509 { 3510 SCIPdebugMsg(scip, "trying to aggregate <%s> and <%s> due to they are the last two unfixed variables in the set partitionning constraint <%s>\n", SCIPvarGetName(var), SCIPvarGetName(vars[v]), SCIPconsGetName(cons)); 3511 3512 #ifdef VARUSES 3513 /* in order to not mess up the variable usage counting, we have to decrease usage counting, aggregate, 3514 * and increase usage counting again 3515 */ 3516 SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var) ); 3517 SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, vars[v]) ); 3518 #endif 3519 3520 /* aggregate last remaining variables in the set partitioning constraint */ 3521 SCIP_CALL( SCIPaggregateVars(scip, var, vars[v], 1.0, 1.0, 1.0, cutoff, &redundant, &aggregated) ); 3522 if( *cutoff ) 3523 { 3524 SCIPdebugMsg(scip, "set partitioning constraint <%s>: aggregate <%s> + <%s> == 1\n", 3525 SCIPconsGetName(cons), SCIPvarGetName(var), SCIPvarGetName(vars[v])); 3526 3527 return SCIP_OKAY; 3528 } 3529 3530 #ifdef VARUSES 3531 /* increase variable usage counting again */ 3532 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var) ); 3533 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, vars[v]) ); 3534 #endif 3535 3536 if( aggregated ) 3537 ++(*naggrvars); 3538 3539 if( redundant ) 3540 { 3541 /* delete constraint */ 3542 SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons)); 3543 assert(SCIPconsIsActive(cons)); 3544 SCIP_CALL( SCIPdelCons(scip, cons) ); 3545 ++(*ndelconss); 3546 } 3547 } 3548 else 3549 { 3550 assert(undoneaggrvars != NULL); 3551 assert(undoneaggrtypes != NULL); 3552 assert(naggregations != NULL); 3553 assert(saggregations != NULL); 3554 3555 SCIPdebugMsg(scip, "memorize the aggregation of <%s> + <%s> = 1, because they are the last two unfixed variable in the set partitioning constraints <%s>\n", SCIPvarGetName(var), SCIPvarGetName(vars[v]), SCIPconsGetName(cons)); 3556 3557 /* resize the aggregation arrays if necessary */ 3558 if( *saggregations == *naggregations ) 3559 { 3560 *saggregations = SCIPcalcMemGrowSize(scip, *naggregations + 1); 3561 assert(*saggregations > *naggregations); 3562 SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrtypes, *saggregations) ); 3563 SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrvars, 2 * (*saggregations)) ); 3564 3565 /* clear the aggregation type array to set the default to the aggregation of the form x + y = 1 */ 3566 BMSclearMemoryArray(&(undoneaggrtypes[*naggregations]), *saggregations - *naggregations); /*lint !e866*/ 3567 } 3568 3569 /* memorize aggregation variables*/ 3570 assert(undoneaggrtypes[*naggregations] == FALSE); 3571 undoneaggrvars[2 * (*naggregations)] = var; 3572 undoneaggrvars[2 * (*naggregations) + 1] = vars[v]; 3573 ++(*naggregations); 3574 3575 if( !SCIPdoNotAggr(scip) ) 3576 { 3577 /* delete constraint */ 3578 SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons)); 3579 assert(SCIPconsIsActive(cons)); 3580 SCIP_CALL( SCIPdelCons(scip, cons) ); 3581 ++(*ndelconss); 3582 } 3583 } 3584 3585 return SCIP_OKAY; 3586 } 3587 } 3588 } 3589 /* we should never be here, because the last to unfixed variables should have been either aggregated or a cutoff 3590 * should be applied 3591 */ 3592 assert(FALSE); /*lint !e506*/ 3593 } 3594 3595 return SCIP_OKAY; 3596 } 3597 3598 /** check for overlapping constraint */ 3599 static 3600 SCIP_RETCODE checkForOverlapping( 3601 SCIP*const scip, /**< SCIP data structure */ 3602 SCIP_CONS*const cons, /**< constraint which may overlap */ 3603 int const considx, /**< constraint index to avoid checking against itself */ 3604 int const endidx, /**< end index to check against given constraint */ 3605 SCIP_CONS**const usefulconss, /**< clique constraints */ 3606 int const nusefulconss, /**< number of clique constraints */ 3607 SCIP_VAR**const usefulvars, /**< storage for all found variables */ 3608 int*const nusefulvars, /**< pointer to store number of added variables */ 3609 SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */ 3610 int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */ 3611 int*const maxnvarconsidx, /**< storage for the maximal number of occurrences of a variable */ 3612 int**const varconsidxs, /**< storage for constraint indices in which the corresponding variable exists */ 3613 int*const countofoverlapping, /**< the amount of variables of cons which overlap in all other constraint */ 3614 SCIP_Bool const shrinking, /**< try to replace some variables with one variable */ 3615 SCIP_Bool*const chgcons, /**< pointer to store if the given constraint was changed, due to 3616 * added/deleted variables 3617 */ 3618 SCIP_VAR** undoneaggrvars, /**< array to store aggregation variables, if aggregation is not performed 3619 * yet; both variables are standing next to each other; 3620 */ 3621 SCIP_Bool* undoneaggrtypes, /**< array to store aggregation type, if aggregation is not performed yet; 3622 * type FALSE means the aggregation is of the form x + y = 1; type TRUE means 3623 * the aggregation is of the form x = y; 3624 */ 3625 int*const naggregations, /**< pointer to store number of aggregations which are not yet performed; */ 3626 int*const saggregations, /**< pointer to store size of the array for aggregation type and two times 3627 * the value is the size of the array for the aggregation variables which 3628 * are not yet performed; 3629 */ 3630 int*const nfixedvars, /**< pointer to count number of deleted variables */ 3631 int*const naggrvars, /**< pointer to count number of aggregated variables */ 3632 int*const nchgcoefs, /**< pointer to count number of changed coefficients */ 3633 int*const ndelconss, /**< pointer to count number of deleted constraints */ 3634 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */ 3635 ) 3636 { 3637 SCIP_CONS* cons1; 3638 SCIP_CONSDATA* consdata1; 3639 SCIP_CONSDATA* consdata; 3640 SCIP_VAR** vars; 3641 SCIP_VAR** vars1; 3642 SCIP_VAR* var; 3643 SCIP_VAR* var1; 3644 SCIP_Bool fixed; 3645 SCIP_Bool overlapdestroyed; 3646 int nvars; 3647 int nvars1; 3648 int oldnfixedzeros; 3649 int c; 3650 int v; 3651 int v1; 3652 #ifndef NDEBUG 3653 int oldnaggrvars; 3654 #endif 3655 3656 assert(scip != NULL); 3657 assert(cons != NULL); 3658 assert(usefulconss != NULL && nusefulconss > 0); 3659 assert(0 <= considx && considx < nusefulconss); 3660 assert(usefulconss[considx] == cons); 3661 assert(0 <= endidx && endidx <= nusefulconss); 3662 assert(countofoverlapping != NULL); 3663 assert(chgcons != NULL); 3664 assert(undoneaggrvars != NULL); 3665 assert(undoneaggrtypes != NULL); 3666 assert(naggregations != NULL); 3667 assert(saggregations != NULL); 3668 assert(nfixedvars != NULL); 3669 assert(naggrvars != NULL); 3670 assert(nchgcoefs != NULL); 3671 assert(ndelconss != NULL); 3672 assert(cutoff != NULL); 3673 3674 if( !SCIPconsIsActive(cons) ) 3675 return SCIP_OKAY; 3676 3677 consdata = SCIPconsGetData(cons); 3678 assert(consdata != NULL); 3679 3680 nvars = consdata->nvars; 3681 3682 if( nvars == 0 ) 3683 return SCIP_OKAY; 3684 3685 vars = consdata->vars; 3686 assert(vars != NULL); 3687 3688 oldnfixedzeros = consdata->nfixedzeros; 3689 overlapdestroyed = FALSE; 3690 3691 /* first check for redundancy for all unprocessed constraints with cons */ 3692 for( c = endidx - 1; c >= 0; --c ) 3693 { 3694 cons1 = usefulconss[c]; 3695 3696 if( !SCIPconsIsActive(cons1) ) 3697 continue; 3698 3699 /* avoid checking constraint against itself */ 3700 if( considx == c ) 3701 continue; 3702 3703 assert(usefulconss[c] != cons); 3704 3705 #ifndef NDEBUG 3706 oldnaggrvars = *naggrvars; 3707 #endif 3708 3709 /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if 3710 * possible 3711 */ 3712 SCIP_CALL( presolvePropagateCons(scip, cons1, FALSE, undoneaggrvars, undoneaggrtypes, naggregations, saggregations, nfixedvars, naggrvars, ndelconss, cutoff) ); 3713 3714 if( *cutoff ) 3715 return SCIP_OKAY; 3716 3717 /* we can't handle aggregated variables later on so we should have saved them for later */ 3718 assert(*naggrvars == oldnaggrvars); 3719 3720 if( !SCIPconsIsActive(cons1) ) 3721 continue; 3722 3723 consdata1 = SCIPconsGetData(cons1); 3724 assert(consdata1 != NULL); 3725 3726 nvars1 = consdata1->nvars; 3727 3728 if( nvars1 == 0 ) 3729 continue; 3730 3731 /* no more variables from cons as nvars1 can overlap */ 3732 assert(countofoverlapping[c] <= nvars1); 3733 3734 /* constraint should not be redundant or infeasible */ 3735 assert(consdata1->nfixedones == 0); 3736 3737 SCIPdebugMsg(scip, "constraint <%s> overlaps with constraint <%s> by %d variables\n", SCIPconsGetName(cons), SCIPconsGetName(cons1), countofoverlapping[c]); 3738 3739 /* cons1 includes cons */ 3740 if( !overlapdestroyed && countofoverlapping[c] == nvars - consdata->nfixedzeros ) 3741 { 3742 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/ 3743 { 3744 if( nvars - consdata->nfixedzeros < nvars1 ) 3745 { 3746 #ifndef NDEBUG 3747 SCIP_Bool negated0; 3748 SCIP_Bool negated1; 3749 #endif 3750 3751 /* both constraints should stay merged */ 3752 assert(consdata->merged); 3753 assert(consdata1->merged); 3754 3755 vars1 = consdata1->vars; 3756 assert(vars1 != NULL); 3757 3758 /* sorting array after indices of variables, negated and active counterparts would stand side by side */ 3759 SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1); 3760 /* standard setppc-sorting now lost */ 3761 consdata1->sorted = FALSE; 3762 3763 /* iterate over the both cliques variables the "same" time */ 3764 for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; ) 3765 { 3766 if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 ) 3767 { 3768 --v1; 3769 continue; 3770 } 3771 if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 ) 3772 { 3773 --v; 3774 continue; 3775 } 3776 3777 /* all variables inside the second clique constraint should be either active or negated of an active one */ 3778 assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1])))); 3779 3780 /* get not negated variable and clique value in cons */ 3781 if( SCIPvarGetStatus(vars[v]) != SCIP_VARSTATUS_NEGATED ) 3782 { 3783 var = vars[v]; 3784 #ifndef NDEBUG 3785 negated0 = FALSE; 3786 #endif 3787 } 3788 else 3789 { 3790 var = SCIPvarGetNegationVar(vars[v]); 3791 #ifndef NDEBUG 3792 negated0 = TRUE; 3793 #endif 3794 } 3795 3796 /* get active variable and clique value of next variable */ 3797 if( SCIPvarIsActive(vars1[v1]) ) 3798 { 3799 var1 = vars1[v1]; 3800 #ifndef NDEBUG 3801 negated1 = FALSE; 3802 #endif 3803 } 3804 else 3805 { 3806 assert(SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))); 3807 var1 = SCIPvarGetNegationVar(vars1[v1]); 3808 #ifndef NDEBUG 3809 negated1 = TRUE; 3810 #endif 3811 } 3812 3813 /* variable index in the constraint smaller than the other one, so go to the next variable in cons */ 3814 if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) ) 3815 --v; 3816 /* variable index in the constraint is greater than the other one, so fix this variable */ 3817 else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) ) 3818 { 3819 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(vars1[v1])); 3820 3821 /* fix all variables except the one which has the negated var in the clique to zero */ 3822 SCIP_CALL( SCIPfixVar(scip, vars1[v1], 0.0, cutoff, &fixed) ); 3823 if( *cutoff ) 3824 { 3825 SCIPdebugMsg(scip, "fixing led to cutoff\n"); 3826 3827 return SCIP_OKAY; 3828 } 3829 3830 assert(fixed); 3831 ++(*nfixedvars); 3832 --v1; 3833 } 3834 else 3835 { 3836 /* because the constraint's are merged it is not possible that one constraint contains a negated 3837 * variable of another and because all variables in cons are in cons1 this should be really the 3838 * same variable here; so we can decrease v and v1 3839 */ 3840 assert(negated0 == negated1); 3841 3842 --v; 3843 --v1; 3844 } 3845 } 3846 /* maybe we ended because of cons(v reached -1) so try to add rest of cons1 to cons */ 3847 for( ; v1 >= 0; --v1) 3848 { 3849 if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 ) 3850 continue; 3851 3852 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(vars1[v1])); 3853 3854 /* fix all variables except the one which has the negated var in the clique to zero */ 3855 SCIP_CALL( SCIPfixVar(scip, vars1[v1], 0.0, cutoff, &fixed) ); 3856 if( *cutoff ) 3857 { 3858 SCIPdebugMsg(scip, "fixing led to cutoff\n"); 3859 3860 return SCIP_OKAY; 3861 } 3862 3863 assert(fixed); 3864 ++(*nfixedvars); 3865 } 3866 } 3867 3868 /* if caused by all fixings now this set partitioning constraint doesn't have any variable which was 3869 * fixed to one, it's infeasible */ 3870 if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nfixedzeros == nvars1 && consdata1->nfixedones != 1 ) /*lint !e641*/ 3871 { 3872 SCIPdebugMsg(scip, "all variables in the set-partitioning constraint <%s> are fixed to zero, this leads to a cutoff\n", SCIPconsGetName(cons1)); 3873 *cutoff = TRUE; 3874 3875 return SCIP_OKAY; 3876 } 3877 3878 assert(SCIPconsIsActive(cons1)); 3879 /* delete second constraint */ 3880 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it includes the setpartitioning constraint <%s> number <%d>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons), considx); 3881 3882 SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) ); 3883 SCIP_CALL( SCIPdelCons(scip, cons1) ); 3884 ++(*ndelconss); 3885 } 3886 /* could already be deleted because the constraint was included in another set partition constraint */ 3887 else if( SCIPconsIsActive(cons) ) 3888 { 3889 /* delete cons due to redundancy to cons1 */ 3890 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to inclusion in constraint <%s> number <%d>\n", SCIPconsGetName(cons), considx, SCIPconsGetName(cons1), c); 3891 3892 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons) ); 3893 SCIP_CALL( SCIPdelCons(scip, cons) ); 3894 ++(*ndelconss); 3895 } 3896 } 3897 /* cons includes cons1 3898 * 3899 * @note that zero fixations from above can only appear through a set-partitioning constraint, this means if 3900 * cons was the set-partitioning constraint only variables which are not in this constraint could be fixed 3901 * to zero, and this also means that the overlapping variables in this particular case are still active or 3902 * fixed to 1 3903 * later on it could be possible that even variables in cons are fixed to zero, which can lead to wrong 3904 * results when checking if countofoverlapping[c] + consdata1->nfixedzeros == nvars1, because a fixed 3905 * variable could be counted twice 3906 */ 3907 else if( (!overlapdestroyed && countofoverlapping[c] + consdata1->nfixedzeros == nvars1) || countofoverlapping[c] == nvars1 ) 3908 { 3909 /* even in deleted constraints we may fix unfixed variables */ 3910 if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/ 3911 { 3912 const int oldnfixedvars = *nfixedvars; 3913 #ifndef NDEBUG 3914 SCIP_Bool negated0; 3915 SCIP_Bool negated1; 3916 #endif 3917 /* both constraints should stay merged */ 3918 assert(consdata->merged); 3919 assert(consdata1->merged); 3920 3921 vars1 = consdata1->vars; 3922 3923 /* sorting array after indices of variables, negated and active counterparts would stand side by side */ 3924 SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1); 3925 /* standard setppc-sorting now lost */ 3926 consdata1->sorted = FALSE; 3927 3928 /* iterate over the both cliques variables the "same" time */ 3929 for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; ) 3930 { 3931 if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 ) 3932 { 3933 --v1; 3934 continue; 3935 } 3936 if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 ) 3937 { 3938 --v; 3939 continue; 3940 } 3941 3942 /* all variables inside the second clique constraint should be either active or negated of an active one */ 3943 assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1])))); 3944 /* all variables inside the first clique constraint should be either active or negated of an active one */ 3945 assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v])))); 3946 3947 /* get not negated variable and clique value in cons */ 3948 if( SCIPvarIsActive(vars[v]) ) 3949 { 3950 var = vars[v]; 3951 #ifndef NDEBUG 3952 negated0 = FALSE; 3953 #endif 3954 } 3955 else 3956 { 3957 assert(SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))); 3958 var = SCIPvarGetNegationVar(vars[v]); 3959 #ifndef NDEBUG 3960 negated0 = TRUE; 3961 #endif 3962 } 3963 3964 /* get active variable and clique value of next variable */ 3965 if( SCIPvarIsActive(vars1[v1]) ) 3966 { 3967 var1 = vars1[v1]; 3968 #ifndef NDEBUG 3969 negated1 = FALSE; 3970 #endif 3971 } 3972 else 3973 { 3974 assert(SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))); 3975 var1 = SCIPvarGetNegationVar(vars1[v1]); 3976 #ifndef NDEBUG 3977 negated1 = TRUE; 3978 #endif 3979 } 3980 3981 /* variable index in the constraint smaller than the other one, so go to the next variable in cons */ 3982 if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) ) 3983 { 3984 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(var)); 3985 3986 /* fix all variables except the one which has the negated var in the clique to zero */ 3987 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) ); 3988 if( *cutoff ) 3989 { 3990 SCIPdebugMsg(scip, "fixing led to cutoff\n"); 3991 3992 return SCIP_OKAY; 3993 } 3994 3995 assert(fixed); 3996 ++(*nfixedvars); 3997 3998 --v; 3999 } 4000 /* variable index in the constraint is greater than the other one, so fix this variable */ 4001 else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) ) 4002 --v1; 4003 else 4004 { 4005 /* because the constraint's are merged it is not possible that one constraint contains a negated 4006 * variable of another and because all variables in cons1 are in cons this should be really the same 4007 * variable here; so we can decrease v and v1 4008 */ 4009 assert(negated0 == negated1); 4010 4011 --v; 4012 --v1; 4013 } 4014 } 4015 4016 /* maybe we ended because of cons1(v1 reached -1) so try to add rest of cons to cons1 */ 4017 for( ; v >= 0; --v) 4018 { 4019 if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 ) 4020 continue; 4021 4022 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(vars[v])); 4023 4024 /* fix all variables except the one which has the negated var in the clique to zero */ 4025 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) ); 4026 if( *cutoff ) 4027 { 4028 SCIPdebugMsg(scip, "fixing led to cutoff\n"); 4029 4030 return SCIP_OKAY; 4031 } 4032 4033 assert(fixed); 4034 ++(*nfixedvars); 4035 } 4036 4037 /* if caused by all fixings now this set partitioning constraint doesn't have any variable which was 4038 * fixed to one, it's infeasible */ 4039 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedzeros == nvars && consdata->nfixedones != 1 ) /*lint !e641*/ 4040 { 4041 SCIPdebugMsg(scip, "all variables in the set-partitioning constraint <%s> are fixed to zero, this leads to a cutoff\n", SCIPconsGetName(cons1)); 4042 *cutoff = TRUE; 4043 4044 return SCIP_OKAY; 4045 } 4046 4047 /* could already be deleted because the constraint was included in another set partition constraint */ 4048 if( SCIPconsIsActive(cons) ) 4049 { 4050 /* delete cons because it include another set partitioning constraint */ 4051 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it includes the setpartitioning constraint <%s> number <%d>\n", SCIPconsGetName(cons), considx, SCIPconsGetName(cons1), c); 4052 assert(SCIPconsIsActive(cons)); 4053 4054 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons) ); 4055 SCIP_CALL( SCIPdelCons(scip, cons) ); 4056 ++(*ndelconss); 4057 } 4058 4059 /* due to fixings in cons0 mark overlapping invalid for checking with fixedzero variables together */ 4060 if( oldnfixedvars < *nfixedvars ) 4061 overlapdestroyed = TRUE; 4062 } 4063 else 4064 { 4065 assert(consdata1->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/ 4066 4067 /* delete cons1 due to redundancy to cons */ 4068 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to inclusion in constraint <%s> number <%d>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons), considx); 4069 assert(SCIPconsIsActive(cons1)); 4070 4071 SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) ); 4072 SCIP_CALL( SCIPdelCons(scip, cons1) ); 4073 ++(*ndelconss); 4074 } 4075 } 4076 /* if cons has only one unfixed variable which is not in cons1 and cons1 has one variable which does not appear in 4077 * cons and both constraints are setpartitioning constraints we might aggregate both not overlapping variables and 4078 * delete one constraint 4079 */ 4080 else if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1 && countofoverlapping[c] == nvars1 - 1 ) /*lint !e641*/ 4081 { 4082 SCIP_VAR* aggvar1; 4083 SCIP_VAR* aggvar2; 4084 SCIP_Bool negated0; 4085 SCIP_Bool negated1; 4086 4087 aggvar1 = NULL; 4088 aggvar2 = NULL; 4089 4090 /* both constraints should stay merged */ 4091 assert(consdata->merged); 4092 assert(consdata1->merged); 4093 4094 vars1 = consdata1->vars; 4095 4096 /* sorting array after indices of variables, negated and active counterparts would stand side by side */ 4097 SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1); 4098 /* standard setppc-sorting now lost */ 4099 consdata1->sorted = FALSE; 4100 4101 /* iterate over the both cliques variables the "same" time */ 4102 for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; ) 4103 { 4104 if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 ) 4105 { 4106 --v1; 4107 continue; 4108 } 4109 if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 ) 4110 { 4111 --v; 4112 continue; 4113 } 4114 4115 /* all variables inside the second clique constraint should be either active or negated of an active one */ 4116 assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1])))); 4117 /* all variables inside the first clique constraint should be either active or negated of an active one */ 4118 assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v])))); 4119 4120 /* get not negated variable and clique value in cons */ 4121 if( SCIPvarIsActive(vars[v]) ) 4122 { 4123 var = vars[v]; 4124 negated0 = FALSE; 4125 } 4126 else 4127 { 4128 assert(SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))); 4129 var = SCIPvarGetNegationVar(vars[v]); 4130 negated0 = TRUE; 4131 } 4132 4133 /* get active variable and clique value of next variable */ 4134 if( SCIPvarIsActive(vars1[v1]) ) 4135 { 4136 var1 = vars1[v1]; 4137 negated1 = FALSE; 4138 } 4139 else 4140 { 4141 assert(SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))); 4142 var1 = SCIPvarGetNegationVar(vars1[v1]); 4143 negated1 = TRUE; 4144 } 4145 4146 /* variable index in the constraint smaller than the other one, so go to the next variable in cons */ 4147 if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) ) 4148 { 4149 assert(aggvar1 == NULL); 4150 aggvar1 = vars[v]; 4151 4152 if( aggvar2 != NULL ) 4153 break; 4154 4155 --v; 4156 } 4157 /* variable index in the constraint is greater than the other one, so fix this variable */ 4158 else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) ) 4159 { 4160 assert(aggvar2 == NULL); 4161 aggvar2 = vars1[v1]; 4162 4163 if( aggvar1 != NULL ) 4164 break; 4165 4166 --v1; 4167 } 4168 else 4169 { 4170 /* because the constraint's are merged it is not possible that one constraint contains a negated variable 4171 * of another, but both variables in both constraints still can be negated to each other 4172 */ 4173 if( negated0 != negated1 ) 4174 { 4175 /* cons is except for one variable equal to cons1 and the unequal variable in cons is negated 4176 * to the one in cons1, so the problem is infeasible 4177 */ 4178 SCIPdebugMsg(scip, "two set-partitioning constraint <%s> and <%s> have only one variable not in common, but this variable <%s> appears in one constraint as the negated version as in the other constraint\n", SCIPconsGetName(cons), SCIPconsGetName(cons1), SCIPvarGetName(vars[v])); 4179 *cutoff = TRUE; 4180 4181 return SCIP_OKAY; 4182 } 4183 --v; 4184 --v1; 4185 } 4186 } 4187 4188 /* due to fixings, it is possible that there are no active variables left, we we did not recognize which variables we could aggregate */ 4189 if( aggvar1 == NULL && aggvar2 == NULL ) 4190 continue; 4191 4192 /* determine second aggregation var, if not yet done */ 4193 if( aggvar2 == NULL ) 4194 { 4195 for( ; v1 >= 0; --v1) 4196 { 4197 if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 ) 4198 continue; 4199 4200 aggvar2 = vars1[v1]; 4201 break; 4202 } 4203 } 4204 /* determine first aggregation var, if not yet done */ 4205 else if( aggvar1 == NULL ) 4206 { 4207 /* maybe we ended because of cons1(v1 reached -1) so find the aggvar1 in cons */ 4208 for( ; v >= 0; --v) 4209 { 4210 if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 ) 4211 continue; 4212 4213 aggvar1 = vars[v]; 4214 break; 4215 } 4216 } 4217 4218 /* due to fixings, it is possible that there are no active variables left, we we did not recognize which variables we could aggregate */ 4219 if( aggvar1 == NULL || aggvar2 == NULL ) 4220 continue; 4221 4222 SCIPdebugMsg(scip, "memorize the aggregation of <%s> == <%s>, because they are the last two variable which are different in these two set partitioning constraints <%s> <%s>\n", SCIPvarGetName(aggvar1), SCIPvarGetName(aggvar2), SCIPconsGetName(cons), SCIPconsGetName(cons1)); 4223 4224 /* resize the aggregation arrays if necessary */ 4225 if( *saggregations == *naggregations ) 4226 { 4227 *saggregations = SCIPcalcMemGrowSize(scip, *naggregations + 1); 4228 assert(*saggregations > *naggregations); 4229 SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrtypes, *saggregations) ); 4230 SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrvars, 2 * (*saggregations)) ); 4231 4232 /* clear the aggregation type array to set the default to the aggregation of the form x + y = 1 */ 4233 BMSclearMemoryArray(&(undoneaggrtypes[*naggregations]), *saggregations - *naggregations); /*lint !e866*/ 4234 } 4235 4236 /* memorize aggregation variables*/ 4237 undoneaggrtypes[*naggregations] = TRUE; 4238 undoneaggrvars[2 * (*naggregations)] = aggvar1; 4239 undoneaggrvars[2 * (*naggregations) + 1] = aggvar2; 4240 ++(*naggregations); 4241 4242 if( !SCIPdoNotAggr(scip) ) 4243 { 4244 /* delete constraint */ 4245 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it is dominated by constraint <%s>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons)); 4246 assert(SCIPconsIsActive(cons1)); 4247 4248 SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) ); 4249 SCIP_CALL( SCIPdelCons(scip, cons1) ); 4250 ++(*ndelconss); 4251 } 4252 } 4253 /* w.l.o.g. cons is a setpartitioning constraint and countofoverlapping == nvars - oldnfixedzeros - 1 we can 4254 * delete all overlapping variables in cons1 and add the negated variable of the not overlapped variable to cons 4255 * 1; the result should be a shorter constraint with the same impact 4256 */ 4257 else if( shrinking && !overlapdestroyed && countofoverlapping[c] > 1 && ((consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1) || (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars1 - 1)) ) /*lint !e641*/ 4258 { 4259 SCIP_CONSDATA* consdatachange; 4260 SCIP_VAR** varstostay; 4261 SCIP_VAR** varstochange; 4262 SCIP_CONS* constochange; 4263 SCIP_CONS* constostay; 4264 SCIP_VAR* addvar; 4265 SCIP_Bool negated0; 4266 SCIP_Bool negated1; 4267 int nvarstostay; 4268 int nvarstochange; 4269 int constochangeidx; 4270 #ifndef NDEBUG 4271 const int oldnchgcoefs = *nchgcoefs; 4272 #endif 4273 4274 addvar = NULL; 4275 4276 assert((consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING) != (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING) || countofoverlapping[c] != nvars - 1 || countofoverlapping[c] != nvars1 - 1); /*lint !e641*/ 4277 4278 /* both constraints should stay merged */ 4279 assert(consdata->merged); 4280 assert(consdata1->merged); 4281 4282 /* sorting array after indices of variables, negated and active counterparts would stand side by side */ 4283 SCIPsortDownPtr((void**)(consdata1->vars), SCIPvarCompActiveAndNegated, nvars1); 4284 /* standard setppc-sorting now lost */ 4285 consdata1->sorted = FALSE; 4286 4287 /* initialize variables */ 4288 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1) /*lint !e641*/ 4289 { 4290 varstostay = vars; 4291 varstochange = consdata1->vars; 4292 nvarstostay = nvars; 4293 nvarstochange = nvars1; 4294 constostay = cons; 4295 constochange = cons1; 4296 consdatachange = consdata1; 4297 constochangeidx = c; 4298 } 4299 else 4300 { 4301 varstostay = consdata1->vars; 4302 varstochange = vars; 4303 nvarstostay = nvars1; 4304 nvarstochange = nvars; 4305 constostay = cons1; 4306 constochange = cons; 4307 consdatachange = consdata; 4308 constochangeidx = considx; 4309 4310 *chgcons = TRUE; 4311 } 4312 4313 /* iterate over the both cliques variables the "same" time, here we need the backward loop, because we 4314 * delete some variables and we don not want to loose order 4315 */ 4316 for( v = nvarstostay - 1, v1 = nvarstochange - 1; v >= 0 && v1 >= 0; ) 4317 { 4318 if( SCIPvarGetLbLocal(varstochange[v1]) > 0.5 || SCIPvarGetUbLocal(varstochange[v1]) < 0.5 ) 4319 { 4320 --v1; 4321 continue; 4322 } 4323 if( SCIPvarGetLbLocal(varstostay[v]) > 0.5 || SCIPvarGetUbLocal(varstostay[v]) < 0.5 ) 4324 { 4325 --v; 4326 continue; 4327 } 4328 4329 /* all variables inside the second clique constraint should be either active or negated of an active one */ 4330 assert(SCIPvarIsActive(varstochange[v1]) || (SCIPvarGetStatus(varstochange[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstochange[v1])))); 4331 /* all variables inside the first clique constraint should be either active or negated of an active one */ 4332 assert(SCIPvarIsActive(varstostay[v]) || (SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v])))); 4333 4334 /* get not negated variable and clique value in constostay */ 4335 if( SCIPvarIsActive(varstostay[v]) ) 4336 { 4337 var = varstostay[v]; 4338 negated0 = FALSE; 4339 } 4340 else 4341 { 4342 assert(SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v]))); 4343 var = SCIPvarGetNegationVar(varstostay[v]); 4344 negated0 = TRUE; 4345 } 4346 4347 /* get active variable and clique value of in constochange*/ 4348 if( SCIPvarIsActive(varstochange[v1]) ) 4349 { 4350 var1 = varstochange[v1]; 4351 negated1 = FALSE; 4352 } 4353 else 4354 { 4355 assert(SCIPvarGetStatus(varstochange[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstochange[v1]))); 4356 var1 = SCIPvarGetNegationVar(varstochange[v1]); 4357 negated1 = TRUE; 4358 } 4359 4360 /* variable index in the constraint smaller than the other one, so go to the next variable in cons */ 4361 if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) ) 4362 { 4363 assert(addvar == NULL); 4364 addvar = varstostay[v]; 4365 --v; 4366 } 4367 /* variable index in the constraint is greater than the other one, so fix this variable */ 4368 else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) ) 4369 { 4370 --v1; 4371 } 4372 else 4373 { 4374 /* because the constraint's are merged it is not possible that one constraint contains a negated variable 4375 * of another, but both constraint might have a variable in negated form of the other 4376 */ 4377 if( negated0 != negated1 ) 4378 { 4379 assert(addvar == NULL); 4380 4381 SCIPdebugMsg(scip, "-> trying to fix <%s> to 0 because it would exist twice in a constraint\n", SCIPvarGetName(varstochange[v1])); 4382 4383 /* fix variable to zero */ 4384 SCIP_CALL( SCIPfixVar(scip, varstochange[v1], 0.0, cutoff, &fixed) ); 4385 if( *cutoff ) 4386 { 4387 SCIPdebugMsg(scip, "fixing led to cutoff\n"); 4388 4389 return SCIP_OKAY; 4390 } 4391 4392 assert(fixed); 4393 ++(*nfixedvars); 4394 4395 /* the above fixing is equal to the fixation of varstostay[v] to 1, so we can call presolvePropagateCons() for consstay */ 4396 SCIP_CALL( presolvePropagateCons(scip, constostay, FALSE, NULL, NULL, NULL, NULL, nfixedvars, naggrvars, ndelconss, cutoff) ); 4397 4398 return SCIP_OKAY; 4399 } 4400 else 4401 { 4402 /* correct local data structure, remove variable from constraint entry where it will be removed */ 4403 deleteCliqueDataEntry(varstochange[v1], constochangeidx, vartoindex, varnconss, varconsidxs); 4404 4405 SCIPdebugMsg(scip, " -> deleting variable <%s> in constraint <%s> number %d, because it will be replaced\n", SCIPvarGetName(varstochange[v1]), SCIPconsGetName(constochange), constochangeidx); 4406 /* delete overlapping variables in constochange */ 4407 SCIP_CALL( delCoefPos(scip, constochange, v1) ); 4408 ++(*nchgcoefs); 4409 } 4410 4411 --v; 4412 --v1; 4413 } 4414 } 4415 assert(addvar != NULL || v >= 0); 4416 /* we should have removed exactly countofoverlapping[c] variables from the constochange */ 4417 assert(*nchgcoefs - oldnchgcoefs == countofoverlapping[c]); 4418 4419 /* determine addvar if not yet found */ 4420 if( addvar == NULL ) 4421 { 4422 for( ; v >= 0; --v) 4423 { 4424 if( SCIPvarGetLbLocal(varstostay[v]) > 0.5 || SCIPvarGetUbLocal(varstostay[v]) < 0.5 ) 4425 continue; 4426 4427 /* all variables inside the first clique constraint should be either active or negated of an active one */ 4428 assert(SCIPvarIsActive(varstostay[v]) || (SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v])))); 4429 4430 addvar = varstostay[v]; 4431 break; 4432 } 4433 } 4434 assert(addvar != NULL); 4435 4436 /* get representative variable for all deleted variables */ 4437 SCIP_CALL( SCIPgetNegatedVar(scip, addvar, &addvar) ); 4438 assert(addvar != NULL); 4439 4440 SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(addvar), SCIPconsGetName(constochange), constochangeidx); 4441 /* add representative for overlapping instead */ 4442 SCIP_CALL( addCoef(scip, constochange, addvar) ); 4443 ++(*nchgcoefs); 4444 4445 /* constraint should be still merged because this added variable is new in this constraint */ 4446 consdatachange->merged = TRUE; 4447 assert(constochangeidx == (cons == constochange ? considx : c)); 4448 4449 /* correct local data structure, add constraint entry to variable data */ 4450 SCIP_CALL( addCliqueDataEntry(scip, addvar, constochangeidx, TRUE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) ); 4451 4452 /* cons changed so much, that it cannot be used for more overlapping checks */ 4453 if( *chgcons ) 4454 return SCIP_OKAY; 4455 } 4456 } 4457 4458 return SCIP_OKAY; 4459 } 4460 4461 /** try to lift variables to given constraint */ 4462 /** @todo try another variant by determine lifting variables as the intersection of all cliques variables of the 4463 * constraint variables, note that the intersection changes after one variable was added 4464 */ 4465 static 4466 SCIP_RETCODE liftCliqueVariables( 4467 SCIP*const scip, /**< SCIP data structure */ 4468 SCIP_CONS*const cons, /**< constraint which may overlap */ 4469 int const arraypos, /**< position of constraint in global array */ 4470 SCIP_VAR**const usefulvars, /**< possible variables to lift */ 4471 int*const nusefulvars, /**< pointer to store number of added variables */ 4472 int const endidx, /**< end index for possible lifting variables */ 4473 SCIP_Bool** cliquevalues, /**< pointer to clique values of constraint-variables, either one if the 4474 * variable is active or zero if the variable is negated 4475 * @note this array can be resized in this method 4476 */ 4477 SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */ 4478 int*const varnconss, /**< array with number of constraints a variable occurs */ 4479 int*const maxnvarconsidx, /**< array with the maximal number of occurrences of a variable */ 4480 int**const varconsidxs, /**< array with constraint indices in which the corresponding variable 4481 * exists 4482 */ 4483 int*const maxnvars, /**< pointer to store maximal number of variables of a constraint */ 4484 int*const nadded, /**< pointer to store number of possible added variables */ 4485 SCIP_Bool*const chgcons, /**< pointer to store if the constraint was changed, due to added 4486 * variables 4487 */ 4488 int*const nfixedvars, /**< pointer to count number of deleted variables */ 4489 int*const ndelconss, /**< pointer to count number of deleted constraints */ 4490 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */ 4491 ) 4492 { 4493 SCIP_CONSDATA* consdata; 4494 SCIP_VAR** vars; 4495 SCIP_VAR* var; 4496 SCIP_VAR* var1; 4497 SCIP_Bool fixed; 4498 SCIP_Bool value; 4499 int nvars; 4500 int nottocheck; /* will be the position for a variable in cons0 which is in negated form in the same clique */ 4501 int v; 4502 int v1; 4503 int k; 4504 4505 assert(scip != NULL); 4506 assert(cons != NULL); 4507 assert(usefulvars != NULL); 4508 assert(cliquevalues != NULL); 4509 assert(*cliquevalues != NULL); 4510 assert(vartoindex != NULL); 4511 assert(varnconss != NULL); 4512 assert(maxnvarconsidx != NULL); 4513 assert(varconsidxs != NULL); 4514 assert(maxnvars != NULL); 4515 assert(nadded != NULL); 4516 assert(chgcons != NULL); 4517 assert(nfixedvars != NULL); 4518 assert(ndelconss != NULL); 4519 assert(cutoff != NULL); 4520 4521 if( !SCIPconsIsActive(cons) ) 4522 return SCIP_OKAY; 4523 4524 consdata = SCIPconsGetData(cons); 4525 assert(consdata != NULL); 4526 4527 nvars = consdata->nvars; 4528 4529 if( nvars == 0 ) 4530 return SCIP_OKAY; 4531 4532 assert(nvars <= *maxnvars); 4533 4534 vars = consdata->vars; 4535 assert(vars != NULL); 4536 4537 v1 = endidx; 4538 4539 /* now we try to add variables with index prior to endidx to cons */ 4540 for( v = nvars - 1; v >= 0 && v1 >= 0; ) 4541 { 4542 if( SCIPvarGetLbLocal(usefulvars[v1]) > 0.5 || SCIPvarGetUbLocal(usefulvars[v1]) < 0.5 ) 4543 { 4544 --v1; 4545 continue; 4546 } 4547 if( SCIPvarGetUbLocal(vars[v]) < 0.5 ) 4548 { 4549 --v; 4550 continue; 4551 } 4552 4553 /* check that constraint variables are still correctly sorted, indices of active variables should be decreasing */ 4554 assert(v == 0 || SCIPvarCompareActiveAndNegated(vars[v], vars[v - 1]) <= 0); 4555 4556 /* there should no variables fixed to one occur in our constraint */ 4557 assert(SCIPvarGetLbLocal(vars[v]) < 0.5 && SCIPvarGetUbLocal(vars[v]) > 0.5); 4558 assert(SCIPvarGetLbLocal(usefulvars[v1]) < 0.5 && SCIPvarGetUbLocal(usefulvars[v1]) > 0.5); 4559 4560 /* all variables which we have inside the clique constraint and which can possibly be added should be either active or negated */ 4561 assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v])))); 4562 assert(SCIPvarIsActive(usefulvars[v1]) || (SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1])))); 4563 4564 /* constraint should during adding of variables stay merged, because for each variable which is added holds that 4565 * the index of this corresponding active variable is pairwise different to all indices of all active 4566 * corresponding variables inside the constraint 4567 * @note it should not happen that we add one variable and the corresponding counterpart to the same constraint */ 4568 assert(consdata->merged); 4569 4570 /* get active variable and clique value in cons */ 4571 if( (*cliquevalues)[v] ) 4572 var = vars[v]; 4573 else 4574 { 4575 assert(SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))); 4576 var = SCIPvarGetNegationVar(vars[v]); 4577 } 4578 4579 /* get active variable and clique value of next variable */ 4580 if( SCIPvarIsActive(usefulvars[v1]) ) 4581 { 4582 var1 = usefulvars[v1]; 4583 value = TRUE; 4584 } 4585 else 4586 { 4587 assert(SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1]))); 4588 var1 = SCIPvarGetNegationVar(usefulvars[v1]); 4589 value = FALSE; 4590 } 4591 4592 nottocheck = -1; 4593 k = 0; 4594 4595 /* variable index in the constraint smaller than the other one, so go to the next variable in cons */ 4596 if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) ) 4597 { 4598 --v; 4599 continue; 4600 } 4601 /* variable index in the constraint is greater than the other one, so check for possible inclusion of the variable */ 4602 else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) ) 4603 { 4604 assert(consdata == SCIPconsGetData(cons)); 4605 4606 /* check if every variable in the actual clique is in clique with the new variable */ 4607 for( k = nvars - 1; k >= 0; --k ) 4608 { 4609 if( SCIPvarGetUbLocal(vars[k]) > 0.5 ) 4610 { 4611 /* there should no variables fixed to one occur in our constraint */ 4612 assert(SCIPvarGetLbLocal(vars[k]) < 0.5); 4613 assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k])))); 4614 4615 if( (*cliquevalues)[k] ) 4616 { 4617 assert(SCIPvarIsActive(vars[k])); 4618 var = vars[k]; 4619 } 4620 else 4621 { 4622 assert(SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))); 4623 var = SCIPvarGetNegationVar(vars[k]); 4624 } 4625 if( !SCIPhaveVarsCommonClique(scip, var1, value, var, (*cliquevalues)[k], TRUE) ) 4626 break; 4627 } 4628 } 4629 --v1; 4630 } 4631 /* variable index in the constraint is equal to the index of the other variable, check if these variables are 4632 * negated of each other so memorize the position and check for possible inclusion of the new variable and if 4633 * possible decrease indices 4634 */ 4635 else 4636 { 4637 /* one clique contains the negated and the other clique the corresponding active var */ 4638 if( value != (*cliquevalues)[v] ) 4639 { 4640 nottocheck = v; 4641 4642 assert(consdata == SCIPconsGetData(cons)); 4643 assert(nvars <= consdata->nvars); 4644 4645 /* check if every variable in the actual clique is in clique with the new variable */ 4646 for( k = nvars - 1; k >= 0; --k ) 4647 { 4648 if( SCIPvarGetUbLocal(vars[k]) > 0.5 ) 4649 { 4650 /* there should no variables fixed to one occur in our constraint */ 4651 assert(SCIPvarGetLbLocal(vars[k]) < 0.5); 4652 4653 assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k])))); 4654 4655 if( k == nottocheck ) 4656 continue; 4657 4658 if( (*cliquevalues)[k] ) 4659 { 4660 assert(SCIPvarIsActive(vars[k])); 4661 var = vars[k]; 4662 } 4663 else 4664 { 4665 assert(SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))); 4666 var = SCIPvarGetNegationVar(vars[k]); 4667 } 4668 4669 if( !SCIPhaveVarsCommonClique(scip, var1, value, var, (*cliquevalues)[k], TRUE) ) 4670 break; 4671 } 4672 } 4673 } 4674 /* don't decrease v because it might happen that the corresponding negated variable of var is next in 4675 * usefulvars 4676 */ 4677 --v1; 4678 } 4679 4680 /* if k is smaller than 0 than the possible new variables is in the same clique with all variables of cons, 4681 * so we add the new variable to clique constraint or fix some variables */ 4682 if( k < 0 ) 4683 { 4684 ++(*nadded); 4685 4686 /* we found a variable which is the negated variable of another one in this clique so we can fix all 4687 * other variable to zero and if it's a partitioning constraint we can also fix the variable of the 4688 * negated to one and we can delete the constraint too */ 4689 if( nottocheck >= 0 ) 4690 { 4691 assert(consdata == SCIPconsGetData(cons)); 4692 assert(nvars <= consdata->nvars); 4693 assert(consdata->merged); 4694 4695 /* process all vars for possible fixing */ 4696 for( k = consdata->nvars - 1; k >= 0; --k ) 4697 { 4698 if( SCIPvarGetUbLocal(vars[k]) > 0.5 ) 4699 { 4700 /* there should no variables fixed to one occur in our constraint */ 4701 assert(SCIPvarGetLbLocal(vars[v]) < 0.5); 4702 4703 assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k])))); 4704 4705 if( k != nottocheck ) 4706 { 4707 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because we could lift a negated variable of another constraint variable\n", SCIPvarGetName(vars[k])); 4708 /* fix variable to zero */ 4709 SCIP_CALL( SCIPfixVar(scip, vars[k], 0.0, cutoff, &fixed) ); 4710 4711 if( *cutoff ) 4712 { 4713 SCIPdebugMsg(scip, "fixing led to cutoff\n"); 4714 4715 return SCIP_OKAY; 4716 } 4717 4718 assert(fixed); 4719 4720 ++(*nfixedvars); 4721 } 4722 } 4723 } 4724 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/ 4725 { 4726 assert(SCIPvarIsActive(vars[nottocheck]) || (SCIPvarGetStatus(vars[nottocheck]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[nottocheck])))); 4727 4728 SCIPdebugMsg(scip, "trying to fix <%s> to 1 due to this setpartitioning variable is with its negated in the same clique\n", SCIPvarGetName(vars[nottocheck])); 4729 /* fix the remaining variable to one, due to it's the only one left to satisfy the constraint */ 4730 SCIP_CALL( SCIPfixVar(scip, vars[nottocheck], 1.0, cutoff, &fixed) ); 4731 if( *cutoff ) 4732 { 4733 SCIPdebugMsg(scip, "fixing led to cutoff\n"); 4734 4735 return SCIP_OKAY; 4736 } 4737 4738 assert(fixed); 4739 ++(*nfixedvars); 4740 } 4741 4742 /* delete constraint */ 4743 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to active and negated variable in the same clique constraint\n", SCIPconsGetName(cons), arraypos); 4744 assert(SCIPconsIsActive(cons)); 4745 SCIP_CALL( SCIPdelCons(scip, cons) ); 4746 ++(*ndelconss); 4747 4748 break; 4749 } 4750 /* we found a variable which could be added to a partitioning constraint so we can fix it to zero */ 4751 else if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/ 4752 { 4753 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because this variable is in the same clique with a set partition\n", SCIPvarGetName(usefulvars[v1 + 1])); 4754 /* fix variable to zero */ 4755 SCIP_CALL( SCIPfixVar(scip, usefulvars[v1 + 1], 0.0, cutoff, &fixed) ); 4756 4757 if( *cutoff ) 4758 { 4759 SCIPdebugMsg(scip, "fixing led to cutoff\n"); 4760 4761 return SCIP_OKAY; 4762 } 4763 4764 assert(fixed); 4765 4766 ++(*nfixedvars); 4767 } 4768 /* we have found a new variable for a set packing constraint cons, so add the found variable to the first constraint */ 4769 else 4770 { 4771 SCIP_VAR* addvar; 4772 4773 assert(SCIPconsIsActive(cons)); 4774 4775 addvar = usefulvars[v1 + 1]; 4776 4777 assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5); 4778 4779 /* add representative instead */ 4780 SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(usefulvars[v1 + 1]), SCIPconsGetName(cons), arraypos); 4781 SCIP_CALL( addCoef(scip, cons, addvar) ); 4782 assert(consdata == SCIPconsGetData(cons)); 4783 /* we know that this constraint stays merged but later on we have to resort */ 4784 consdata->merged = TRUE; 4785 4786 /* second we add the constraint index to the list of indices where this variable occurs */ 4787 assert(SCIPhashmapExists(vartoindex, (void*) addvar)); 4788 4789 /* correct local data structure, add constraint entry to variable data */ 4790 SCIP_CALL( addCliqueDataEntry(scip, addvar, arraypos, FALSE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) ); 4791 4792 /* we need the new pointer to the variables, because due to adding variables it is possible that we 4793 * did reallocate the variables array inside the constraint, the index v should stay the same because the 4794 * added variable was inserted at the end and we are decreasing v in our for loop 4795 */ 4796 vars = consdata->vars; 4797 nvars = consdata->nvars; 4798 4799 /* we need to update our data structure */ 4800 4801 /* resize clique array if necessary, due to adding variables */ 4802 if( (*maxnvars) < nvars ) 4803 { 4804 while( (*maxnvars) < nvars ) 4805 (*maxnvars) *= 2 ; 4806 SCIP_CALL( SCIPreallocBufferArray(scip, cliquevalues, (*maxnvars)) ); 4807 } 4808 (*cliquevalues)[nvars - 1] = SCIPvarIsActive(addvar) ? TRUE : FALSE; 4809 4810 (*chgcons) = TRUE; 4811 } 4812 } 4813 } 4814 4815 if( !SCIPconsIsActive(cons) ) 4816 return SCIP_OKAY; 4817 4818 /* maybe we stopped because of cons(v reached -1) so try to add rest in usefulvars */ 4819 for( ; v1 >= 0; --v1) 4820 { 4821 if( SCIPvarGetLbLocal(usefulvars[v1]) > 0.5 || SCIPvarGetUbLocal(usefulvars[v1]) < 0.5 ) 4822 continue; 4823 4824 /* get active variable and clique value */ 4825 if( SCIPvarIsActive(usefulvars[v1]) ) 4826 { 4827 var1 = usefulvars[v1]; 4828 value = TRUE; 4829 } 4830 else 4831 { 4832 assert(SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1]))); 4833 var1 = SCIPvarGetNegationVar(usefulvars[v1]); 4834 value = FALSE; 4835 } 4836 4837 assert(consdata == SCIPconsGetData(cons)); 4838 assert(nvars <= consdata->nvars); 4839 4840 /* check if every variable in the actual clique is in clique with the new variable */ 4841 for( k = nvars - 1; k >= 0; --k ) 4842 { 4843 if( SCIPvarGetUbLocal(vars[k]) > 0.5 ) 4844 { 4845 /* there should no variables fixed to one occur in our constraint */ 4846 assert(SCIPvarGetLbLocal(vars[k]) < 0.5); 4847 4848 assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k])))); 4849 4850 if( (*cliquevalues)[k] ) 4851 { 4852 assert(SCIPvarIsActive(vars[k])); 4853 var = vars[k]; 4854 } 4855 else 4856 { 4857 assert(SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))); 4858 var = SCIPvarGetNegationVar(vars[k]); 4859 } 4860 4861 if( !SCIPvarsHaveCommonClique(var1, value, var, (*cliquevalues)[k], TRUE) ) 4862 break; 4863 } 4864 } 4865 4866 /* add new variable to clique constraint or fix some variables */ 4867 if( k < 0 ) 4868 { 4869 /* we found a variable which could be added to a partitioning constraint so we can fix it to zero */ 4870 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/ 4871 { 4872 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because this variable is in the same clique with a set partition\n", SCIPvarGetName(usefulvars[v1])); 4873 4874 /* fix variable to zero */ 4875 SCIP_CALL( SCIPfixVar(scip, usefulvars[v1], 0.0, cutoff, &fixed) ); 4876 if( *cutoff ) 4877 { 4878 SCIPdebugMsg(scip, "fixing led to cutoff\n"); 4879 4880 return SCIP_OKAY; 4881 } 4882 assert(fixed); 4883 4884 ++(*nfixedvars); 4885 ++(*nadded); 4886 } 4887 /* add the found variable to the first constraint */ 4888 else 4889 { 4890 SCIP_VAR* addvar; 4891 4892 assert(SCIPconsIsActive(cons)); 4893 4894 addvar = usefulvars[v1]; 4895 4896 assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5); 4897 4898 /* add representative instead */ 4899 SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(addvar), SCIPconsGetName(cons), arraypos); 4900 SCIP_CALL( addCoef(scip, cons, addvar) ); 4901 assert(consdata == SCIPconsGetData(cons)); 4902 /* we know that this constraint stays merged but later on we have to resort */ 4903 consdata->merged = TRUE; 4904 4905 /* second we add the constraint index to the list of indices where this variable occurs */ 4906 assert(SCIPhashmapExists(vartoindex, (void*) addvar)); 4907 4908 /* correct local data structure, add constraint entry to variable data */ 4909 SCIP_CALL( addCliqueDataEntry(scip, addvar, arraypos, FALSE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) ); 4910 4911 /* we need the new pointer to the variables, because due to adding variables it is possible that we 4912 * did reallocate the variables array inside the constraint, the index v should stay the same because the 4913 * added variable was inserted at the end and we are decreasing v in our for loop 4914 */ 4915 vars = consdata->vars; 4916 nvars = consdata->nvars; 4917 4918 /* we need to update our data structure */ 4919 4920 /* resize clique array if necessary, due to adding variables */ 4921 if( (*maxnvars) < nvars ) 4922 { 4923 while( (*maxnvars) < nvars ) 4924 (*maxnvars) *= 2 ; 4925 SCIP_CALL( SCIPreallocBufferArray(scip, cliquevalues, (*maxnvars)) ); 4926 } 4927 (*cliquevalues)[nvars - 1] = SCIPvarIsActive(addvar) ? TRUE : FALSE; 4928 4929 ++(*nadded); 4930 (*chgcons) = TRUE; 4931 } 4932 } 4933 } 4934 4935 return SCIP_OKAY; 4936 } 4937 4938 /** perform all collected aggregations */ 4939 static 4940 SCIP_RETCODE performAggregations( 4941 SCIP*const scip, /**< SCIP data structure */ 4942 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 4943 SCIP_VAR**const undoneaggrvars, /**< aggregation variables storage */ 4944 SCIP_Bool*const undoneaggrtypes, /**< aggregation type storage, type FALSE means the aggregation is of the 4945 * form x + y = 1; type TRUE means the aggregation is of the form x = y; 4946 */ 4947 int const naggregations, /**< number of aggregations to performed */ 4948 int*const naggrvars, /**< pointer to count number of aggregated variables */ 4949 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */ 4950 ) 4951 { /*lint --e{715}*/ 4952 SCIP_VAR* var1; 4953 SCIP_VAR* var2; 4954 SCIP_Bool aggregated; 4955 SCIP_Bool redundant; 4956 int a; 4957 4958 assert(scip != NULL); 4959 assert(conshdlrdata != NULL); 4960 assert(undoneaggrvars != NULL); 4961 assert(undoneaggrtypes != NULL); 4962 assert(naggregations > 0); 4963 assert(naggrvars != NULL); 4964 assert(cutoff != NULL); 4965 4966 /* loop over all open aggregations and try to aggregate them */ 4967 for( a = 0; a < naggregations; ++a ) 4968 { 4969 var1 = undoneaggrvars[2 * a]; 4970 var2 = undoneaggrvars[2 * a + 1]; 4971 assert(var1 != NULL); 4972 assert(var2 != NULL); 4973 4974 SCIPdebugMsg(scip, "trying to aggregate <%s> %s <%s>%s\n", SCIPvarGetName(var1), undoneaggrtypes[a] ? "=" : "+", SCIPvarGetName(var2), undoneaggrtypes[a] ? "" : " = 1"); 4975 4976 #ifdef VARUSES 4977 /* in order to not mess up the variable usage counting, we have to decrease usage counting, aggregate, 4978 * and increase usage counting again 4979 */ 4980 SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var1) ); 4981 SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var2) ); 4982 #endif 4983 4984 /* aggregate last remaining variables in the set partitioning constraint */ 4985 if( undoneaggrtypes[a] ) 4986 { 4987 SCIP_CALL( SCIPaggregateVars(scip, var1, var2, 1.0, -1.0, 0.0, cutoff, &redundant, &aggregated) ); 4988 } 4989 else 4990 { 4991 SCIP_CALL( SCIPaggregateVars(scip, var1, var2, 1.0, 1.0, 1.0, cutoff, &redundant, &aggregated) ); 4992 } 4993 4994 if( *cutoff ) 4995 { 4996 SCIPdebugMsg(scip, "aggregation was infeasible\n"); 4997 4998 return SCIP_OKAY; 4999 } 5000 /* binary variables should always be aggregated, or due to fixation the aggregation is redundant */ 5001 assert(redundant); 5002 5003 if( aggregated ) 5004 ++(*naggrvars); 5005 5006 #ifdef VARUSES 5007 /* increase variable usage counting again */ 5008 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var1) ); 5009 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var2) ); 5010 #endif 5011 } 5012 5013 return SCIP_OKAY; 5014 } 5015 5016 /** check whether we can combine or grow cliques so some constraints become redundant or we can fix variables */ 5017 /** @todo try another variant, by building up the clique graph and delete unnecessary (transitive closure) edges and do 5018 * a bfs search to search for common ancestors to get all possible lifting variables 5019 */ 5020 static 5021 SCIP_RETCODE preprocessCliques( 5022 SCIP*const scip, /**< SCIP data structure */ 5023 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ 5024 SCIP_CONS**const conss, /**< constraint set */ 5025 int const nconss, /**< number of constraints in constraint set */ 5026 int const nrounds, /**< actual presolving round */ 5027 int*const firstchange, /**< pointer to store first changed constraint */ 5028 int*const firstclique, /**< pointer to store first constraint to start adding clique again */ 5029 int*const lastclique, /**< pointer to store last constraint to add cliques again */ 5030 int*const nfixedvars, /**< pointer to count number of deleted variables */ 5031 int*const naggrvars, /**< pointer to count number of aggregated variables */ 5032 int*const ndelconss, /**< pointer to count number of deleted constraints */ 5033 int*const nchgcoefs, /**< pointer to count number of deleted coefficients */ 5034 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */ 5035 ) 5036 { 5037 /* extend cliques/constraints by checking whether some variables are in the same clique, no pairwise clique lifting 5038 * which would be slower 5039 */ 5040 SCIP_CONS** usefulconss; /* array with pointers of constraint of setpartitioning and setpacking type */ 5041 SCIP_VAR** usefulvars; /* array with pointers of variables in setpartitioning and setpacking constraints */ 5042 int** varconsidxs; /* array consisting of constraint indices in which the corresponding variable exists */ 5043 int* varnconss; /* array consisting of number of constraints the variable occurs */ 5044 int* maxnvarconsidx; /* maximal number of occurrences of a variable */ 5045 int* countofoverlapping = NULL; /* the amount of variables which are in another constraint */ 5046 SCIP_Bool* cliquevalues = NULL; /* values of clique-variables, either one if the variable is active or zero if the variable is negated */ 5047 5048 SCIP_HASHMAP* vartoindex; /* mapping of SCIP variables to indices */ 5049 SCIP_CONSDATA* consdata; 5050 5051 SCIP_Bool chgcons0; 5052 int nvars; 5053 int c; 5054 int v; 5055 int nusefulconss; 5056 int nusefulvars; 5057 int susefulvars; 5058 int maxnvars; 5059 int varindex; 5060 5061 SCIP_VAR** undoneaggrvars; /* storage for not yet performed aggregations */ 5062 SCIP_Bool* undoneaggrtypes; /* storage for not yet performed aggregation type (x = y or x + y = 1) */ 5063 int saggregations; 5064 int naggregations; 5065 5066 assert(scip != NULL); 5067 assert(conshdlrdata != NULL); 5068 assert(conss != NULL || nconss == 0); 5069 assert(firstchange != NULL); 5070 assert(firstclique != NULL); 5071 assert(lastclique != NULL); 5072 assert(nfixedvars != NULL); 5073 assert(naggrvars != NULL); 5074 assert(ndelconss != NULL); 5075 assert(nchgcoefs != NULL); 5076 assert(cutoff != NULL); 5077 5078 *cutoff = FALSE; 5079 5080 if( nconss == 0 ) 5081 return SCIP_OKAY; 5082 5083 nvars = SCIPgetNVars(scip); 5084 5085 if( nvars == 0 ) 5086 return SCIP_OKAY; 5087 5088 susefulvars = 2 * nvars; /* two times because of negated vars, maybe due to deleted variables we need to increase this */ 5089 5090 /* a hashmap from varindex to postion in varconsidxs array, because above is still too small */ 5091 SCIP_CALL( SCIPhashmapCreate(&vartoindex, SCIPblkmem(scip), nvars) ); 5092 5093 /* get temporary memory for the aggregation storage, to memorize aggregations which will be performed later, otherwise we would destroy our local data structures */ 5094 saggregations = nvars; 5095 SCIP_CALL( SCIPallocBufferArray(scip, &undoneaggrvars, 2 * saggregations) ); 5096 SCIP_CALL( SCIPallocBufferArray(scip, &undoneaggrtypes, saggregations) ); 5097 BMSclearMemoryArray(undoneaggrtypes, saggregations); 5098 naggregations = 0; 5099 5100 /* get temporary memory for all clique constraints, all appearing variables and the mapping from variables to constraints */ 5101 SCIP_CALL( SCIPallocBufferArray(scip, &usefulconss, nconss) ); 5102 SCIP_CALL( SCIPallocBufferArray(scip, &usefulvars, susefulvars) ); 5103 BMSclearMemoryArray(usefulvars, susefulvars); 5104 SCIP_CALL( SCIPallocBufferArray(scip, &varnconss, susefulvars + 1) ); 5105 BMSclearMemoryArray(varnconss, susefulvars + 1); 5106 SCIP_CALL( SCIPallocBufferArray(scip, &maxnvarconsidx, susefulvars + 1) ); 5107 SCIP_CALL( SCIPallocBufferArray(scip, &varconsidxs, susefulvars + 1) ); 5108 BMSclearMemoryArray(varconsidxs, susefulvars + 1); 5109 nusefulvars = 0; 5110 nusefulconss = 0; 5111 maxnvars = 0; 5112 5113 /* @todo: check for round limit for adding extra clique constraints */ 5114 /* adding clique constraints which arises from global clique information */ 5115 if( conshdlrdata->nclqpresolve == 0 && conshdlrdata->addvariablesascliques ) 5116 { 5117 SCIP_VAR** vars = SCIPgetVars(scip); 5118 SCIP_VAR** binvars; 5119 int* cliquepartition; 5120 int ncliques; 5121 int nbinvars; 5122 int naddconss; 5123 5124 nbinvars = SCIPgetNBinVars(scip); 5125 SCIP_CALL( SCIPduplicateBufferArray(scip, &binvars, vars, nbinvars) ); 5126 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nbinvars) ); 5127 5128 /* @todo: check for better permutations/don't permute the first round 5129 * @todo: take binary variables which are not of vartype SCIP_VARTYPE_BINARY into account 5130 */ 5131 SCIPrandomPermuteArray(conshdlrdata->randnumgen, (void**)binvars, 0, nbinvars); 5132 5133 /* try to create a clique-partition over all binary variables and create these cliques as new setppc constraints 5134 * and add them to the usefulconss array and adjust all necessary data this will hopefully lead to faster 5135 * detection of redundant constraints 5136 */ 5137 SCIP_CALL( SCIPcalcCliquePartition(scip, binvars, nbinvars, cliquepartition, &ncliques) ); 5138 5139 /* resize usefulconss array if necessary */ 5140 SCIP_CALL( SCIPreallocBufferArray(scip, &usefulconss, nconss + ncliques) ); 5141 5142 naddconss = 0; 5143 5144 /* add extra clique constraints resulting from the cliquepartition calculation to SCIP and to the local data structure */ 5145 SCIP_CALL( addExtraCliques(scip, binvars, nbinvars, cliquepartition, ncliques, usefulconss, &nusefulconss, 5146 nrounds, nfixedvars, &naddconss, ndelconss, nchgcoefs, cutoff) ); 5147 5148 /* bad hack, we don't want to count these artificial created constraints if they got deleted, so ndelconss 5149 * can become negative which will be change to zero at the end of this method if it's still negative 5150 */ 5151 *ndelconss -= naddconss; 5152 5153 SCIPfreeBufferArray(scip, &cliquepartition); 5154 SCIPfreeBufferArray(scip, &binvars); 5155 5156 if( *cutoff ) 5157 goto TERMINATE; 5158 } 5159 5160 /* start to collect setpartitioning and setpacking constraints, and try to remove fixed variables and merged these 5161 * constraints 5162 */ 5163 SCIP_CALL( collectCliqueConss(scip, conss, nconss, usefulconss, &nusefulconss, nfixedvars, ndelconss, nchgcoefs, cutoff) ); 5164 /* @Note: Even after the call above some constraints can have fixed variables, because it might happen that caused by 5165 * mergeMultiplies some variables were fixed which occurred already in previous constraints 5166 */ 5167 if( *cutoff ) 5168 goto TERMINATE; 5169 5170 /* no usefulconss found */ 5171 if( nusefulconss <= 1 ) 5172 goto TERMINATE; 5173 5174 /* @todo: maybe sort them after biggest indices too, or another variant would be to restore the order as they were 5175 * read in 5176 */ 5177 /* sort constraints first after type (partitioning before packing) and second after number of variables such that the 5178 * partitioning constraints have increasing number of variables and the packing constraints have decreasing number of 5179 * variables, because we loop from back to front we sort them downwards, so they are the other way around 5180 */ 5181 SCIPsortDownPtr((void**)usefulconss, setppcConssSort, nusefulconss); 5182 5183 /* creating all necessary data in array structure, collect all clique constraint variables and occurrences */ 5184 SCIP_CALL( collectCliqueData(scip, usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs, &maxnvars) ); 5185 assert(maxnvars > 0); 5186 5187 /* allocate temporary memory for actual clique */ 5188 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, maxnvars) ); 5189 /* allocate temporary memory for counting an overlap of variables */ 5190 SCIP_CALL( SCIPallocBufferArray(scip, &countofoverlapping, nusefulconss) ); 5191 5192 /* sort usefulvars after indices of variables, negated and active counterparts will stand side by side */ 5193 SCIPsortDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, nusefulvars); 5194 5195 /* extend cliques/constraints by checking whether some variables of a second constraint are in the same clique */ 5196 for( c = nusefulconss - 1; c >= 0 && !SCIPisStopped(scip); --c ) 5197 { 5198 SCIP_VAR** cons0vars; /* these are the clique variables */ 5199 SCIP_CONS* cons0; 5200 int ncons0vars; 5201 SCIP_VAR* var0; 5202 int v1; 5203 int nadded; /* number of possible added variables to constraint */ 5204 int cons0fixedzeros; 5205 int oldnchgcoefs; 5206 #ifndef NDEBUG 5207 const int oldnaggrvars = *naggrvars; 5208 #endif 5209 cons0 = usefulconss[c]; 5210 5211 if( !SCIPconsIsActive(cons0) ) 5212 continue; 5213 5214 /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if 5215 * possible 5216 */ 5217 SCIP_CALL( presolvePropagateCons(scip, cons0, FALSE, undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations, nfixedvars, naggrvars, ndelconss, cutoff) ); 5218 5219 if( *cutoff ) 5220 break; 5221 5222 /* we can't handle aggregated variables later on so we should have saved them for later */ 5223 assert(*naggrvars == oldnaggrvars); 5224 5225 if( !SCIPconsIsActive(cons0) ) 5226 continue; 5227 5228 /* we need to determine the cliquedata in each iteration because we eventual will change it later */ 5229 consdata = SCIPconsGetData(cons0); 5230 assert(consdata != NULL); 5231 5232 cons0vars = consdata->vars; 5233 ncons0vars = consdata->nvars; 5234 5235 /* sorting array after indices of variables, negated and active counterparts will stand side by side */ 5236 SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars); 5237 /* standard setppc-sorting now lost */ 5238 consdata->sorted = FALSE; 5239 5240 /* clique array should be long enough */ 5241 assert(maxnvars >= ncons0vars); 5242 5243 /* clear old entries in overlapping constraint */ 5244 BMSclearMemoryArray(countofoverlapping, nusefulconss); 5245 5246 /* calculate overlapping */ 5247 for( v = ncons0vars - 1; v >= 0 ; --v ) 5248 { 5249 var0 = cons0vars[v]; 5250 5251 /* fixed variables later to the count */ 5252 if( SCIPvarGetLbLocal(var0) > 0.5 || SCIPvarGetUbLocal(var0) < 0.5 ) 5253 continue; 5254 5255 assert(SCIPhashmapExists(vartoindex, (void*) var0)); 5256 5257 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var0); 5258 for( v1 = varnconss[varindex] - 1; v1 >= 0 ; --v1 ) 5259 ++(countofoverlapping[varconsidxs[varindex][v1]]); 5260 } 5261 5262 oldnchgcoefs = *nchgcoefs; 5263 cons0fixedzeros = consdata->nfixedzeros; 5264 5265 chgcons0 = FALSE; 5266 5267 /* check for overlapping constraint before starting lifting */ 5268 SCIP_CALL( checkForOverlapping(scip, cons0, c, c, usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex, 5269 varnconss, maxnvarconsidx, varconsidxs, countofoverlapping, conshdlrdata->cliqueshrinking, &chgcons0, 5270 undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations, 5271 nfixedvars, naggrvars, nchgcoefs, ndelconss, cutoff) ); 5272 5273 if( *cutoff ) 5274 break; 5275 5276 /* we can't handle aggregated variables later on so we should have saved them for later */ 5277 assert(*naggrvars == oldnaggrvars); 5278 5279 /* if cons0 changed, we need to reorder the variables */ 5280 if( chgcons0 && *nchgcoefs > oldnchgcoefs ) 5281 { 5282 consdata = SCIPconsGetData(cons0); 5283 assert(consdata != NULL); 5284 5285 cons0vars = consdata->vars; 5286 ncons0vars = consdata->nvars; 5287 5288 /* sorting array after indices of variables, negated and active counterparts will stand side by side */ 5289 SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars); 5290 /* standard setppc-sorting now lost */ 5291 consdata->sorted = FALSE; 5292 } 5293 5294 /* check cons0 again for redundancy/fixings, because due to fixings in all other constraints it might happen that cons0 is redundant now */ 5295 if( consdata->nfixedones > 0 || consdata->nfixedzeros > cons0fixedzeros ) 5296 { 5297 /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if 5298 * possible 5299 */ 5300 SCIP_CALL( presolvePropagateCons(scip, cons0, FALSE, undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations, nfixedvars, naggrvars, ndelconss, cutoff) ); 5301 5302 if( *cutoff ) 5303 break; 5304 5305 /* we can't handle aggregated variables later on so we should have saved them for later */ 5306 assert(*naggrvars == oldnaggrvars); 5307 5308 if( !SCIPconsIsActive(cons0) ) 5309 continue; 5310 } 5311 5312 nadded = 0; 5313 5314 /* iterate over the cliques variables and all possible new clique variables at the "same" time, determine starting 5315 * index 5316 * 5317 * @note: it might be better to start the first round with our computed v1, but maybe it's better to switch to 5318 * trying to add all variables the second time for set packing constraints 5319 */ 5320 5321 /* we try to add all variables to the partitioning constraints, to try to fix as much as possible */ 5322 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/ 5323 v1 = nusefulvars - 1; 5324 else 5325 { 5326 /* if we already ran a presolving round we want to try to add new variables */ 5327 if( conshdlrdata->nclqpresolve > 0 ) 5328 v1 = nusefulvars - 1; 5329 else 5330 { 5331 /* find start position of variable which we will try to add to our constraint, so we will get better clique constraints */ 5332 (void) SCIPsortedvecFindDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, (void*)cons0vars[ncons0vars - 1], nusefulvars, &v1); 5333 assert(v1 >= 0 && v1 < nusefulvars); 5334 /* if constraint is not merged and we found a variable which is negated the same as it's neighbour we have to 5335 * increase v1 to make sure that we don't loose this important variable */ 5336 if( v1 + 1 < nusefulvars && ((SCIPvarIsNegated(usefulvars[v1 + 1]) && SCIPvarGetNegatedVar(usefulvars[v1 + 1]) == usefulvars[v1]) || (SCIPvarIsNegated(usefulvars[v1]) && SCIPvarGetNegatedVar(usefulvars[v1]) == usefulvars[v1 + 1])) ) 5337 ++v1; 5338 } 5339 } 5340 5341 assert(maxnvars >= ncons0vars); 5342 /* initialize the cliquevalues array */ 5343 for( v = ncons0vars - 1; v >= 0; --v ) 5344 { 5345 if( SCIPvarGetLbLocal(cons0vars[v]) < 0.5 && SCIPvarGetUbLocal(cons0vars[v]) > 0.5 ) 5346 { 5347 /* variable has to be either active or a negated variable of an active one */ 5348 assert(SCIPvarIsActive(cons0vars[v]) || (SCIPvarGetStatus(cons0vars[v]) == SCIP_VARSTATUS_NEGATED && 5349 SCIPvarIsActive(SCIPvarGetNegationVar(cons0vars[v])))); 5350 cliquevalues[v] = SCIPvarIsActive(cons0vars[v]) ? TRUE : FALSE; 5351 } 5352 } 5353 5354 chgcons0 = FALSE; 5355 5356 /* try to lift variables to cons0 */ 5357 SCIP_CALL( liftCliqueVariables(scip, cons0, c, usefulvars, &nusefulvars, v1, &cliquevalues, vartoindex, varnconss, 5358 maxnvarconsidx, varconsidxs, &maxnvars, &nadded, &chgcons0, nfixedvars, ndelconss, cutoff) ); 5359 5360 if( *cutoff ) 5361 break; 5362 5363 if( !SCIPconsIsActive(cons0) ) 5364 continue; 5365 5366 /* check for redundant constraints due to changing cons0 */ 5367 if( chgcons0 ) 5368 { 5369 int i; 5370 5371 *firstchange = MIN(*firstchange, c); 5372 *firstclique = MIN(*firstclique, c); 5373 *lastclique = MAX(*lastclique, c); 5374 5375 /* variables array has changed due to lifting variables, so get new values */ 5376 assert(consdata == SCIPconsGetData(cons0)); 5377 cons0vars = consdata->vars; 5378 ncons0vars = consdata->nvars; 5379 5380 /* resorting array, because we added new variables, in order of indices of variables, negated 5381 * and active counterparts would stand side by side 5382 */ 5383 SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars); 5384 /* standard setppc-sorting now lost */ 5385 consdata->sorted = FALSE; 5386 5387 /* clear old entries in overlapping constraint */ 5388 BMSclearMemoryArray(countofoverlapping, nusefulconss); 5389 5390 for( v = ncons0vars - 1; v >= 0 ; --v ) 5391 { 5392 var0 = cons0vars[v]; 5393 5394 /* fixed variables later to the count */ 5395 if( SCIPvarGetLbLocal(var0) > 0.5 || SCIPvarGetUbLocal(var0) < 0.5 ) 5396 continue; 5397 5398 assert(SCIPhashmapExists(vartoindex, (void*) var0)); 5399 5400 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var0); 5401 for( i = varnconss[varindex] - 1; i >= 0 ; --i ) 5402 ++(countofoverlapping[varconsidxs[varindex][i]]); 5403 } 5404 5405 chgcons0 = FALSE; 5406 5407 /* check for overlapping constraint after lifting, in the first round we will only check up front */ 5408 SCIP_CALL( checkForOverlapping(scip, cons0, c, (conshdlrdata->nclqpresolve > 0) ? nusefulconss : c, 5409 usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs, 5410 countofoverlapping, conshdlrdata->cliqueshrinking, &chgcons0, 5411 undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations, 5412 nfixedvars, naggrvars, nchgcoefs, ndelconss, cutoff) ); 5413 5414 if( *cutoff ) 5415 break; 5416 5417 /* we can't handle aggregated variables later on so we should have saved them for later */ 5418 assert(*naggrvars == oldnaggrvars); 5419 } 5420 } 5421 5422 TERMINATE: 5423 SCIPfreeBufferArrayNull(scip, &countofoverlapping); 5424 SCIPfreeBufferArrayNull(scip, &cliquevalues); 5425 5426 /* free temporary memory for constraints, variables and the mapping between them in reverse order as they were 5427 * allocated 5428 */ 5429 for( c = nusefulvars; c > 0; --c ) 5430 { 5431 if( varconsidxs[c] != NULL ) 5432 { 5433 SCIPfreeBufferArrayNull(scip, &(varconsidxs[c])); 5434 } 5435 } 5436 5437 SCIPfreeBufferArray(scip, &varconsidxs); 5438 SCIPfreeBufferArray(scip, &maxnvarconsidx); 5439 SCIPfreeBufferArray(scip, &varnconss); 5440 SCIPfreeBufferArray(scip, &usefulvars); 5441 SCIPfreeBufferArray(scip, &usefulconss); 5442 5443 /* perform all collected aggregations */ 5444 if( !*cutoff && naggregations > 0 && !SCIPdoNotAggr(scip) ) 5445 { 5446 SCIP_CALL( performAggregations(scip, conshdlrdata, undoneaggrvars, undoneaggrtypes, naggregations, naggrvars, cutoff) ); 5447 } 5448 5449 /* free temporary memory for the aggregation storage */ 5450 SCIPfreeBufferArray(scip, &undoneaggrtypes); 5451 SCIPfreeBufferArray(scip, &undoneaggrvars); 5452 5453 /* free hashmap */ 5454 SCIPhashmapFree(&vartoindex); 5455 5456 if( *ndelconss < 0 ) 5457 *ndelconss = 0; 5458 5459 return SCIP_OKAY; 5460 } 5461 5462 5463 /** add cliques to SCIP */ 5464 static 5465 SCIP_RETCODE addCliques( 5466 SCIP* scip, /**< SCIP data structure */ 5467 SCIP_CONS** conss, /**< constraint set */ 5468 int nconss, /**< number of constraints in constraint set */ 5469 int firstclique, /**< first constraint to start to add cliques */ 5470 int lastclique, /**< last constraint to start to add cliques */ 5471 int* naddconss, /**< pointer to count number of added constraints */ 5472 int* ndelconss, /**< pointer to count number of deleted constraints */ 5473 int* nchgbds, /**< pointer to count number of changed bounds */ 5474 SCIP_Bool* cutoff /**< pointer to store if the problem is infeasible due to a fixing */ 5475 ) 5476 { 5477 SCIP_CONS* cons; 5478 SCIP_CONSDATA* consdata; 5479 SCIP_Bool infeasible; 5480 int nlocalbdchgs; 5481 int c; 5482 5483 assert(scip != NULL); 5484 assert(firstclique >= 0); 5485 assert(lastclique <= nconss); 5486 assert(conss != NULL || ((nconss == 0) && (lastclique == 0))); 5487 5488 /* add clique and implication information */ 5489 for( c = firstclique; c < lastclique; ++c ) 5490 { 5491 cons = conss[c]; /*lint !e613*/ 5492 assert(cons != NULL); 5493 5494 /* ignore deleted constraints */ 5495 if( !SCIPconsIsActive(cons) ) 5496 continue; 5497 5498 nlocalbdchgs = 0; 5499 SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, &nlocalbdchgs, cutoff) ); 5500 *nchgbds += nlocalbdchgs; 5501 5502 if( *cutoff ) 5503 return SCIP_OKAY; 5504 5505 consdata = SCIPconsGetData(cons); 5506 assert(consdata != NULL); 5507 5508 if( SCIPconsIsDeleted(cons) ) 5509 continue; 5510 5511 if( !consdata->cliqueadded && consdata->nvars >= 2 ) 5512 { 5513 /* add a set partitioning / packing constraint as clique */ 5514 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) 5515 { 5516 SCIP_CALL( SCIPaddClique(scip, consdata->vars, NULL, consdata->nvars, 5517 ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING), &infeasible, &nlocalbdchgs) ); 5518 *nchgbds += nlocalbdchgs; 5519 5520 if( infeasible ) 5521 { 5522 *cutoff = TRUE; 5523 return SCIP_OKAY; 5524 } 5525 } 5526 else if( consdata->nvars == 2 && !SCIPconsIsModifiable(cons) ) 5527 { 5528 /* a two-variable set covering constraint x + y >= 1 yields the implication x == 0 -> y == 1 */ 5529 SCIP_CALL( SCIPaddVarImplication(scip, consdata->vars[0], FALSE, consdata->vars[1], 5530 SCIP_BOUNDTYPE_LOWER, 1.0, &infeasible, &nlocalbdchgs) ); 5531 *nchgbds += nlocalbdchgs; 5532 5533 if( infeasible ) 5534 { 5535 *cutoff = TRUE; 5536 return SCIP_OKAY; 5537 } 5538 } 5539 consdata->cliqueadded = TRUE; 5540 } 5541 } 5542 5543 return SCIP_OKAY; 5544 } 5545 5546 /** perform multi-aggregation on variables resulting from a set-partitioning/-packing constraint */ 5547 static 5548 SCIP_RETCODE multiAggregateBinvar( 5549 SCIP* scip, /**< SCIP data structure */ 5550 SCIP_Bool linearconshdlrexist,/**< does the linear constraint handler exist, necessary for multi-aggregations */ 5551 SCIP_VAR** vars, /**< all variables including the variable to which will be multi-aggregated */ 5552 int nvars, /**< number of all variables */ 5553 int pos, /**< position of variable for multi-aggregation */ 5554 SCIP_Bool* infeasible, /**< pointer to store infeasibility status of aggregation */ 5555 SCIP_Bool* aggregated /**< pointer to store aggregation status */ 5556 ) 5557 { 5558 SCIP_VAR** tmpvars; 5559 SCIP_Real* scalars; 5560 int v; 5561 5562 assert(scip != NULL); 5563 assert(vars != NULL); 5564 assert(nvars > 1); 5565 assert(0 <= pos && pos < nvars); 5566 assert(infeasible != NULL); 5567 assert(aggregated != NULL); 5568 5569 if( nvars == 2 ) 5570 { 5571 SCIP_Bool redundant; 5572 5573 /* perform aggregation on variables resulting from a set-packing constraint */ 5574 SCIP_CALL( SCIPaggregateVars(scip, vars[pos], vars[nvars - pos - 1], 1.0, 1.0, 1.0, infeasible, &redundant, aggregated) ); 5575 5576 if( *aggregated ) 5577 SCIPdebugMsg(scip, "aggregated %s = 1 - %s\n", SCIPvarGetName(vars[pos]), SCIPvarGetName(vars[nvars - pos - 1])); 5578 5579 return SCIP_OKAY; 5580 } 5581 5582 if( !linearconshdlrexist ) 5583 { 5584 *infeasible = FALSE; 5585 return SCIP_OKAY; 5586 } 5587 5588 /* if the last variable will be multi-aggregated, we do not need to copy the variables */ 5589 if( pos == nvars - 1 ) 5590 tmpvars = vars; 5591 else 5592 { 5593 /* copy variables for aggregation */ 5594 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) ); 5595 tmpvars[pos] = tmpvars[nvars - 1]; 5596 } 5597 5598 SCIP_CALL( SCIPallocBufferArray(scip, &scalars, nvars - 1) ); 5599 /* initialize scalars */ 5600 for( v = nvars - 2; v >= 0; --v ) 5601 scalars[v] = -1.0; 5602 5603 SCIPdebugMsg(scip, "multi-aggregating binary variable <%s> (locks: [%d,%d]; to %d variables)\n", 5604 SCIPvarGetName(vars[pos]), SCIPvarGetNLocksDownType(vars[pos], SCIP_LOCKTYPE_MODEL), 5605 SCIPvarGetNLocksUpType(vars[pos], SCIP_LOCKTYPE_MODEL), nvars - 1); 5606 5607 /* perform multi-aggregation */ 5608 SCIP_CALL( SCIPmultiaggregateVar(scip, vars[pos], nvars - 1, tmpvars, scalars, 1.0, infeasible, aggregated) ); 5609 assert(!(*infeasible)); 5610 5611 SCIPfreeBufferArray(scip, &scalars); 5612 5613 if( pos < nvars - 1 ) 5614 { 5615 assert(tmpvars != vars); 5616 SCIPfreeBufferArray(scip, &tmpvars); 5617 } 5618 5619 return SCIP_OKAY; 5620 } 5621 5622 /** determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and negated) 5623 * in any combination of set-partitioning and set-packing constraints 5624 * 5625 * we can multi-aggregate the variable and either change the set-partitioning constraint to a set-packing constraint or 5626 * even delete it 5627 * 5628 * 1. c1: x + y + z = 1, uplocks(x) = 1, downlocks(x) = 1 => x = 1 - y - z and change c1 to y + z <= 1 5629 * 5630 * 2. c2: x + y + z <= 1, uplocks(x) = 1, downlocks(x) = 0, obj(x) < 0 => x = 1 - y - z and change c2 to y + z <= 1 5631 * 5632 * 3. d1: x + y + z <= 1 and d2: ~x + u + v <= 1, uplocks(x) = 1, downlocks(x) = 1 5633 * a) obj(x) <= 0 => x = 1 - y - z and delete d1 5634 * b) obj(x) > 0 => ~x = 1 - u - v and delete d2 5635 * 5636 * 4. e1: x + y + z == 1 and e2: ~x + u + v (<= or ==) 1, uplocks(x) = (1 or 2), downlocks(x) = 2 5637 * => x = 1 - y - z and delete e1 5638 * 5639 * we can also aggregate a variable in a set-packing constraint with only two variables when the uplocks are equal to 5640 * one and then delete this constraint 5641 * 5642 * 5. f1: x + y <= 1, uplocks(x) = 1, obj(x) <= 0 => x = 1 - y and delete f1 5643 * 5644 * @todo might want to multi-aggregate variables even with more locks, when the fill in is still smaller or equal to 5645 * the old number of non-zeros, e.g. 5646 * 5647 * x + y + z = 1 5648 * ~x + u + v <=/= 1 5649 * ~x + w <= 1 5650 */ 5651 static 5652 SCIP_RETCODE removeDoubleAndSingletonsAndPerformDualpresolve( 5653 SCIP* scip, /**< SCIP data structure */ 5654 SCIP_CONS** conss, /**< constraint set */ 5655 int nconss, /**< number of constraints in constraint set */ 5656 SCIP_Bool dualpresolvingenabled,/**< is dual presolving enabled */ 5657 SCIP_Bool linearconshdlrexist,/**< does the linear constraint handler exist, necessary for 5658 * multi-aggregations 5659 */ 5660 int* nfixedvars, /**< pointer to count number of deleted variables */ 5661 int* naggrvars, /**< pointer to count number of aggregated variables */ 5662 int* ndelconss, /**< pointer to count number of deleted constraints */ 5663 int* nchgcoefs, /**< pointer to count number of changed coefficients */ 5664 int* nchgsides, /**< pointer to count number of changed left hand sides */ 5665 SCIP_Bool* cutoff /**< pointer to store if a cut off was detected */ 5666 ) 5667 { 5668 SCIP_CONS** usefulconss; 5669 SCIP_VAR** binvars; 5670 SCIP_HASHMAP* vartoindex; 5671 SCIP_Bool* chgtype; 5672 int* considxs; 5673 int* posincons; 5674 SCIP_Bool infeasible; 5675 SCIP_Bool aggregated; 5676 SCIP_Bool donotaggr; 5677 SCIP_Bool donotmultaggr; 5678 SCIP_Bool mustcheck; 5679 SCIP_Bool addcut; 5680 int nposvars; 5681 int ndecs; 5682 int nbinvars; 5683 int nposbinvars; 5684 int nuplocks; 5685 int ndownlocks; 5686 #ifndef NDEBUG 5687 int posreplacements = 0; 5688 #endif 5689 int nhashmapentries; 5690 int nlocaladdconss; 5691 int v; 5692 int c; 5693 5694 assert(scip != NULL); 5695 assert(conss != NULL); 5696 assert(nconss > 0); 5697 assert(nfixedvars != NULL); 5698 assert(naggrvars != NULL); 5699 assert(ndelconss != NULL); 5700 assert(nchgcoefs != NULL); 5701 assert(nchgsides != NULL); 5702 5703 nbinvars = SCIPgetNBinVars(scip); 5704 nposbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip); 5705 assert(nbinvars + SCIPgetNIntVars(scip) + SCIPgetNImplVars(scip) == nposbinvars); 5706 5707 binvars = SCIPgetVars(scip); 5708 5709 /* determine number for possible multi-aggregations */ 5710 nposvars = 0; 5711 for( v = nposbinvars - 1; v >= 0; --v ) 5712 { 5713 assert(SCIPvarGetType(binvars[v]) != SCIP_VARTYPE_CONTINUOUS); 5714 5715 if( v < nbinvars || SCIPvarIsBinary(binvars[v]) ) 5716 { 5717 nuplocks = SCIPvarGetNLocksUpType(binvars[v], SCIP_LOCKTYPE_MODEL); 5718 ndownlocks = SCIPvarGetNLocksDownType(binvars[v], SCIP_LOCKTYPE_MODEL); 5719 5720 if( (nuplocks == 1 && ndownlocks <= 1) || (nuplocks <= 1 && ndownlocks == 1) || (nuplocks <= 2 && ndownlocks <= 2 && SCIPvarGetNegatedVar(binvars[v]) != NULL) ) 5721 ++nposvars; 5722 } 5723 } 5724 5725 SCIPdebugMsg(scip, "found %d binary variables for possible multi-aggregation\n", nposvars); 5726 5727 if( nposvars == 0 ) 5728 return SCIP_OKAY; 5729 5730 /* a hashmap from var to index when found in a set-partitioning constraint */ 5731 SCIP_CALL( SCIPhashmapCreate(&vartoindex, SCIPblkmem(scip), nposvars) ); 5732 5733 /* get temporary memory */ 5734 SCIP_CALL( SCIPallocBufferArray(scip, &chgtype, nconss) ); 5735 BMSclearMemoryArray(chgtype, nconss); 5736 5737 SCIP_CALL( SCIPallocBufferArray(scip, &considxs, nposbinvars) ); 5738 SCIP_CALL( SCIPallocBufferArray(scip, &posincons, nposbinvars) ); 5739 5740 SCIP_CALL( SCIPduplicateBufferArray(scip, &usefulconss, conss, nconss) ); 5741 /* sort constraints */ 5742 SCIPsortPtr((void**)usefulconss, setppcConssSort2, nconss); 5743 5744 nhashmapentries = 0; 5745 ndecs = 0; 5746 donotaggr = SCIPdoNotAggr(scip); 5747 donotmultaggr = SCIPdoNotMultaggr(scip); 5748 assert(!donotaggr || !donotmultaggr); 5749 5750 /* determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and 5751 * negated) in any combination of set-partitioning and set-packing constraints 5752 * 5753 * we can multi-aggregate the variable and either change the set-partitioning constraint to a set-packing constraint 5754 * or even delete it 5755 */ 5756 for( c = 0; c < nconss; ++c ) 5757 { 5758 SCIP_CONS* cons; 5759 SCIP_CONSDATA* consdata; 5760 int oldnfixedvars; 5761 nlocaladdconss = 0; 5762 5763 cons = usefulconss[c]; 5764 assert(cons != NULL); 5765 5766 if( SCIPconsIsDeleted(cons) ) 5767 continue; 5768 5769 consdata = SCIPconsGetData(cons); 5770 assert(consdata != NULL); 5771 5772 /* if we cannot find any constraint to perform a useful multi-aggregation, stop */ 5773 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) 5774 break; 5775 5776 if( !SCIPconsIsChecked(cons) ) 5777 continue; 5778 5779 if( SCIPconsIsModifiable(cons) ) 5780 continue; 5781 5782 /* update the variables */ 5783 SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) ); 5784 5785 if( *cutoff ) 5786 break; 5787 5788 /* due to resolving multi-aggregations a constraint can become deleted */ 5789 if( SCIPconsIsDeleted(cons) ) 5790 continue; 5791 5792 SCIP_CALL( processFixings(scip, cons, cutoff, nfixedvars, &addcut, &mustcheck) ); 5793 assert(!addcut); 5794 5795 if( *cutoff ) 5796 break; 5797 5798 if( SCIPconsIsDeleted(cons) ) 5799 continue; 5800 5801 oldnfixedvars = *nfixedvars; 5802 5803 /* merging unmerged constraints */ 5804 SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, cutoff) ); 5805 5806 if( *cutoff ) 5807 break; 5808 5809 if( SCIPconsIsDeleted(cons) ) 5810 continue; 5811 5812 if( oldnfixedvars < *nfixedvars ) 5813 { 5814 /* update the variables */ 5815 SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) ); 5816 assert(!SCIPconsIsDeleted(cons)); 5817 assert(nlocaladdconss == 0); 5818 assert(!*cutoff); 5819 5820 if( SCIPconsIsDeleted(cons) ) 5821 continue; 5822 } 5823 5824 /* if the constraint was not merged and consists of a variable with its negation, the constraint is redundant */ 5825 if( consdata->nvars < 2 ) 5826 { 5827 /* deleting redundant set-packing constraint */ 5828 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) 5829 { 5830 SCIPdebugMsg(scip, "deleting redundant set-packing constraint <%s>\n", SCIPconsGetName(cons)); 5831 5832 SCIP_CALL( SCIPdelCons(scip, cons) ); 5833 ++(*ndelconss); 5834 5835 continue; 5836 } 5837 else 5838 { 5839 SCIP_Bool fixed; 5840 5841 assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING); 5842 5843 if( consdata->nvars == 0 ) 5844 { 5845 SCIPdebugMsg(scip, "empty set partition constraint <%s> led to infeasibility\n", SCIPconsGetName(cons)); 5846 5847 *cutoff = TRUE; 5848 break; 5849 } 5850 5851 SCIPdebugMsg(scip, "fixing <%s> to 1 because this variable is the last variable in a set partition constraint <%s>\n", SCIPvarGetName(consdata->vars[0]), SCIPconsGetName(cons)); 5852 5853 SCIP_CALL( SCIPfixVar(scip, consdata->vars[0], 1.0, &infeasible, &fixed) ); 5854 assert(!infeasible); 5855 5856 if( fixed ) 5857 ++(*nfixedvars); 5858 5859 assert(SCIPvarGetLbGlobal(consdata->vars[0]) > 0.5); 5860 5861 SCIPdebugMsg(scip, "deleting redundant set-partition constraint <%s>\n", SCIPconsGetName(cons)); 5862 5863 SCIP_CALL( SCIPdelCons(scip, cons) ); 5864 ++(*ndelconss); 5865 5866 continue; 5867 } 5868 } 5869 5870 /* perform dualpresolve on set-packing constraints with exactly two variables */ 5871 if( !donotaggr && consdata->nvars == 2 && dualpresolvingenabled && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) 5872 { 5873 SCIP_VAR* var; 5874 SCIP_Real objval; 5875 SCIP_Bool redundant; 5876 5877 var = consdata->vars[0]; 5878 assert(var != NULL); 5879 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); 5880 5881 SCIP_CALL( SCIPvarGetAggregatedObj(var, &objval) ); 5882 5883 nuplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL); 5884 5885 if( nuplocks == 1 && objval <= 0 ) 5886 { 5887 /* perform aggregation on variables resulting from a set-packing constraint */ 5888 SCIP_CALL( SCIPaggregateVars(scip, var, consdata->vars[1], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) ); 5889 5890 if( infeasible ) 5891 { 5892 *cutoff = TRUE; 5893 break; 5894 } 5895 5896 if( aggregated ) 5897 { 5898 SCIPdebugMsg(scip, "dualpresolve, aggregated %s + %s = 1, in set-packing constraint %s\n", SCIPvarGetName(var), SCIPvarGetName(consdata->vars[1]), SCIPconsGetName(cons)); 5899 ++(*naggrvars); 5900 5901 SCIP_CALL( SCIPdelCons(scip, cons) ); 5902 ++(*ndelconss); 5903 } 5904 5905 continue; 5906 } 5907 else 5908 { 5909 var = consdata->vars[1]; 5910 assert(var != NULL); 5911 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); 5912 5913 SCIP_CALL( SCIPvarGetAggregatedObj(var, &objval) ); 5914 5915 nuplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL); 5916 5917 if( nuplocks == 1 && objval <= 0 ) 5918 { 5919 /* perform aggregation on variables resulting from a set-packing constraint */ 5920 SCIP_CALL( SCIPaggregateVars(scip, var, consdata->vars[0], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) ); 5921 5922 if( infeasible ) 5923 { 5924 *cutoff = TRUE; 5925 break; 5926 } 5927 5928 if( aggregated ) 5929 { 5930 SCIPdebugMsg(scip, "dualpresolve, aggregated %s + %s = 1, in set-packing constraint %s\n", SCIPvarGetName(var), SCIPvarGetName(consdata->vars[0]), SCIPconsGetName(cons)); 5931 ++(*naggrvars); 5932 5933 SCIP_CALL( SCIPdelCons(scip, cons) ); 5934 ++(*ndelconss); 5935 } 5936 5937 continue; 5938 } 5939 } 5940 } 5941 else if( !donotaggr && consdata->nvars == 2 && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) 5942 { 5943 SCIP_Bool redundant; 5944 5945 /* perform aggregation on variables resulting from a set-partitioning constraint */ 5946 SCIP_CALL( SCIPaggregateVars(scip, consdata->vars[0], consdata->vars[1], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) ); 5947 5948 if( infeasible ) 5949 { 5950 *cutoff = TRUE; 5951 break; 5952 } 5953 5954 if( aggregated ) 5955 { 5956 SCIPdebugMsg(scip, "aggregated %s + %s = 1, in set-partition constraint %s\n", SCIPvarGetName(consdata->vars[0]), SCIPvarGetName(consdata->vars[1]), SCIPconsGetName(cons)); 5957 ++(*naggrvars); 5958 5959 SCIP_CALL( SCIPdelCons(scip, cons) ); 5960 ++(*ndelconss); 5961 } 5962 5963 continue; 5964 } 5965 5966 /* we already found all possible variables for multi-aggregation */ 5967 if( ndecs >= nposvars ) 5968 continue; 5969 5970 /* no multi aggregation is allowed, so we can continue */ 5971 if( donotmultaggr ) 5972 continue; 5973 5974 /* if the following condition does not hold, we have an unmerged constraint, and we might need to merge it first */ 5975 assert(nposbinvars >= consdata->nvars); 5976 5977 /* search for possible variables for multi-aggregation */ 5978 for( v = consdata->nvars - 1; v >= 0; --v ) 5979 { 5980 SCIP_VAR* var; 5981 SCIP_CONS* constoupdate; 5982 int deleteconsindex = -1; 5983 5984 constoupdate = cons; 5985 var = consdata->vars[v]; 5986 assert(var != NULL); 5987 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); 5988 assert(!SCIPconsIsDeleted(cons)); 5989 5990 aggregated = FALSE; 5991 nuplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL); 5992 ndownlocks = SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL); 5993 assert(nuplocks >= 1 && ndownlocks >= 0); /* we are only treating set partitioning and set packing constraints, so every variable in there should have an uplock */ 5994 5995 if( dualpresolvingenabled && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING && nuplocks <= 1 && nuplocks + ndownlocks <= 2 ) 5996 { 5997 assert(nuplocks == 1 && ndownlocks <= 1); 5998 5999 /* we found a redundant variable in a set-partitioning constraint */ 6000 if( ndownlocks == 0 ) 6001 { 6002 SCIP_Real objval; 6003 6004 SCIP_CALL( SCIPvarGetAggregatedObj(var, &objval) ); 6005 6006 /* if the objective value is >= 0 the fixing is normally done by the dualfix presolver */ 6007 if( !SCIPisNegative(scip, objval) ) 6008 { 6009 SCIP_Bool fixed; 6010 6011 SCIPdebugMsg(scip, "dual-fixing of variable <%s> to 0.0\n", SCIPvarGetName(var)); 6012 6013 SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) ); 6014 assert(!infeasible); 6015 assert(fixed); 6016 6017 ++(*nfixedvars); 6018 } 6019 else 6020 { 6021 SCIPdebugMsg(scip, "multi-aggregating in set-packing constraint\n"); 6022 6023 /* perform aggregation on variables resulting from a set-packing constraint */ 6024 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) ); 6025 6026 if( infeasible ) 6027 { 6028 *cutoff = TRUE; 6029 break; 6030 } 6031 } 6032 6033 ++ndecs; 6034 } 6035 else if( ndownlocks == 1 && SCIPvarGetNegatedVar(var) != NULL ) 6036 { 6037 SCIP_CONSDATA* aggrconsdata; 6038 SCIP_VAR* negvar; 6039 SCIP_VAR* activevar; 6040 SCIP_Real objval; 6041 int multaggridx; 6042 int notmultaggridx; 6043 int image; 6044 int consindex; 6045 int varindex; 6046 6047 assert(!SCIPhashmapExists(vartoindex, (void*) var)); 6048 6049 negvar = SCIPvarGetNegatedVar(var); 6050 6051 /* if we found a new variable add it to the data */ 6052 if( !SCIPhashmapExists(vartoindex, (void*) negvar) ) 6053 { 6054 ++nhashmapentries; 6055 SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) var, nhashmapentries) ); 6056 6057 considxs[nhashmapentries - 1] = c; 6058 posincons[nhashmapentries - 1] = v; 6059 6060 #ifndef NDEBUG 6061 ++posreplacements; 6062 #endif 6063 continue; 6064 } 6065 6066 assert(SCIPhashmapExists(vartoindex, (void*) negvar)); 6067 image = SCIPhashmapGetImageInt(vartoindex, (void*) negvar); 6068 assert(image > 0 && image <= nhashmapentries); 6069 6070 consindex = considxs[image - 1]; 6071 assert(0 <= consindex && consindex < nconss); 6072 6073 /* if the following assert fails, the constraint was not merged, or something really strange happened */ 6074 assert(consindex < c); 6075 6076 ++ndecs; 6077 #ifndef NDEBUG 6078 --posreplacements; 6079 #endif 6080 assert(posreplacements >= 0); 6081 6082 varindex = posincons[image - 1]; 6083 considxs[image - 1] = -1; 6084 posincons[image - 1] = -1; 6085 SCIP_CALL( SCIPhashmapRemove(vartoindex, (void*) negvar) ); 6086 6087 /* if two variables in one constraint might be multi-aggregated, it might happen that this constraint was already removed */ 6088 if( SCIPconsIsDeleted(usefulconss[consindex]) ) 6089 continue; 6090 6091 aggrconsdata = SCIPconsGetData(usefulconss[consindex]); 6092 assert(aggrconsdata != NULL); 6093 assert((SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PACKING); 6094 assert(0 <= varindex); 6095 6096 /* it might be that due to other multi-aggregations the constraint has fewer variables than when we 6097 * remembered the position, therefore we need to find the variable again 6098 */ 6099 if( varindex >= aggrconsdata->nvars || aggrconsdata->vars[varindex] != negvar ) 6100 { 6101 int v2; 6102 6103 /* if the following assert is raised, then the constraint is redundant and we do not need to aggregate 6104 * anymore and can delete this constraint 6105 */ 6106 assert(aggrconsdata->nvars >= 2); 6107 6108 for( v2 = aggrconsdata->nvars - 1; v2 >= 0; --v2 ) 6109 { 6110 if( aggrconsdata->vars[v2] == negvar ) 6111 break; 6112 } 6113 assert(v2 >= 0); 6114 6115 varindex = v2; 6116 } 6117 assert(0 <= varindex && varindex < aggrconsdata->nvars); 6118 assert(aggrconsdata->vars[varindex] == negvar); 6119 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(negvar) == SCIP_VARSTATUS_NEGATED); 6120 6121 /* determine active variable and constraint that corresponds to */ 6122 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED ) 6123 { 6124 activevar = negvar; 6125 multaggridx = consindex; 6126 notmultaggridx = c; 6127 } 6128 else 6129 { 6130 activevar = var; 6131 multaggridx = c; 6132 notmultaggridx = consindex; 6133 } 6134 objval = SCIPvarGetObj(activevar); 6135 6136 SCIPdebugMsg(scip, "multi-aggregating in two set-packing constraint\n"); 6137 6138 if( objval <= 0.0 ) 6139 { 6140 /* perform aggregation on variables resulting from a set-packing constraint */ 6141 if( multaggridx == c ) 6142 { 6143 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) ); 6144 } 6145 else 6146 { 6147 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, aggrconsdata->vars, aggrconsdata->nvars, varindex, &infeasible, &aggregated) ); 6148 } 6149 deleteconsindex = multaggridx; 6150 } 6151 else 6152 { 6153 /* perform aggregation on variables resulting from a set-packing constraint */ 6154 /* coverity[copy_paste_error] */ 6155 if( multaggridx == c ) 6156 { 6157 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, aggrconsdata->vars, aggrconsdata->nvars, varindex, &infeasible, &aggregated) ); 6158 } 6159 else 6160 { 6161 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) ); 6162 } 6163 deleteconsindex = notmultaggridx; 6164 } 6165 6166 if( infeasible ) 6167 { 6168 *cutoff = TRUE; 6169 break; 6170 } 6171 6172 assert(deleteconsindex >= 0 && deleteconsindex <= c); 6173 } 6174 } 6175 /* we found a redundant variable in a set-partitioning constraint */ 6176 else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && nuplocks == 1 && ndownlocks == 1 ) 6177 { 6178 SCIPdebugMsg(scip, "multi-aggregating in set-partitioning constraint\n"); 6179 6180 /* perform aggregation on variables resulting from a set-partitioning constraint */ 6181 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) ); 6182 6183 if( infeasible ) 6184 { 6185 *cutoff = TRUE; 6186 break; 6187 } 6188 6189 ++ndecs; 6190 } 6191 /* we might have found a redundant variable */ 6192 else if( ndownlocks <= 2 && nuplocks <= 2 && SCIPvarGetNegatedVar(var) != NULL ) 6193 { 6194 SCIP_CONSDATA* aggrconsdata; 6195 int image; 6196 int consindex; 6197 int varindex; 6198 6199 /* if we have two times the same variable in a set-partitioning constraint, we cannot aggregate this */ 6200 if( SCIPhashmapExists(vartoindex, (void*) var) ) 6201 { 6202 image = SCIPhashmapGetImageInt(vartoindex, (void*) var); 6203 assert(image > 0 && image <= nhashmapentries); 6204 6205 assert(0 <= considxs[image - 1] && considxs[image - 1] < nconss); 6206 assert(SCIPconsIsDeleted(usefulconss[considxs[image - 1]]) || chgtype[considxs[image - 1]] || (0 <= posincons[image - 1] && posincons[image - 1] < SCIPconsGetData(usefulconss[considxs[image - 1]])->nvars)); 6207 6208 considxs[image - 1] = -1; 6209 posincons[image - 1] = -1; 6210 6211 SCIP_CALL( SCIPhashmapRemove(vartoindex, (void*) var) ); 6212 6213 #ifndef NDEBUG 6214 --posreplacements; 6215 #endif 6216 assert(posreplacements >= 0); 6217 6218 continue; 6219 } 6220 else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) 6221 { 6222 /* if we found a new variable add it to the data */ 6223 if( !SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(var)) ) 6224 { 6225 assert(!SCIPhashmapExists(vartoindex, (void*) var)); 6226 6227 ++nhashmapentries; 6228 SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) var, nhashmapentries) ); 6229 6230 considxs[nhashmapentries - 1] = c; 6231 posincons[nhashmapentries - 1] = v; 6232 6233 #ifndef NDEBUG 6234 ++posreplacements; 6235 #endif 6236 continue; 6237 } 6238 } 6239 else 6240 { 6241 assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING); 6242 6243 /* the negated variable did not occur in a set partitioning constraint (those will be iterated over 6244 * first), so we cannot aggregate this variable 6245 */ 6246 if( !SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(var)) ) 6247 continue; 6248 } 6249 6250 assert(!chgtype[c]); 6251 assert(SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(var))); 6252 image = SCIPhashmapGetImageInt(vartoindex, (void*) SCIPvarGetNegatedVar(var)); 6253 assert(image > 0 && image <= nhashmapentries); 6254 6255 consindex = considxs[image - 1]; 6256 assert(0 <= consindex && consindex < nconss); 6257 6258 /* if the following assert fails, the constraint was not merged, or something really strange happened */ 6259 assert(consindex < c); 6260 6261 ++ndecs; 6262 #ifndef NDEBUG 6263 --posreplacements; 6264 #endif 6265 assert(posreplacements >= 0); 6266 6267 varindex = posincons[image - 1]; 6268 considxs[image - 1] = -1; 6269 posincons[image - 1] = -1; 6270 SCIP_CALL( SCIPhashmapRemove(vartoindex, (void*) SCIPvarGetNegatedVar(var)) ); 6271 6272 /* if two variables in one constraint might be multi-aggregated, it might happen that this constraint was 6273 * already removed 6274 */ 6275 if( SCIPconsIsDeleted(usefulconss[consindex]) ) 6276 continue; 6277 6278 aggrconsdata = SCIPconsGetData(usefulconss[consindex]); 6279 assert(aggrconsdata != NULL); 6280 6281 /* must not multi-aggregate variables that are locked more then twice by all setppc constraints */ 6282 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING && 6283 (SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PACKING ) 6284 { 6285 assert(!dualpresolvingenabled || nuplocks + ndownlocks > 2); 6286 continue; 6287 } 6288 6289 assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || 6290 (SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING); 6291 6292 /* we already removed a variable before, so our positioning information might be wrong, so we need to walk 6293 * over all variables again 6294 */ 6295 if( chgtype[consindex] ) 6296 { 6297 #ifndef NDEBUG 6298 int v2; 6299 6300 assert((SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PACKING); 6301 6302 /* negated variables needs to be still in the upgraded set-packing constraint */ 6303 for( v2 = aggrconsdata->nvars - 1; v2 >= 0; --v2 ) 6304 { 6305 if( aggrconsdata->vars[v2] == SCIPvarGetNegatedVar(var) ) 6306 break; 6307 } 6308 assert(v2 >= 0); 6309 #endif 6310 assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING); 6311 6312 SCIPdebugMsg(scip, "multi-aggregating in one set-partitioning or one set-packing constraint\n"); 6313 6314 /* perform aggregation on variables resulting from a set-partitioning constraint */ 6315 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) ); 6316 6317 if( infeasible ) 6318 { 6319 *cutoff = TRUE; 6320 break; 6321 } 6322 assert(deleteconsindex == -1); 6323 } 6324 else 6325 { 6326 /* @note it might have happened that we have a variable at hand which exists actually in a set-packing 6327 * constraint and due to some other aggregation we increased the number of locks and reached this 6328 * part of the code, where we would expect only set-partitioning constraints in general, so in 6329 * such a strange case we cannot aggregate anything 6330 */ 6331 if( (SCIP_SETPPCTYPE)aggrconsdata->setppctype != SCIP_SETPPCTYPE_PARTITIONING ) 6332 continue; 6333 6334 assert(0 <= varindex && varindex < aggrconsdata->nvars); 6335 assert(aggrconsdata->vars[varindex] == SCIPvarGetNegatedVar(var)); 6336 assert((SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING); 6337 6338 SCIPdebugMsg(scip, "multi-aggregating in two set-partitioning or one set-partitioning and -packing constraint\n"); 6339 6340 /* perform aggregation on variables resulting from a set-partitioning constraint */ 6341 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, aggrconsdata->vars, aggrconsdata->nvars, varindex, &infeasible, &aggregated) ); 6342 6343 if( infeasible ) 6344 { 6345 *cutoff = TRUE; 6346 break; 6347 } 6348 6349 /* change pointer for deletion */ 6350 constoupdate = usefulconss[consindex]; 6351 assert(deleteconsindex == -1); 6352 } 6353 } 6354 6355 if( aggregated ) 6356 { 6357 assert(nuplocks >= 1 && ndownlocks >= 0); /* repeated from above */ 6358 ++(*naggrvars); 6359 6360 if( nuplocks == 1 && ndownlocks == 0 && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) 6361 { 6362 assert(deleteconsindex < 0); 6363 6364 SCIP_CALL( delCoefPos(scip, constoupdate, v) ); 6365 ++(*nchgcoefs); 6366 } 6367 else if( nuplocks == 1 && ndownlocks == 1 && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) 6368 { 6369 assert(deleteconsindex < 0); 6370 6371 SCIP_CALL( delCoefPos(scip, constoupdate, v) ); 6372 ++(*nchgcoefs); 6373 6374 SCIPdebugMsg(scip, "changing constraint <%s> from set-partitioning to set-packing, due to multi-aggregation\n", SCIPconsGetName(cons)); 6375 6376 chgtype[c] = TRUE; 6377 6378 SCIP_CALL( setSetppcType(scip, constoupdate, SCIP_SETPPCTYPE_PACKING) ); 6379 ++(*nchgsides); 6380 } 6381 else 6382 { 6383 if( deleteconsindex >= 0 ) 6384 { 6385 SCIPdebugMsg(scip, "1: deleting redundant constraint <%s>, due to multi-aggregation\n", SCIPconsGetName(usefulconss[deleteconsindex])); 6386 SCIPdebugPrintCons(scip, usefulconss[deleteconsindex], NULL); 6387 6388 assert(!SCIPconsIsDeleted(usefulconss[deleteconsindex])); 6389 SCIP_CALL( SCIPdelCons(scip, usefulconss[deleteconsindex]) ); 6390 } 6391 else 6392 { 6393 SCIPdebugMsg(scip, "2: deleting redundant constraint <%s>, due to multi-aggregation\n", SCIPconsGetName(cons)); 6394 SCIPdebugPrintCons(scip, constoupdate, NULL); 6395 6396 assert(!SCIPconsIsDeleted(cons)); 6397 SCIP_CALL( SCIPdelCons(scip, constoupdate) ); 6398 } 6399 ++(*ndelconss); 6400 } 6401 6402 break; 6403 } 6404 } 6405 } 6406 6407 /* free temporary memory */ 6408 SCIPfreeBufferArray(scip, &usefulconss); 6409 SCIPfreeBufferArray(scip, &posincons); 6410 SCIPfreeBufferArray(scip, &considxs); 6411 SCIPfreeBufferArray(scip, &chgtype); 6412 6413 /* free hashmap */ 6414 SCIPhashmapFree(&vartoindex); 6415 6416 return SCIP_OKAY; 6417 } 6418 6419 6420 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint 6421 * accordingly; in contrast to removeRedundantConstraints(), it uses a hash table 6422 */ 6423 static 6424 SCIP_RETCODE detectRedundantConstraints( 6425 SCIP* scip, /**< SCIP data structure */ 6426 BMS_BLKMEM* blkmem, /**< block memory */ 6427 SCIP_CONS** conss, /**< constraint set */ 6428 int nconss, /**< number of constraints in constraint set */ 6429 int* firstchange, /**< pointer to store first changed constraint */ 6430 int* ndelconss, /**< pointer to count number of deleted constraints */ 6431 int* nchgsides /**< pointer to count number of changed left/right hand sides */ 6432 ) 6433 { 6434 SCIP_HASHTABLE* hashtable; 6435 int hashtablesize; 6436 int c; 6437 6438 assert(scip != NULL); 6439 assert(blkmem != NULL); 6440 assert(conss != NULL || nconss == 0); 6441 assert(firstchange != NULL); 6442 assert(ndelconss != NULL); 6443 assert(nchgsides != NULL); 6444 6445 if( nconss == 0 ) 6446 return SCIP_OKAY; 6447 6448 assert(conss != NULL); 6449 6450 /* create a hash table for the constraint set */ 6451 hashtablesize = nconss; 6452 hashtablesize = MAX(hashtablesize, HASHSIZE_SETPPCCONS); 6453 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize, 6454 hashGetKeySetppccons, hashKeyEqSetppccons, hashKeyValSetppccons, (void*) scip) ); 6455 6456 /* check all constraints in the given set for redundancy */ 6457 for( c = 0; c < nconss; ++c ) 6458 { 6459 SCIP_CONS* cons0; 6460 SCIP_CONS* cons1; 6461 6462 cons0 = conss[c]; 6463 6464 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) ) 6465 continue; 6466 6467 /* get constraint from current hash table with same variables as cons0 and with coefficients either equal or negated 6468 * to the ones of cons0 */ 6469 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0)); 6470 6471 if( cons1 != NULL ) 6472 { 6473 SCIP_CONSDATA* consdata0; 6474 SCIP_CONSDATA* consdata1; 6475 6476 assert(SCIPconsIsActive(cons1)); 6477 assert(!SCIPconsIsModifiable(cons1)); 6478 6479 /* constraint found: create a new constraint with same coefficients and best left and right hand side; 6480 * delete old constraints afterwards 6481 */ 6482 consdata0 = SCIPconsGetData(cons0); 6483 consdata1 = SCIPconsGetData(cons1); 6484 6485 assert(consdata0 != NULL && consdata1 != NULL); 6486 assert(consdata0->nvars >= 1 && consdata0->nvars == consdata1->nvars); 6487 6488 assert(consdata0->sorted && consdata1->sorted); 6489 assert(consdata0->vars[0] == consdata1->vars[0]); 6490 6491 SCIPdebugMsg(scip, "setppc constraints <%s> and <%s> have identical variable sets\n", 6492 SCIPconsGetName(cons0), SCIPconsGetName(cons1)); 6493 SCIPdebugPrintCons(scip, cons0, NULL); 6494 SCIPdebugPrintCons(scip, cons1, NULL); 6495 6496 /* if necessary change type of setppc constraint */ 6497 if( consdata1->setppctype != SCIP_SETPPCTYPE_PARTITIONING && consdata0->setppctype != consdata1->setppctype ) /*lint !e641*/ 6498 { 6499 /* change the type of cons0 */ 6500 SCIP_CALL( setSetppcType(scip, cons1, SCIP_SETPPCTYPE_PARTITIONING) ); 6501 (*nchgsides)++; 6502 } 6503 6504 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */ 6505 /* coverity[swapped_arguments] */ 6506 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) ); 6507 6508 /* delete cons0 */ 6509 SCIP_CALL( SCIPdelCons(scip, cons0) ); 6510 (*ndelconss)++; 6511 6512 /* update the first changed constraint to begin the next aggregation round with */ 6513 if( consdata0->changed && SCIPconsGetPos(cons1) < *firstchange ) 6514 *firstchange = SCIPconsGetPos(cons1); 6515 6516 assert(SCIPconsIsActive(cons1)); 6517 } 6518 else 6519 { 6520 /* no such constraint in current hash table: insert cons0 into hash table */ 6521 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) ); 6522 } 6523 } 6524 6525 /* free hash table */ 6526 SCIPhashtableFree(&hashtable); 6527 6528 return SCIP_OKAY; 6529 } 6530 6531 /** removes the redundant second constraint and updates the flags of the first one */ 6532 static 6533 SCIP_RETCODE removeRedundantCons( 6534 SCIP* scip, /**< SCIP data structure */ 6535 SCIP_CONS* cons0, /**< constraint that should stay */ 6536 SCIP_CONS* cons1, /**< constraint that should be deleted */ 6537 int* ndelconss /**< pointer to count number of deleted constraints */ 6538 ) 6539 { 6540 assert(ndelconss != NULL); 6541 6542 SCIPdebugMsg(scip, " -> removing setppc constraint <%s> which is redundant to <%s>\n", 6543 SCIPconsGetName(cons1), SCIPconsGetName(cons0)); 6544 SCIPdebugPrintCons(scip, cons0, NULL); 6545 SCIPdebugPrintCons(scip, cons1, NULL); 6546 6547 /* update flags of cons0 */ 6548 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) ); 6549 6550 /* delete cons1 */ 6551 SCIP_CALL( SCIPdelCons(scip, cons1) ); 6552 (*ndelconss)++; 6553 6554 return SCIP_OKAY; 6555 } 6556 6557 /** for cons0 contained in cons1, fixes variables of cons1 that are not in cons0 to zero */ 6558 static 6559 SCIP_RETCODE fixAdditionalVars( 6560 SCIP* scip, /**< SCIP data structure */ 6561 SCIP_CONS* cons0, /**< constraint that is contained in the other */ 6562 SCIP_CONS* cons1, /**< constraint that is a superset of the other */ 6563 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */ 6564 int* nfixedvars /**< pointer to count number of fixed variables */ 6565 ) 6566 { 6567 SCIP_CONSDATA* consdata0; 6568 SCIP_CONSDATA* consdata1; 6569 int v0; 6570 int v1; 6571 6572 assert(cutoff != NULL); 6573 assert(nfixedvars != NULL); 6574 6575 *cutoff = FALSE; 6576 6577 /* get constraint data */ 6578 consdata0 = SCIPconsGetData(cons0); 6579 consdata1 = SCIPconsGetData(cons1); 6580 assert(consdata0 != NULL); 6581 assert(consdata1 != NULL); 6582 assert(consdata0->nvars < consdata1->nvars); 6583 assert(consdata0->sorted); 6584 assert(consdata1->sorted); 6585 6586 /* fix variables in the range of cons0 */ 6587 for( v0 = 0, v1 = 0; v0 < consdata0->nvars && !(*cutoff); ++v0, ++v1 ) 6588 { 6589 int index0; 6590 6591 assert(v1 < consdata1->nvars); 6592 index0 = SCIPvarGetIndex(consdata0->vars[v0]); 6593 for( ; SCIPvarGetIndex(consdata1->vars[v1]) < index0 && !(*cutoff); ++v1 ) /*lint !e445*/ 6594 { 6595 SCIP_Bool fixed; 6596 6597 /* fix variable to zero */ 6598 SCIP_CALL( SCIPfixVar(scip, consdata1->vars[v1], 0.0, cutoff, &fixed) ); 6599 if( fixed ) 6600 { 6601 SCIPdebugMsg(scip, " -> fixed <%s> == 0\n", SCIPvarGetName(consdata1->vars[v1])); 6602 (*nfixedvars)++; 6603 } 6604 assert(v1 < consdata1->nvars-1); 6605 } 6606 assert(SCIPvarGetIndex(consdata1->vars[v1]) == index0 || *cutoff); 6607 } 6608 6609 /* fix remaining variables of cons1 */ 6610 for( ; v1 < consdata1->nvars && !(*cutoff); ++v1 ) 6611 { 6612 SCIP_Bool fixed; 6613 6614 assert(consdata0->nvars == 0 6615 || SCIPvarGetIndex(consdata1->vars[v1]) > SCIPvarGetIndex(consdata0->vars[consdata0->nvars-1])); 6616 6617 /* fix variable to zero */ 6618 SCIP_CALL( SCIPfixVar(scip, consdata1->vars[v1], 0.0, cutoff, &fixed) ); 6619 if( fixed ) 6620 { 6621 SCIPdebugMsg(scip, " -> fixed <%s> == 0\n", SCIPvarGetName(consdata1->vars[v1])); 6622 (*nfixedvars)++; 6623 } 6624 } 6625 6626 return SCIP_OKAY; 6627 } 6628 6629 /** applies reductions for cons0 being contained in cons1 */ 6630 static 6631 SCIP_RETCODE processContainedCons( 6632 SCIP* scip, /**< SCIP data structure */ 6633 SCIP_CONS* cons0, /**< constraint that is contained in the other */ 6634 SCIP_CONS* cons1, /**< constraint that is a superset of the other */ 6635 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */ 6636 int* nfixedvars, /**< pointer to count number of fixed variables */ 6637 int* ndelconss, /**< pointer to count number of deleted constraints */ 6638 int* nchgsides /**< pointer to count number of changed left/right hand sides */ 6639 ) 6640 { 6641 SCIP_CONSDATA* consdata0; 6642 SCIP_CONSDATA* consdata1; 6643 6644 assert(cutoff != NULL); 6645 assert(nfixedvars != NULL); 6646 assert(ndelconss != NULL); 6647 assert(nchgsides != NULL); 6648 6649 *cutoff = FALSE; 6650 6651 /* get constraint data */ 6652 consdata0 = SCIPconsGetData(cons0); 6653 consdata1 = SCIPconsGetData(cons1); 6654 assert(consdata0 != NULL); 6655 assert(consdata1 != NULL); 6656 assert(consdata0->nvars < consdata1->nvars); 6657 assert(consdata0->sorted); 6658 assert(consdata1->sorted); 6659 6660 switch( consdata0->setppctype ) 6661 { 6662 case SCIP_SETPPCTYPE_PARTITIONING: 6663 switch( consdata1->setppctype ) 6664 { 6665 case SCIP_SETPPCTYPE_PARTITIONING: 6666 case SCIP_SETPPCTYPE_PACKING: 6667 /* cons0: partitioning, cons1: partitioning or packing 6668 * -> fix additional variables in cons1 to zero, remove cons1 6669 */ 6670 SCIP_CALL( fixAdditionalVars(scip, cons0, cons1, cutoff, nfixedvars) ); 6671 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) ); 6672 break; 6673 6674 case SCIP_SETPPCTYPE_COVERING: 6675 /* cons0: partitioning, cons1: covering 6676 * -> remove cons1 6677 */ 6678 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) ); 6679 break; 6680 6681 default: 6682 SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata1->setppctype, SCIPconsGetName(cons1)); 6683 return SCIP_INVALIDDATA; 6684 } 6685 break; 6686 6687 case SCIP_SETPPCTYPE_PACKING: 6688 switch( consdata1->setppctype ) 6689 { 6690 case SCIP_SETPPCTYPE_PARTITIONING: 6691 case SCIP_SETPPCTYPE_PACKING: 6692 /* cons0: packing, cons1: partitioning or packing 6693 * -> remove cons0 6694 */ 6695 SCIP_CALL( removeRedundantCons(scip, cons1, cons0, ndelconss) ); 6696 break; 6697 6698 case SCIP_SETPPCTYPE_COVERING: 6699 /* cons0: packing, cons1: covering 6700 * -> nothing can be deduced 6701 */ 6702 break; 6703 6704 default: 6705 SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata1->setppctype, SCIPconsGetName(cons1)); 6706 return SCIP_INVALIDDATA; 6707 } 6708 break; 6709 6710 case SCIP_SETPPCTYPE_COVERING: 6711 switch( consdata1->setppctype ) 6712 { 6713 case SCIP_SETPPCTYPE_PARTITIONING: 6714 case SCIP_SETPPCTYPE_PACKING: 6715 /* cons0: covering, cons1: partitioning or packing 6716 * -> fix additional variables in cons1 to zero, remove cons1, convert cons0 into partitioning 6717 */ 6718 SCIP_CALL( fixAdditionalVars(scip, cons0, cons1, cutoff, nfixedvars) ); 6719 SCIP_CALL( setSetppcType(scip, cons0, SCIP_SETPPCTYPE_PARTITIONING) ); 6720 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) ); 6721 (*nchgsides)++; 6722 break; 6723 6724 case SCIP_SETPPCTYPE_COVERING: 6725 /* cons0: covering, cons1: covering 6726 * -> remove cons1 6727 */ 6728 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) ); 6729 break; 6730 6731 default: 6732 SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata1->setppctype, SCIPconsGetName(cons1)); 6733 return SCIP_INVALIDDATA; 6734 } 6735 break; 6736 6737 default: 6738 SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata0->setppctype, SCIPconsGetName(cons0)); 6739 return SCIP_INVALIDDATA; 6740 } 6741 6742 return SCIP_OKAY; 6743 } 6744 6745 /** deletes redundant constraints */ 6746 static 6747 SCIP_RETCODE removeRedundantConstraints( 6748 SCIP* scip, /**< SCIP data structure */ 6749 SCIP_CONS** conss, /**< constraint set */ 6750 int firstchange, /**< first constraint that changed since last pair preprocessing round */ 6751 int chkind, /**< index of constraint to check against all prior indices up to startind */ 6752 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */ 6753 int* nfixedvars, /**< pointer to count number of fixed variables */ 6754 int* ndelconss, /**< pointer to count number of deleted constraints */ 6755 int* nchgsides /**< pointer to count number of changed left/right hand sides */ 6756 ) 6757 { 6758 SCIP_CONS* cons0; 6759 SCIP_CONSDATA* consdata0; 6760 uint64_t signature0; 6761 SCIP_Bool cons0changed; 6762 int c; 6763 6764 assert(scip != NULL); 6765 assert(conss != NULL); 6766 assert(cutoff != NULL); 6767 assert(nfixedvars != NULL); 6768 assert(ndelconss != NULL); 6769 assert(nchgsides != NULL); 6770 6771 *cutoff = FALSE; 6772 6773 /* get the constraint to be checked against all prior constraints */ 6774 cons0 = conss[chkind]; 6775 assert(SCIPconsIsActive(cons0)); 6776 assert(!SCIPconsIsModifiable(cons0)); 6777 6778 consdata0 = SCIPconsGetData(cons0); 6779 assert(consdata0 != NULL); 6780 assert(consdata0->nvars >= 1); 6781 6782 /* sort the constraint cons0 */ 6783 consdataSort(consdata0); 6784 6785 /* get the bit signature of the constraint */ 6786 signature0 = consdataGetSignature(consdata0); 6787 6788 /* check constraint against all prior constraints */ 6789 cons0changed = consdata0->changed; 6790 consdata0->changed = FALSE; 6791 for( c = (cons0changed ? 0 : firstchange); c < chkind && !(*cutoff) && SCIPconsIsActive(cons0); ++c ) 6792 { 6793 SCIP_CONS* cons1; 6794 SCIP_CONSDATA* consdata1; 6795 uint64_t signature1; 6796 uint64_t jointsignature; 6797 SCIP_Bool cons0iscontained; 6798 SCIP_Bool cons1iscontained; 6799 int v0; 6800 int v1; 6801 6802 cons1 = conss[c]; 6803 6804 /* ignore inactive and modifiable constraints */ 6805 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) ) 6806 continue; 6807 6808 consdata1 = SCIPconsGetData(cons1); 6809 assert(consdata1 != NULL); 6810 6811 /* sort the constraint cons1 */ 6812 consdataSort(consdata1); 6813 6814 /* get the bit signature of cons1 */ 6815 signature1 = consdataGetSignature(consdata1); 6816 6817 /* check (based on signature) if the two constraints are not included in each other */ 6818 jointsignature = (signature0 | signature1); 6819 if( jointsignature != signature0 && jointsignature != signature1 ) 6820 continue; 6821 6822 /* check whether one constraint is really a subset of the other */ 6823 cons0iscontained = (consdata0->nvars <= consdata1->nvars); 6824 cons1iscontained = (consdata1->nvars <= consdata0->nvars); 6825 v0 = 0; 6826 v1 = 0; 6827 while( v0 < consdata0->nvars && v1 < consdata1->nvars ) 6828 { 6829 int index0; 6830 int index1; 6831 6832 index0 = SCIPvarGetIndex(consdata0->vars[v0]); 6833 index1 = SCIPvarGetIndex(consdata1->vars[v1]); 6834 if( index0 < index1 ) 6835 { 6836 cons0iscontained = FALSE; 6837 if( !cons1iscontained ) 6838 break; 6839 for( v0++; v0 < consdata0->nvars && SCIPvarGetIndex(consdata0->vars[v0]) < index1; v0++ ) 6840 {} 6841 } 6842 else if( index1 < index0 ) 6843 { 6844 cons1iscontained = FALSE; 6845 if( !cons0iscontained ) 6846 break; 6847 for( v1++; v1 < consdata1->nvars && SCIPvarGetIndex(consdata1->vars[v1]) < index0; v1++ ) 6848 {} 6849 } 6850 else 6851 { 6852 v0++; 6853 v1++; 6854 } 6855 } 6856 cons0iscontained = cons0iscontained && (v0 == consdata0->nvars); 6857 cons1iscontained = cons1iscontained && (v1 == consdata1->nvars); 6858 6859 if( cons0iscontained && cons1iscontained ) 6860 { 6861 SCIPdebugMsg(scip, "setppc constraints <%s> and <%s> have identical variable sets\n", 6862 SCIPconsGetName(cons0), SCIPconsGetName(cons1)); 6863 SCIPdebugPrintCons(scip, cons0, NULL); 6864 SCIPdebugPrintCons(scip, cons1, NULL); 6865 6866 /* both constraints consists of the same variables */ 6867 if( consdata0->setppctype == consdata1->setppctype ) 6868 { 6869 /* both constraints are equal: update flags in cons0 and delete cons1 */ 6870 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) ); 6871 } 6872 else if( consdata0->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/ 6873 { 6874 /* the set partitioning constraint is stronger: remove the other one */ 6875 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) ); 6876 } 6877 else if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/ 6878 { 6879 /* the set partitioning constraint is stronger: remove the other one */ 6880 SCIP_CALL( removeRedundantCons(scip, cons1, cons0, ndelconss) ); 6881 } 6882 else 6883 { 6884 /* one is a covering, the other one a packing constraint: replace them by a single partitioning constraint */ 6885 assert((consdata0->setppctype == SCIP_SETPPCTYPE_COVERING && consdata1->setppctype == SCIP_SETPPCTYPE_PACKING) 6886 || (consdata1->setppctype == SCIP_SETPPCTYPE_COVERING && consdata0->setppctype == SCIP_SETPPCTYPE_PACKING)); /*lint !e641*/ 6887 6888 /* change the type of cons0 */ 6889 SCIP_CALL( setSetppcType(scip, cons0, SCIP_SETPPCTYPE_PARTITIONING) ); 6890 (*nchgsides)++; 6891 6892 /* delete cons1 */ 6893 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) ); 6894 } 6895 } 6896 else if( cons0iscontained ) 6897 { 6898 /* cons0 is contained in cons1 */ 6899 SCIPdebugMsg(scip, "setppc constraint <%s> is contained in <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1)); 6900 SCIPdebugPrintCons(scip, cons0, NULL); 6901 SCIPdebugPrintCons(scip, cons1, NULL); 6902 SCIP_CALL( processContainedCons(scip, cons0, cons1, cutoff, nfixedvars, ndelconss, nchgsides) ); 6903 } 6904 else if( cons1iscontained ) 6905 { 6906 /* cons1 is contained in cons1 */ 6907 SCIPdebugMsg(scip, "setppc constraint <%s> is contained in <%s>\n", SCIPconsGetName(cons1), SCIPconsGetName(cons0)); 6908 SCIPdebugPrintCons(scip, cons0, NULL); 6909 SCIPdebugPrintCons(scip, cons1, NULL); 6910 SCIP_CALL( processContainedCons(scip, cons1, cons0, cutoff, nfixedvars, ndelconss, nchgsides) ); 6911 } 6912 } 6913 6914 return SCIP_OKAY; 6915 } 6916 6917 /* perform deletion of variables in all constraints of the constraint handler */ 6918 static 6919 SCIP_RETCODE performVarDeletions( 6920 SCIP* scip, /**< SCIP data structure */ 6921 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 6922 SCIP_CONS** conss, /**< array of constraints */ 6923 int nconss /**< number of constraints */ 6924 ) 6925 { 6926 SCIP_CONSDATA* consdata; 6927 int i; 6928 int v; 6929 6930 assert(scip != NULL); 6931 assert(conshdlr != NULL); 6932 assert(conss != NULL); 6933 assert(nconss >= 0); 6934 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 6935 6936 /* iterate over all constraints */ 6937 for( i = 0; i < nconss; i++ ) 6938 { 6939 consdata = SCIPconsGetData(conss[i]); 6940 6941 /* constraint is marked, that some of its variables were deleted */ 6942 if( consdata->varsdeleted ) 6943 { 6944 /* iterate over all variables of the constraint and delete marked variables */ 6945 for( v = consdata->nvars - 1; v >= 0; v-- ) 6946 { 6947 if( SCIPvarIsDeleted(consdata->vars[v]) ) 6948 { 6949 SCIP_CALL( delCoefPos(scip, conss[i], v) ); 6950 } 6951 } 6952 consdata->varsdeleted = FALSE; 6953 } 6954 } 6955 6956 return SCIP_OKAY; 6957 } 6958 6959 /** helper function to enforce constraints */ 6960 static 6961 SCIP_RETCODE enforceConstraint( 6962 SCIP* scip, /**< SCIP data structure */ 6963 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 6964 SCIP_CONS** conss, /**< constraints to process */ 6965 int nconss, /**< number of constraints */ 6966 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */ 6967 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */ 6968 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */ 6969 ) 6970 { 6971 SCIP_Bool cutoff; 6972 SCIP_Bool separated; 6973 SCIP_Bool reduceddom; 6974 int c; 6975 6976 assert(conshdlr != NULL); 6977 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 6978 assert(nconss == 0 || conss != NULL); 6979 assert(result != NULL); 6980 6981 SCIPdebugMsg(scip, "Enforcing %d set partitioning / packing / covering constraints for %s solution\n", nconss, 6982 sol == NULL ? "LP" : "relaxation"); 6983 6984 *result = SCIP_FEASIBLE; 6985 6986 cutoff = FALSE; 6987 separated = FALSE; 6988 reduceddom = FALSE; 6989 6990 /* check all useful set partitioning / packing / covering constraints for feasibility */ 6991 for( c = 0; c < nusefulconss && !cutoff && !reduceddom; ++c ) 6992 { 6993 SCIP_CALL( separateCons(scip, conss[c], sol, TRUE, &cutoff, &separated, &reduceddom) ); 6994 } 6995 6996 /* check all obsolete set partitioning / packing / covering constraints for feasibility */ 6997 for( c = nusefulconss; c < nconss && !cutoff && !separated && !reduceddom; ++c ) 6998 { 6999 SCIP_CALL( separateCons(scip, conss[c], sol, TRUE, &cutoff, &separated, &reduceddom) ); 7000 } 7001 7002 #ifdef VARUSES 7003 #ifdef BRANCHLP 7004 /* @todo also branch on relaxation solution */ 7005 if( (sol == NULL) && !cutoff && !separated && !reduceddom ) 7006 { 7007 /* if solution is not integral, choose a variable set to branch on */ 7008 SCIP_CALL( branchLP(scip, conshdlr, result) ); 7009 if( *result != SCIP_FEASIBLE ) 7010 return SCIP_OKAY; 7011 } 7012 #endif 7013 #endif 7014 7015 /* return the correct result */ 7016 if( cutoff ) 7017 *result = SCIP_CUTOFF; 7018 else if( separated ) 7019 *result = SCIP_SEPARATED; 7020 else if( reduceddom ) 7021 *result = SCIP_REDUCEDDOM; 7022 7023 return SCIP_OKAY; 7024 } 7025 7026 /* 7027 * upgrading of linear constraints 7028 */ 7029 7030 7031 /** creates and captures a set partitioning / packing / covering constraint */ 7032 static 7033 SCIP_RETCODE createConsSetppc( 7034 SCIP* scip, /**< SCIP data structure */ 7035 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 7036 const char* name, /**< name of constraint */ 7037 int nvars, /**< number of variables in the constraint */ 7038 SCIP_VAR** vars, /**< array with variables of constraint entries */ 7039 SCIP_SETPPCTYPE setppctype, /**< type of constraint: set partitioning, packing, or covering constraint */ 7040 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? 7041 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ 7042 SCIP_Bool separate, /**< should the constraint be separated during LP processing? 7043 * Usually set to TRUE. */ 7044 SCIP_Bool enforce, /**< should the constraint be enforced during node processing? 7045 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 7046 SCIP_Bool check, /**< should the constraint be checked for feasibility? 7047 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 7048 SCIP_Bool propagate, /**< should the constraint be propagated during node processing? 7049 * Usually set to TRUE. */ 7050 SCIP_Bool local, /**< is constraint only valid locally? 7051 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ 7052 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? 7053 * Usually set to FALSE. In column generation applications, set to TRUE if pricing 7054 * adds coefficients to this constraint. */ 7055 SCIP_Bool dynamic, /**< is constraint subject to aging? 7056 * Usually set to FALSE. Set to TRUE for own cuts which 7057 * are separated as constraints. */ 7058 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup? 7059 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */ 7060 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even 7061 * if it may be moved to a more global node? 7062 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */ 7063 ) 7064 { 7065 SCIP_CONSHDLR* conshdlr; 7066 SCIP_CONSDATA* consdata; 7067 SCIP_CONSHDLRDATA* conshdlrdata; 7068 7069 assert(scip != NULL); 7070 7071 /* find the set partitioning constraint handler */ 7072 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME); 7073 if( conshdlr == NULL ) 7074 { 7075 SCIPerrorMessage("set partitioning / packing / covering constraint handler not found\n"); 7076 return SCIP_INVALIDCALL; 7077 } 7078 7079 /* create the constraint specific data */ 7080 if( SCIPgetStage(scip) == SCIP_STAGE_PROBLEM ) 7081 { 7082 /* create constraint in original problem */ 7083 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, setppctype) ); 7084 } 7085 else 7086 { 7087 /* create constraint in transformed problem */ 7088 SCIP_CALL( consdataCreateTransformed(scip, &consdata, nvars, vars, setppctype) ); 7089 } 7090 7091 /* create constraint */ 7092 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate, 7093 local, modifiable, dynamic, removable, stickingatnode) ); 7094 7095 conshdlrdata = SCIPconshdlrGetData(conshdlr); 7096 assert(conshdlrdata != NULL); 7097 7098 if( SCIPisTransformed(scip) && setppctype == SCIP_SETPPCTYPE_PARTITIONING ) 7099 { 7100 ++(conshdlrdata->nsetpart); 7101 assert(conshdlrdata->nsetpart >= 0); 7102 } 7103 7104 if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM ) 7105 { 7106 /* get event handler */ 7107 assert(conshdlrdata->eventhdlr != NULL); 7108 7109 /* catch bound change events of variables */ 7110 SCIP_CALL( catchAllEvents(scip, *cons, conshdlrdata->eventhdlr) ); 7111 } 7112 7113 return SCIP_OKAY; 7114 } 7115 7116 /** creates and captures a normalized (with all coefficients +1) setppc constraint */ 7117 static 7118 SCIP_RETCODE createNormalizedSetppc( 7119 SCIP* scip, /**< SCIP data structure */ 7120 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 7121 const char* name, /**< name of constraint */ 7122 int nvars, /**< number of variables in the constraint */ 7123 SCIP_VAR** vars, /**< array with variables of constraint entries */ 7124 SCIP_Real* vals, /**< array with coefficients (+1.0 or -1.0) */ 7125 int mult, /**< multiplier on the coefficients(+1 or -1) */ 7126 SCIP_SETPPCTYPE setppctype, /**< type of constraint: set partitioning, packing, or covering constraint */ 7127 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? 7128 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ 7129 SCIP_Bool separate, /**< should the constraint be separated during LP processing? 7130 * Usually set to TRUE. */ 7131 SCIP_Bool enforce, /**< should the constraint be enforced during node processing? 7132 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 7133 SCIP_Bool check, /**< should the constraint be checked for feasibility? 7134 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 7135 SCIP_Bool propagate, /**< should the constraint be propagated during node processing? 7136 * Usually set to TRUE. */ 7137 SCIP_Bool local, /**< is constraint only valid locally? 7138 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ 7139 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? 7140 * Usually set to FALSE. In column generation applications, set to TRUE if pricing 7141 * adds coefficients to this constraint. */ 7142 SCIP_Bool dynamic, /**< is constraint subject to aging? 7143 * Usually set to FALSE. Set to TRUE for own cuts which 7144 * are separated as constraints. */ 7145 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup? 7146 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */ 7147 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even 7148 * if it may be moved to a more global node? 7149 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */ 7150 ) 7151 { 7152 SCIP_VAR** transvars; 7153 int v; 7154 7155 assert(nvars == 0 || vars != NULL); 7156 assert(nvars == 0 || vals != NULL); 7157 assert(mult == +1 || mult == -1); 7158 7159 /* get temporary memory */ 7160 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) ); 7161 7162 /* negate positive or negative variables */ 7163 for( v = 0; v < nvars; ++v ) 7164 { 7165 if( mult * vals[v] > 0.0 ) 7166 transvars[v] = vars[v]; 7167 else 7168 { 7169 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) ); 7170 } 7171 assert(transvars[v] != NULL); 7172 } 7173 7174 /* create the constraint */ 7175 SCIP_CALL( createConsSetppc(scip, cons, name, nvars, transvars, setppctype, 7176 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) ); 7177 7178 /* release temporary memory */ 7179 SCIPfreeBufferArray(scip, &transvars); 7180 7181 return SCIP_OKAY; 7182 } 7183 7184 /** check, if linear constraint can be upgraded to set partitioning, packing, or covering constraint */ 7185 static 7186 SCIP_DECL_LINCONSUPGD(linconsUpgdSetppc) 7187 { /*lint --e{715}*/ 7188 assert(upgdcons != NULL); 7189 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0 ); 7190 7191 /* check, if linear constraint can be upgraded to set partitioning, packing, or covering constraint 7192 * - all set partitioning / packing / covering constraints consist only of binary variables with a 7193 * coefficient of +1.0 or -1.0 (variables with -1.0 coefficients can be negated): 7194 * lhs <= x1 + ... + xp - y1 - ... - yn <= rhs 7195 * - negating all variables y = (1-Y) with negative coefficients gives: 7196 * lhs + n <= x1 + ... + xp + Y1 + ... + Yn <= rhs + n 7197 * - negating all variables x = (1-X) with positive coefficients and multiplying with -1 gives: 7198 * p - rhs <= X1 + ... + Xp + y1 + ... + yn <= p - lhs 7199 * - a set partitioning constraint has left hand side of +1.0, and right hand side of +1.0 : x(S) == 1.0 7200 * -> without negations: lhs == rhs == 1 - n or lhs == rhs == p - 1 7201 * - a set packing constraint has left hand side of -infinity, and right hand side of +1.0 : x(S) <= 1.0 7202 * -> without negations: (lhs == -inf and rhs == 1 - n) or (lhs == p - 1 and rhs = +inf) 7203 * - a set covering constraint has left hand side of +1.0, and right hand side of +infinity: x(S) >= 1.0 7204 * -> without negations: (lhs == 1 - n and rhs == +inf) or (lhs == -inf and rhs = p - 1) 7205 */ 7206 if( nposbin + nnegbin + nposimplbin + nnegimplbin == nvars && ncoeffspone + ncoeffsnone == nvars ) 7207 { 7208 int mult; 7209 7210 if( SCIPisEQ(scip, lhs, rhs) && (SCIPisEQ(scip, lhs, 1.0 - ncoeffsnone) || SCIPisEQ(scip, lhs, ncoeffspone - 1.0)) ) 7211 { 7212 SCIPdebugMsg(scip, "upgrading constraint <%s> to set partitioning constraint\n", SCIPconsGetName(cons)); 7213 7214 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */ 7215 mult = SCIPisEQ(scip, lhs, 1.0 - ncoeffsnone) ? +1 : -1; 7216 7217 /* create the set partitioning constraint (an automatically upgraded constraint is always unmodifiable) */ 7218 assert(!SCIPconsIsModifiable(cons)); 7219 SCIP_CALL( createNormalizedSetppc(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, mult, 7220 SCIP_SETPPCTYPE_PARTITIONING, 7221 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 7222 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), 7223 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), 7224 SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) ); 7225 } 7226 else if( (SCIPisInfinity(scip, -lhs) && SCIPisEQ(scip, rhs, 1.0 - ncoeffsnone)) 7227 || (SCIPisEQ(scip, lhs, ncoeffspone - 1.0) && SCIPisInfinity(scip, rhs)) ) 7228 { 7229 SCIPdebugMsg(scip, "upgrading constraint <%s> to set packing constraint\n", SCIPconsGetName(cons)); 7230 7231 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */ 7232 mult = SCIPisInfinity(scip, -lhs) ? +1 : -1; 7233 7234 /* create the set packing constraint (an automatically upgraded constraint is always unmodifiable) */ 7235 assert(!SCIPconsIsModifiable(cons)); 7236 SCIP_CALL( createNormalizedSetppc(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, mult, 7237 SCIP_SETPPCTYPE_PACKING, 7238 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 7239 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), 7240 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), 7241 SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) ); 7242 } 7243 else if( (SCIPisEQ(scip, lhs, 1.0 - ncoeffsnone) && SCIPisInfinity(scip, rhs)) 7244 || (SCIPisInfinity(scip, -lhs) && SCIPisEQ(scip, rhs, ncoeffspone - 1.0)) ) 7245 { 7246 SCIPdebugMsg(scip, "upgrading constraint <%s> to set covering constraint\n", SCIPconsGetName(cons)); 7247 7248 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */ 7249 mult = SCIPisInfinity(scip, rhs) ? +1 : -1; 7250 7251 /* create the set covering constraint (an automatically upgraded constraint is always unmodifiable) */ 7252 assert(!SCIPconsIsModifiable(cons)); 7253 SCIP_CALL( createNormalizedSetppc(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, mult, 7254 SCIP_SETPPCTYPE_COVERING, 7255 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 7256 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), 7257 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), 7258 SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) ); 7259 } 7260 } 7261 7262 return SCIP_OKAY; 7263 } 7264 7265 /** tries to upgrade a nonlinear constraint to a setpacking constraint */ 7266 static 7267 SCIP_DECL_NONLINCONSUPGD(nonlinUpgdSetppc) 7268 { 7269 SCIP_Bool isquadratic; 7270 SCIP_EXPR* expr; 7271 SCIP_EXPR* expr1; 7272 SCIP_EXPR* expr2; 7273 SCIP_VAR* bilinvars[2]; 7274 SCIP_VAR* vars[2]; 7275 SCIP_Real bilincoef; 7276 SCIP_Real constant; 7277 SCIP_Real lincoef; 7278 SCIP_Real sqrcoef; 7279 SCIP_Real coefx; 7280 SCIP_Real coefy; 7281 SCIP_Real rhs; 7282 int nbilinexprterms; 7283 int nquadexprs; 7284 int nlinexprs; 7285 7286 assert(scip != NULL); 7287 assert(cons != NULL); 7288 assert(nupgdconss != NULL); 7289 assert(upgdconss != NULL); 7290 assert(! SCIPconsIsModifiable(cons)); 7291 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "nonlinear") == 0); 7292 7293 *nupgdconss = 0; 7294 7295 SCIPdebugMsg(scip, "try to upgrade nonlinear constraint <%s> to setpacking constraint ...\n", SCIPconsGetName(cons)); 7296 SCIPdebugPrintCons(scip, cons, NULL); 7297 7298 /* need exactly two variables */ 7299 if( nvarexprs != 2 ) 7300 return SCIP_OKAY; 7301 7302 /* left and right hand side need to be equal 7303 * @todo we could also handle inequalities 7304 */ 7305 rhs = SCIPgetRhsNonlinear(cons); 7306 if( SCIPisInfinity(scip, rhs) || !SCIPisEQ(scip, SCIPgetLhsNonlinear(cons), rhs) ) 7307 return SCIP_OKAY; 7308 7309 /* check whether constraint is quadratic */ 7310 SCIP_CALL( SCIPcheckQuadraticNonlinear(scip, cons, &isquadratic) ); 7311 if( !isquadratic ) 7312 return SCIP_OKAY; 7313 7314 expr = SCIPgetExprNonlinear(cons); 7315 SCIPexprGetQuadraticData(expr, &constant, &nlinexprs, NULL, NULL, &nquadexprs, &nbilinexprterms, NULL, NULL); 7316 7317 /* adjust rhs */ 7318 rhs -= constant; 7319 7320 /* cannot currently handle linear part */ 7321 if( nlinexprs > 0 ) 7322 return SCIP_OKAY; 7323 7324 /* need only one bilinear term */ 7325 if( nbilinexprterms != 1 ) 7326 return SCIP_OKAY; 7327 7328 /* need exactly two quadratic variables */ 7329 if( nquadexprs != 2 ) 7330 return SCIP_OKAY; 7331 7332 /* get bilinear term */ 7333 SCIPexprGetQuadraticBilinTerm(expr, 0, &expr1, &expr2, &bilincoef, NULL, NULL); 7334 bilinvars[0] = SCIPgetVarExprVar(expr1); 7335 bilinvars[1] = SCIPgetVarExprVar(expr2); 7336 7337 if( SCIPisZero(scip, bilincoef) ) 7338 return SCIP_OKAY; 7339 7340 /* check variable types */ 7341 if( SCIPvarGetType(bilinvars[0]) != SCIP_VARTYPE_BINARY || SCIPvarGetType(bilinvars[1]) != SCIP_VARTYPE_BINARY ) 7342 return SCIP_OKAY; 7343 7344 /* get data of quadratic terms */ 7345 SCIPexprGetQuadraticQuadTerm(expr, 0, &expr1, &lincoef, &sqrcoef, NULL, NULL, NULL); 7346 coefx = lincoef + sqrcoef; /* for binary variables, we can treat sqr coef as lin coef */ 7347 7348 SCIPexprGetQuadraticQuadTerm(expr, 1, &expr2, &lincoef, &sqrcoef, NULL, NULL, NULL); 7349 coefy = lincoef + sqrcoef; /* for binary variables, we can treat sqr coef as lin coef */ 7350 7351 /* divide constraint by coefficient of x*y */ 7352 coefx /= bilincoef; 7353 coefy /= bilincoef; 7354 rhs /= bilincoef; 7355 7356 /* constraint is now of the form coefx * x + coefy * y + x * y == rhs 7357 * we can rewrite as (x + coefy) * (y + coefx) == rhs + coefx * coefy 7358 */ 7359 7360 /* we can only upgrade if coefx and coefy are 0 or -1 and rhs == -coefx * coefy */ 7361 if( !SCIPisZero(scip, coefx) && !SCIPisEQ(scip, coefx, -1.0) ) 7362 return SCIP_OKAY; 7363 if( !SCIPisZero(scip, coefy) && !SCIPisEQ(scip, coefy, -1.0) ) 7364 return SCIP_OKAY; 7365 if( !SCIPisEQ(scip, rhs, -coefx * coefy) ) 7366 return SCIP_OKAY; 7367 7368 if( SCIPisZero(scip, coefy) ) 7369 { 7370 vars[0] = SCIPgetVarExprVar(expr1); 7371 } 7372 else 7373 { 7374 assert(SCIPisEQ(scip, coefy, -1.0)); 7375 /* x - 1 = -(1-x) = -(~x) */ 7376 SCIP_CALL( SCIPgetNegatedVar(scip, SCIPgetVarExprVar(expr1), &vars[0]) ); 7377 } 7378 if( SCIPisZero(scip, coefx) ) 7379 { 7380 vars[1] = SCIPgetVarExprVar(expr2); 7381 } 7382 else 7383 { 7384 assert(SCIPisEQ(scip, coefx, -1.0)); 7385 /* y - 1 = -(1 - y) = -(~y) */ 7386 SCIP_CALL( SCIPgetNegatedVar(scip, SCIPgetVarExprVar(expr2), &vars[1]) ); 7387 } 7388 7389 /* constraint is now of the form vars[0] * vars[1] == 0 */ 7390 7391 SCIPdebugMsg(scip, "constraint <%s> can be upgraded ...\n", SCIPconsGetName(cons)); 7392 7393 /* vars[0] + vars[1] <= 1 */ 7394 SCIP_CALL( SCIPcreateConsSetpack(scip, &upgdconss[0], SCIPconsGetName(cons), 2, vars, 7395 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 7396 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), 7397 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) ); 7398 SCIPdebugPrintCons(scip, upgdconss[0], NULL); 7399 7400 ++(*nupgdconss); 7401 7402 return SCIP_OKAY; 7403 } /*lint !e715*/ 7404 7405 /** adds symmetry information of constraint to a symmetry detection graph */ 7406 static 7407 SCIP_RETCODE addSymmetryInformation( 7408 SCIP* scip, /**< SCIP pointer */ 7409 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */ 7410 SCIP_CONS* cons, /**< constraint */ 7411 SYM_GRAPH* graph, /**< symmetry detection graph */ 7412 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */ 7413 ) 7414 { 7415 SCIP_CONSDATA* consdata; 7416 SCIP_VAR** vars; 7417 SCIP_Real* vals; 7418 SCIP_Real constant = 0.0; 7419 SCIP_Real lhs; 7420 SCIP_Real rhs; 7421 int nlocvars; 7422 int nvars; 7423 int i; 7424 7425 assert(scip != NULL); 7426 assert(cons != NULL); 7427 assert(graph != NULL); 7428 assert(success != NULL); 7429 7430 consdata = SCIPconsGetData(cons); 7431 assert(consdata != NULL); 7432 7433 /* get active variables of the constraint */ 7434 nvars = SCIPgetNVars(scip); 7435 nlocvars = consdata->nvars; 7436 7437 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) ); 7438 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) ); 7439 7440 for( i = 0; i < consdata->nvars; ++i ) 7441 { 7442 vars[i] = consdata->vars[i]; 7443 vals[i] = 1.0; 7444 } 7445 7446 SCIP_CALL( SCIPgetActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) ); 7447 7448 lhs = -SCIPinfinity(scip); 7449 rhs = SCIPinfinity(scip); 7450 if ( consdata->setppctype == (unsigned) SCIP_SETPPCTYPE_PACKING ) /*lint !e641*/ 7451 rhs = 1.0 - constant; 7452 else if ( consdata->setppctype == (unsigned) SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/ 7453 lhs = 1.0 - constant; 7454 else 7455 { 7456 assert(consdata->setppctype == (unsigned) SCIP_SETPPCTYPE_PARTITIONING); /*lint !e641*/ 7457 7458 rhs = 1.0 - constant; 7459 lhs = 1.0 - constant; 7460 } 7461 7462 SCIP_CALL( SCIPextendPermsymDetectionGraphLinear(scip, graph, vars, vals, nlocvars, 7463 cons, lhs, rhs, success) ); 7464 7465 SCIPfreeBufferArray(scip, &vals); 7466 SCIPfreeBufferArray(scip, &vars); 7467 7468 return SCIP_OKAY; 7469 } 7470 7471 /* 7472 * Callback methods of constraint handler 7473 */ 7474 7475 /** copy method for constraint handler plugins (called when SCIP copies plugins) */ 7476 static 7477 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySetppc) 7478 { /*lint --e{715}*/ 7479 assert(scip != NULL); 7480 assert(conshdlr != NULL); 7481 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 7482 7483 /* call inclusion method of constraint handler */ 7484 SCIP_CALL( SCIPincludeConshdlrSetppc(scip) ); 7485 7486 *valid = TRUE; 7487 7488 return SCIP_OKAY; 7489 } 7490 7491 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */ 7492 static 7493 SCIP_DECL_CONSFREE(consFreeSetppc) 7494 { /*lint --e{715}*/ 7495 SCIP_CONSHDLRDATA* conshdlrdata; 7496 7497 assert(conshdlr != NULL); 7498 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 7499 assert(scip != NULL); 7500 7501 /* free constraint handler data */ 7502 conshdlrdata = SCIPconshdlrGetData(conshdlr); 7503 assert(conshdlrdata != NULL); 7504 SCIP_CALL( conshdlrdataFree(scip, &conshdlrdata) ); 7505 7506 SCIPconshdlrSetData(conshdlr, NULL); 7507 7508 return SCIP_OKAY; 7509 } 7510 7511 7512 /** initialization method of constraint handler (called after problem was transformed) */ 7513 static 7514 SCIP_DECL_CONSINIT(consInitSetppc) 7515 { /*lint --e{715}*/ 7516 SCIP_CONSHDLRDATA* conshdlrdata; 7517 7518 assert(conshdlr != NULL); 7519 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 7520 assert(scip != NULL); 7521 7522 /* free constraint handler data */ 7523 conshdlrdata = SCIPconshdlrGetData(conshdlr); 7524 assert(conshdlrdata != NULL); 7525 7526 conshdlrdata->noldfixedvars = 0; 7527 conshdlrdata->noldimpls = 0; 7528 conshdlrdata->noldcliques = 0; 7529 conshdlrdata->noldupgrs = 0; 7530 conshdlrdata->nclqpresolve = 0; 7531 conshdlrdata->updatedsetppctype = FALSE; 7532 conshdlrdata->enablecliquelifting = TRUE; 7533 7534 return SCIP_OKAY; 7535 } 7536 7537 7538 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */ 7539 static 7540 SCIP_DECL_CONSEXITPRE(consExitpreSetppc) 7541 { /*lint --e{715}*/ 7542 int c; 7543 7544 assert(scip != NULL); 7545 assert(conshdlr != NULL); 7546 7547 for( c = 0; c < nconss; ++c ) 7548 { 7549 if( !SCIPconsIsDeleted(conss[c]) ) 7550 { 7551 /* we are not allowed to detect infeasibility in the exitpre stage */ 7552 SCIP_CALL( applyFixings(scip, conss[c], NULL, NULL, NULL, NULL) ); 7553 } 7554 } 7555 7556 return SCIP_OKAY; 7557 } 7558 7559 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */ 7560 static 7561 SCIP_DECL_CONSINITSOL(consInitsolSetppc) 7562 { /*lint --e{715}*/ 7563 /* add nlrow representation to NLP, if NLP had been constructed */ 7564 if( SCIPisNLPConstructed(scip) ) 7565 { 7566 int c; 7567 for( c = 0; c < nconss; ++c ) 7568 { 7569 SCIP_CALL( addNlrow(scip, conss[c]) ); 7570 } 7571 } 7572 7573 return SCIP_OKAY; 7574 } 7575 7576 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */ 7577 static 7578 SCIP_DECL_CONSEXITSOL(consExitsolSetppc) 7579 { /*lint --e{715}*/ 7580 SCIP_CONSDATA* consdata; 7581 int c; 7582 7583 /* release the rows and nlrows of all constraints */ 7584 for( c = 0; c < nconss; ++c ) 7585 { 7586 consdata = SCIPconsGetData(conss[c]); 7587 assert(consdata != NULL); 7588 7589 if( consdata->row != NULL ) 7590 { 7591 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) ); 7592 } 7593 7594 if( consdata->nlrow != NULL ) 7595 { 7596 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) ); 7597 } 7598 } 7599 7600 return SCIP_OKAY; 7601 } 7602 7603 7604 /** frees specific constraint data */ 7605 static 7606 SCIP_DECL_CONSDELETE(consDeleteSetppc) 7607 { /*lint --e{715}*/ 7608 SCIP_CONSHDLRDATA* conshdlrdata; 7609 7610 assert(conshdlr != NULL); 7611 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 7612 7613 /* get event handler */ 7614 conshdlrdata = SCIPconshdlrGetData(conshdlr); 7615 assert(conshdlrdata != NULL); 7616 assert(conshdlrdata->eventhdlr != NULL); 7617 7618 if( SCIPisTransformed(scip) ) 7619 { 7620 if( (SCIP_SETPPCTYPE)((*consdata)->setppctype) == SCIP_SETPPCTYPE_PARTITIONING ) 7621 { 7622 --(conshdlrdata->nsetpart); 7623 assert(conshdlrdata->nsetpart >= 0); 7624 } 7625 } 7626 7627 /* if constraint belongs to transformed problem space, drop bound change events on variables */ 7628 if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) ) 7629 { 7630 SCIP_CALL( dropAllEvents(scip, cons, conshdlrdata->eventhdlr) ); 7631 } 7632 7633 /* free setppc constraint data */ 7634 SCIP_CALL( consdataFree(scip, consdata) ); 7635 7636 return SCIP_OKAY; 7637 } 7638 7639 7640 /** transforms constraint data into data belonging to the transformed problem */ 7641 static 7642 SCIP_DECL_CONSTRANS(consTransSetppc) 7643 { /*lint --e{715}*/ 7644 SCIP_CONSHDLRDATA* conshdlrdata; 7645 SCIP_CONSDATA* sourcedata; 7646 SCIP_CONSDATA* targetdata; 7647 7648 /*debugMsg(scip, "Trans method of setppc constraints\n");*/ 7649 7650 assert(conshdlr != NULL); 7651 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 7652 assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING); 7653 assert(sourcecons != NULL); 7654 assert(targetcons != NULL); 7655 7656 /* get event handler */ 7657 conshdlrdata = SCIPconshdlrGetData(conshdlr); 7658 assert(conshdlrdata != NULL); 7659 assert(conshdlrdata->eventhdlr != NULL); 7660 7661 sourcedata = SCIPconsGetData(sourcecons); 7662 assert(sourcedata != NULL); 7663 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */ 7664 7665 /* create constraint data for target constraint */ 7666 SCIP_CALL( consdataCreateTransformed(scip, &targetdata, sourcedata->nvars, sourcedata->vars, 7667 (SCIP_SETPPCTYPE)sourcedata->setppctype) ); 7668 7669 /* create target constraint */ 7670 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata, 7671 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons), 7672 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), 7673 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons), 7674 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) ); 7675 7676 if( (SCIP_SETPPCTYPE)sourcedata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) 7677 { 7678 ++(conshdlrdata->nsetpart); 7679 assert(conshdlrdata->nsetpart >= 0); 7680 } 7681 7682 /* catch bound change events of variables */ 7683 SCIP_CALL( catchAllEvents(scip, *targetcons, conshdlrdata->eventhdlr) ); 7684 7685 return SCIP_OKAY; 7686 } 7687 7688 7689 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */ 7690 static 7691 SCIP_DECL_CONSINITLP(consInitlpSetppc) 7692 { /*lint --e{715}*/ 7693 int c; 7694 7695 *infeasible = FALSE; 7696 7697 for( c = 0; c < nconss && !(*infeasible); ++c ) 7698 { 7699 assert(SCIPconsIsInitial(conss[c])); 7700 SCIP_CALL( addCut(scip, conss[c], infeasible) ); 7701 } 7702 7703 return SCIP_OKAY; 7704 } 7705 7706 7707 /** separation method of constraint handler for LP solutions */ 7708 static 7709 SCIP_DECL_CONSSEPALP(consSepalpSetppc) 7710 { /*lint --e{715}*/ 7711 SCIP_Bool cutoff; 7712 SCIP_Bool separated; 7713 SCIP_Bool reduceddom; 7714 int c; 7715 7716 assert(conshdlr != NULL); 7717 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 7718 assert(nconss == 0 || conss != NULL); 7719 assert(result != NULL); 7720 7721 SCIPdebugMsg(scip, "separating %d/%d set partitioning / packing / covering constraints\n", nusefulconss, nconss); 7722 7723 *result = SCIP_DIDNOTFIND; 7724 7725 cutoff = FALSE; 7726 separated = FALSE; 7727 reduceddom = FALSE; 7728 7729 /* check all useful set partitioning / packing / covering constraints for feasibility */ 7730 for( c = 0; c < nusefulconss && !cutoff; ++c ) 7731 { 7732 SCIP_CALL( separateCons(scip, conss[c], NULL, TRUE, &cutoff, &separated, &reduceddom) ); 7733 } 7734 7735 /* combine set partitioning / packing / covering constraints to get more cuts */ 7736 /**@todo further cuts of set partitioning / packing / covering constraints */ 7737 7738 /* return the correct result */ 7739 if( cutoff ) 7740 *result = SCIP_CUTOFF; 7741 else if( reduceddom ) 7742 *result = SCIP_REDUCEDDOM; 7743 else if( separated ) 7744 *result = SCIP_SEPARATED; 7745 7746 return SCIP_OKAY; 7747 } 7748 7749 7750 /** separation method of constraint handler for arbitrary primal solutions */ 7751 static 7752 SCIP_DECL_CONSSEPASOL(consSepasolSetppc) 7753 { /*lint --e{715}*/ 7754 SCIP_Bool cutoff; 7755 SCIP_Bool separated; 7756 SCIP_Bool reduceddom; 7757 int c; 7758 7759 assert(conshdlr != NULL); 7760 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 7761 assert(nconss == 0 || conss != NULL); 7762 assert(result != NULL); 7763 7764 SCIPdebugMsg(scip, "separating %d/%d set partitioning / packing / covering constraints\n", nusefulconss, nconss); 7765 7766 *result = SCIP_DIDNOTFIND; 7767 7768 cutoff = FALSE; 7769 separated = FALSE; 7770 reduceddom = FALSE; 7771 7772 /* check all useful set partitioning / packing / covering constraints for feasibility */ 7773 for( c = 0; c < nusefulconss && !cutoff; ++c ) 7774 { 7775 SCIP_CALL( separateCons(scip, conss[c], sol, FALSE, &cutoff, &separated, &reduceddom) ); 7776 } 7777 7778 /* combine set partitioning / packing / covering constraints to get more cuts */ 7779 /**@todo further cuts of set partitioning / packing / covering constraints */ 7780 7781 /* return the correct result */ 7782 if( cutoff ) 7783 *result = SCIP_CUTOFF; 7784 else if( reduceddom ) 7785 *result = SCIP_REDUCEDDOM; 7786 else if( separated ) 7787 *result = SCIP_SEPARATED; 7788 7789 return SCIP_OKAY; 7790 } 7791 7792 7793 #ifdef VARUSES 7794 #ifdef BRANCHLP 7795 /** if fractional variables exist, chooses a set S of them and branches on (i) x(S) == 0, and (ii) x(S) >= 1 */ 7796 static 7797 SCIP_RETCODE branchLP( 7798 SCIP* scip, /**< SCIP data structure */ 7799 SCIP_CONSHDLR* conshdlr, /**< set partitioning / packing / covering constraint handler */ 7800 SCIP_RESULT* result /**< pointer to store the result SCIP_BRANCHED, if branching was applied */ 7801 ) 7802 { 7803 SCIP_CONSHDLRDATA* conshdlrdata; 7804 SCIP_INTARRAY* varuses; 7805 SCIP_VAR** lpcands; 7806 SCIP_VAR** sortcands; 7807 SCIP_VAR* var; 7808 SCIP_Real branchweight; 7809 SCIP_Real solval; 7810 int* uses; 7811 int nlpcands; 7812 int nsortcands; 7813 int nselcands; 7814 int numuses; 7815 int i; 7816 int j; 7817 7818 /**@todo use a better set partitioning / packing / covering branching on LP solution (use SOS branching) */ 7819 7820 assert(conshdlr != NULL); 7821 assert(result != NULL); 7822 7823 conshdlrdata = SCIPconshdlrGetData(conshdlr); 7824 assert(conshdlrdata != NULL); 7825 7826 varuses = conshdlrdata->varuses; 7827 assert(varuses != NULL); 7828 7829 /* get fractional variables */ 7830 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, NULL, &nlpcands, NULL, NULL) ); 7831 if( nlpcands == 0 ) 7832 return SCIP_OKAY; 7833 7834 assert(MINBRANCHWEIGHT <= MAXBRANCHWEIGHT); 7835 7836 /* get temporary memory */ 7837 SCIP_CALL( SCIPallocBufferArray(scip, &sortcands, nlpcands) ); 7838 SCIP_CALL( SCIPallocBufferArray(scip, &uses, nlpcands) ); 7839 7840 /* sort fractional variables by number of uses in enabled set partitioning / packing / covering constraints */ 7841 nsortcands = 0; 7842 for( i = 0; i < nlpcands; ++i ) 7843 { 7844 var = lpcands[i]; 7845 numuses = SCIPgetIntarrayVal(scip, varuses, SCIPvarGetIndex(var)); 7846 if( numuses > 0 ) 7847 { 7848 for( j = nsortcands; j > 0 && numuses > uses[j-1]; --j ) 7849 { 7850 sortcands[j] = sortcands[j-1]; 7851 uses[j] = uses[j-1]; 7852 } 7853 assert(0 <= j && j <= nsortcands); 7854 sortcands[j] = var; 7855 uses[j] = numuses; 7856 nsortcands++; 7857 } 7858 } 7859 assert(nsortcands <= nlpcands); 7860 7861 /* if none of the fractional variables is member of a set partitioning / packing / covering constraint, 7862 * we are not responsible for doing the branching 7863 */ 7864 if( nsortcands > 0 ) 7865 { 7866 SCIP_Real cumprio = 0.0; 7867 SCIP_Real minprio = SCIP_INVALID; 7868 SCIP_Real minestzero = SCIP_INVALID; 7869 SCIP_Real minestone = SCIP_INVALID; 7870 SCIP_Real tmp; 7871 7872 /* select the first variables from the sorted candidate list, until MAXBRANCHWEIGHT is reached; 7873 * then choose one less 7874 */ 7875 branchweight = 0.0; 7876 solval = 0.0; 7877 for( nselcands = 0; nselcands < nsortcands; ++nselcands ) 7878 { 7879 solval = SCIPgetVarSol(scip, sortcands[nselcands]); 7880 assert(SCIPisFeasGE(scip, solval, 0.0) && SCIPisFeasLE(scip, solval, 1.0)); 7881 branchweight += solval; 7882 7883 /* did we exceed the maximal weight */ 7884 if( branchweight > MAXBRANCHWEIGHT ) 7885 break; 7886 7887 /* @todo instead of taking the minimum into account try other variants like the maximum and the average */ 7888 /* calculate priorities and estimates by adding up/taking the minimum of all single priorities/estimates */ 7889 cumprio += SCIPcalcNodeselPriority(scip, sortcands[nselcands], SCIP_BRANCHDIR_DOWNWARDS, 0.0); 7890 tmp = SCIPcalcNodeselPriority(scip, sortcands[nselcands], SCIP_BRANCHDIR_UPWARDS, 1.0); 7891 minprio = MIN(minprio, tmp); 7892 tmp = SCIPcalcChildEstimate(scip, sortcands[nselcands], 0.0);; 7893 minestzero = MIN(minestzero, tmp); 7894 tmp = SCIPcalcChildEstimate(scip, sortcands[nselcands], 1.0);; 7895 minestone = MIN(minestone, tmp); 7896 } 7897 assert(minestzero != SCIP_INVALID); /*lint !e777*/ 7898 assert(minestone != SCIP_INVALID); /*lint !e777*/ 7899 assert(minprio != SCIP_INVALID); /*lint !e777*/ 7900 assert(nselcands > 0); 7901 branchweight -= solval; 7902 7903 /* check, if we accumulated at least MIN and at most MAXBRANCHWEIGHT weight */ 7904 if( MINBRANCHWEIGHT <= branchweight && branchweight <= MAXBRANCHWEIGHT ) 7905 { 7906 SCIP_NODE* node; 7907 7908 /* perform the binary set branching on the selected variables */ 7909 assert(1 <= nselcands && nselcands <= nlpcands); 7910 7911 /* create left child, fix x_i = 0 for all i \in S */ 7912 SCIP_CALL( SCIPcreateChild(scip, &node, cumprio, minestzero) ); 7913 for( i = 0; i < nselcands; ++i ) 7914 { 7915 SCIP_CALL( SCIPchgVarUbNode(scip, node, sortcands[i], 0.0) ); 7916 } 7917 7918 /* create right child: add constraint x(S) >= 1 */ 7919 SCIP_CALL( SCIPcreateChild(scip, &node, minprio, minestone) ); 7920 if( nselcands == 1 ) 7921 { 7922 /* only one candidate selected: fix it to 1.0 */ 7923 SCIPdebugMsg(scip, "fixing variable <%s> to 1.0 in right child node\n", SCIPvarGetName(sortcands[0])); 7924 SCIP_CALL( SCIPchgVarLbNode(scip, node, sortcands[0], 1.0) ); 7925 } 7926 else 7927 { 7928 SCIP_CONS* newcons; 7929 char name[SCIP_MAXSTRLEN]; 7930 7931 /* add set covering constraint x(S) >= 1 */ 7932 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "BSB%" SCIP_LONGINT_FORMAT, SCIPgetNTotalNodes(scip)); 7933 7934 SCIP_CALL( SCIPcreateConsSetcover(scip, &newcons, name, nselcands, sortcands, 7935 FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE) ); 7936 SCIP_CALL( SCIPaddConsNode(scip, node, newcons, NULL) ); 7937 SCIP_CALL( SCIPreleaseCons(scip, &newcons) ); 7938 } 7939 7940 *result = SCIP_BRANCHED; 7941 7942 #ifdef SCIP_DEBUG 7943 SCIPdebugMsg(scip, "binary set branching: nselcands=%d/%d, weight(S)=%g, A={", nselcands, nlpcands, branchweight); 7944 for( i = 0; i < nselcands; ++i ) 7945 SCIPdebugMsgPrint(scip, " %s[%g]", SCIPvarGetName(sortcands[i]), SCIPgetSolVal(scip, NULL, sortcands[i])); 7946 SCIPdebugMsgPrint(scip, " }\n"); 7947 #endif 7948 } 7949 } 7950 7951 /* free temporary memory */ 7952 SCIPfreeBufferArray(scip, &uses); 7953 SCIPfreeBufferArray(scip, &sortcands); 7954 7955 return SCIP_OKAY; 7956 } 7957 #endif 7958 7959 /** if unfixed variables exist, chooses a set S of them and creates |S|+1 child nodes: 7960 * - for each variable i from S, create child node with x_0 = ... = x_i-1 = 0, x_i = 1 7961 * - create an additional child node x_0 = ... = x_n-1 = 0 7962 */ 7963 static 7964 SCIP_RETCODE branchPseudo( 7965 SCIP* scip, /**< SCIP data structure */ 7966 SCIP_CONSHDLR* conshdlr, /**< set partitioning / packing / covering constraint handler */ 7967 SCIP_RESULT* result /**< pointer to store the result SCIP_BRANCHED, if branching was applied */ 7968 ) 7969 { 7970 SCIP_CONSHDLRDATA* conshdlrdata; 7971 SCIP_INTARRAY* varuses; 7972 SCIP_VAR** pseudocands; 7973 SCIP_VAR** branchcands; 7974 SCIP_VAR* var; 7975 SCIP_NODE* node; 7976 int* canduses; 7977 int npseudocands; 7978 int maxnbranchcands; 7979 int nbranchcands; 7980 int uses; 7981 int i; 7982 int j; 7983 7984 /**@todo use a better set partitioning / packing / covering branching on pseudo solution (use SOS branching) */ 7985 7986 assert(conshdlr != NULL); 7987 assert(result != NULL); 7988 7989 conshdlrdata = SCIPconshdlrGetData(conshdlr); 7990 assert(conshdlrdata != NULL); 7991 7992 /* check, if pseudo branching is disabled */ 7993 if( conshdlrdata->npseudobranches <= 1 ) 7994 return SCIP_OKAY; 7995 7996 /* get fractional variables */ 7997 SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, NULL, &npseudocands) ); 7998 if( npseudocands == 0 ) 7999 return SCIP_OKAY; 8000 8001 varuses = conshdlrdata->varuses; 8002 assert(varuses != NULL); 8003 8004 /* choose the maximal number of branching variables */ 8005 maxnbranchcands = conshdlrdata->npseudobranches-1; 8006 assert(maxnbranchcands >= 1); 8007 8008 /* get temporary memory */ 8009 SCIP_CALL( SCIPallocBufferArray(scip, &branchcands, maxnbranchcands) ); 8010 SCIP_CALL( SCIPallocBufferArray(scip, &canduses, maxnbranchcands) ); 8011 8012 /* sort unfixed variables by number of uses in enabled set partitioning / packing / covering constraints */ 8013 nbranchcands = 0; 8014 for( i = 0; i < npseudocands; ++i ) 8015 { 8016 var = pseudocands[i]; 8017 uses = SCIPgetIntarrayVal(scip, varuses, SCIPvarGetIndex(var)); 8018 if( uses > 0 ) 8019 { 8020 if( nbranchcands < maxnbranchcands || uses > canduses[nbranchcands-1] ) 8021 { 8022 for( j = MIN(nbranchcands, maxnbranchcands-1); j > 0 && uses > canduses[j-1]; --j ) 8023 { 8024 branchcands[j] = branchcands[j-1]; 8025 canduses[j] = canduses[j-1]; 8026 } 8027 assert(0 <= j && j <= nbranchcands && j < maxnbranchcands); 8028 branchcands[j] = var; 8029 canduses[j] = uses; 8030 if( nbranchcands < maxnbranchcands ) 8031 nbranchcands++; 8032 } 8033 } 8034 } 8035 assert(nbranchcands <= maxnbranchcands); 8036 8037 /* if none of the unfixed variables is member of a set partitioning / packing / covering constraint, 8038 * we are not responsible for doing the branching 8039 */ 8040 if( nbranchcands > 0 ) 8041 { 8042 SCIP_Real* estone; 8043 SCIP_Real minestzero = SCIP_INVALID; 8044 SCIP_Real tmp; 8045 8046 SCIP_CALL( SCIPallocBufferArray(scip, &estone, nbranchcands) ); 8047 8048 /* @todo instead of taking the minimum into account try other variants like the maximum and the average */ 8049 /* @todo calculate priorities instead of setting it to the number of branching candidates */ 8050 /* calculate estimates by taking the minimum over all single estimates */ 8051 for( i = 0; i < nbranchcands; ++i ) 8052 { 8053 tmp = SCIPcalcChildEstimate(scip, branchcands[i], 0.0);; 8054 minestzero = MIN(minestzero, tmp); 8055 estone[i] = SCIPcalcChildEstimate(scip, branchcands[i], 1.0); 8056 } 8057 assert(minestzero != SCIP_INVALID); /*lint !e777*/ 8058 8059 /* branch on the first part of the sorted candidates: 8060 * - for each of these variables i, create a child node x_0 = ... = x_i-1 = 0, x_i = 1 8061 * - create an additional child node x_0 = ... = x_n-1 = 0 8062 */ 8063 for( i = 0; i < nbranchcands; ++i ) 8064 { 8065 /* create child with x_0 = ... = x_i-1 = 0, x_i = 1 */ 8066 SCIP_CALL( SCIPcreateChild(scip, &node, (SCIP_Real)nbranchcands, MIN(minestzero, estone[i])) ); 8067 for( j = 0; j < i; ++j ) 8068 { 8069 SCIP_CALL( SCIPchgVarUbNode(scip, node, branchcands[j], 0.0) ); 8070 } 8071 SCIP_CALL( SCIPchgVarLbNode(scip, node, branchcands[i], 1.0) ); 8072 } 8073 /* create child with x_0 = ... = x_n = 0 */ 8074 SCIP_CALL( SCIPcreateChild(scip, &node, (SCIP_Real)nbranchcands, minestzero) ); 8075 for( i = 0; i < nbranchcands; ++i ) 8076 { 8077 SCIP_CALL( SCIPchgVarUbNode(scip, node, branchcands[i], 0.0) ); 8078 } 8079 8080 *result = SCIP_BRANCHED; 8081 8082 SCIPfreeBufferArray(scip, &estone); 8083 8084 #ifdef SCIP_DEBUG 8085 { 8086 int nchildren; 8087 SCIP_CALL( SCIPgetChildren(scip, NULL, &nchildren) ); 8088 SCIPdebugMsg(scip, "branched on pseudo solution: %d children\n", nchildren); 8089 } 8090 #endif 8091 } 8092 8093 /* free temporary memory */ 8094 SCIPfreeBufferArray(scip, &canduses); 8095 SCIPfreeBufferArray(scip, &branchcands); 8096 8097 return SCIP_OKAY; 8098 } 8099 #endif 8100 8101 8102 /** constraint enforcing method of constraint handler for LP solutions */ 8103 static 8104 SCIP_DECL_CONSENFOLP(consEnfolpSetppc) 8105 { /*lint --e{715}*/ 8106 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) ); 8107 8108 return SCIP_OKAY; 8109 } 8110 8111 8112 /** constraint enforcing method of constraint handler for relaxation solutions */ 8113 static 8114 SCIP_DECL_CONSENFORELAX(consEnforelaxSetppc) 8115 { /*lint --e{715}*/ 8116 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) ); 8117 8118 return SCIP_OKAY; 8119 } 8120 8121 8122 /** constraint enforcing method of constraint handler for pseudo solutions */ 8123 static 8124 SCIP_DECL_CONSENFOPS(consEnfopsSetppc) 8125 { /*lint --e{715}*/ 8126 SCIP_Bool cutoff; 8127 SCIP_Bool infeasible; 8128 SCIP_Bool reduceddom; 8129 SCIP_Bool solvelp; 8130 int c; 8131 8132 assert(conshdlr != NULL); 8133 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 8134 assert(nconss == 0 || conss != NULL); 8135 assert(result != NULL); 8136 8137 /* if the solution is infeasible anyway due to objective value, skip the constraint processing and branch directly */ 8138 #ifdef VARUSES 8139 if( objinfeasible ) 8140 { 8141 *result = SCIP_DIDNOTRUN; 8142 SCIP_CALL( branchPseudo(scip, conshdlr, result) ); 8143 return SCIP_OKAY; 8144 } 8145 #endif 8146 8147 SCIPdebugMsg(scip, "pseudo enforcing %d set partitioning / packing / covering constraints\n", nconss); 8148 8149 *result = SCIP_FEASIBLE; 8150 8151 cutoff = FALSE; 8152 infeasible = FALSE; 8153 reduceddom = FALSE; 8154 solvelp = FALSE; 8155 8156 /* check all set partitioning / packing / covering constraints for feasibility */ 8157 for( c = 0; c < nconss && !cutoff && !reduceddom && !solvelp; ++c ) 8158 { 8159 SCIP_CALL( enforcePseudo(scip, conss[c], &cutoff, &infeasible, &reduceddom, &solvelp) ); 8160 } 8161 8162 if( cutoff ) 8163 *result = SCIP_CUTOFF; 8164 else if( reduceddom ) 8165 *result = SCIP_REDUCEDDOM; 8166 else if( solvelp ) 8167 *result = SCIP_SOLVELP; 8168 else if( infeasible ) 8169 { 8170 *result = SCIP_INFEASIBLE; 8171 8172 #ifdef VARUSES 8173 /* at least one constraint is violated by pseudo solution and we didn't find a better way to resolve this: 8174 * -> branch on pseudo solution 8175 */ 8176 SCIP_CALL( branchPseudo(scip, conshdlr, result) ); 8177 #endif 8178 } 8179 8180 return SCIP_OKAY; 8181 } 8182 8183 8184 /** feasibility check method of constraint handler for integral solutions */ 8185 static 8186 SCIP_DECL_CONSCHECK(consCheckSetppc) 8187 { /*lint --e{715}*/ 8188 SCIP_CONS* cons; 8189 SCIP_CONSDATA* consdata; 8190 int c; 8191 8192 assert(conshdlr != NULL); 8193 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 8194 assert(nconss == 0 || conss != NULL); 8195 assert(result != NULL); 8196 8197 *result = SCIP_FEASIBLE; 8198 8199 /* check all set partitioning / packing / covering constraints for feasibility */ 8200 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c ) 8201 { 8202 cons = conss[c]; 8203 consdata = SCIPconsGetData(cons); 8204 assert(consdata != NULL); 8205 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) ) 8206 { 8207 if( !checkCons(scip, consdata, sol) ) 8208 { 8209 /* constraint is violated */ 8210 *result = SCIP_INFEASIBLE; 8211 8212 if( printreason ) 8213 { 8214 SCIP_Real sum = 0.0; 8215 int v; 8216 8217 SCIP_CALL( SCIPprintCons(scip, cons, NULL) ); 8218 8219 for( v = 0; v < consdata->nvars; ++v ) 8220 { 8221 assert(SCIPvarIsBinary(consdata->vars[v])); 8222 8223 sum += SCIPgetSolVal(scip, sol, consdata->vars[v]); 8224 } 8225 SCIPinfoMessage(scip, NULL, ";\n"); 8226 SCIPinfoMessage(scip, NULL, "violation: the right hand side is violated by by %.15g\n", ABS(sum - 1)); 8227 } 8228 } 8229 } 8230 } 8231 8232 return SCIP_OKAY; 8233 } 8234 8235 /** domain propagation method of constraint handler */ 8236 static 8237 SCIP_DECL_CONSPROP(consPropSetppc) 8238 { /*lint --e{715}*/ 8239 SCIP_Bool cutoff; 8240 SCIP_Bool addcut; 8241 SCIP_Bool mustcheck; 8242 SCIP_Bool inpresolve; 8243 int nfixedvars = 0; 8244 int c; 8245 8246 assert(conshdlr != NULL); 8247 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 8248 assert(nconss == 0 || conss != NULL); 8249 assert(result != NULL); 8250 8251 *result = SCIP_DIDNOTFIND; 8252 8253 SCIPdebugMsg(scip, "propagating %d/%d set partitioning / packing / covering constraints\n", nmarkedconss, nconss); 8254 8255 cutoff = FALSE; 8256 inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE); 8257 8258 /* propagate all marked set partitioning / packing / covering constraints */ 8259 for( c = nmarkedconss - 1; c >= 0 && !cutoff; --c ) 8260 { 8261 assert(SCIPconsGetData(conss[c]) != NULL); 8262 8263 /* during presolving, we do not want to propagate constraints with multiaggregated variables. After presolving, 8264 * we want to resolve the multiaggregation to have a clean data structure; All initial constraints should not 8265 * have multiaggregated variables, but this is not true for constraints that were introduced during solving 8266 */ 8267 if( SCIPconsGetData(conss[c])->existmultaggr ) 8268 { 8269 int naddconss, ndelconss; 8270 8271 if( inpresolve ) 8272 continue; 8273 8274 naddconss = ndelconss = 0; 8275 SCIP_CALL( applyFixings(scip, conss[c], &naddconss, &ndelconss, &nfixedvars, &cutoff) ); 8276 8277 if( cutoff ) 8278 break; 8279 } 8280 8281 /* all multiaggregations should be resolved at here */ 8282 assert(inpresolve || ! SCIPconsGetData(conss[c])->existmultaggr); 8283 8284 SCIP_CALL( processFixings(scip, conss[c], &cutoff, &nfixedvars, &addcut, &mustcheck) ); 8285 8286 SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[c]) ); 8287 } 8288 8289 /* return the correct result */ 8290 if( cutoff ) 8291 *result = SCIP_CUTOFF; 8292 else if( nfixedvars > 0 ) 8293 *result = SCIP_REDUCEDDOM; 8294 8295 return SCIP_OKAY; /*lint !e438*/ 8296 } 8297 8298 8299 /** presolving method of constraint handler */ 8300 static 8301 SCIP_DECL_CONSPRESOL(consPresolSetppc) 8302 { /*lint --e{715}*/ 8303 SCIP_CONSHDLRDATA* conshdlrdata; 8304 int oldnfixedvars; 8305 int oldnaggrvars; 8306 int oldndelconss; 8307 int oldnchgcoefs; 8308 int firstchange; 8309 int firstclique; 8310 int lastclique; 8311 int startdelconss; 8312 int c; 8313 SCIP_Bool cutoff; 8314 8315 assert(conshdlr != NULL); 8316 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 8317 assert(scip != NULL); 8318 assert(result != NULL); 8319 8320 *result = SCIP_DIDNOTFIND; 8321 oldnfixedvars = *nfixedvars; 8322 oldndelconss = *ndelconss; 8323 oldnaggrvars = *naggrvars; 8324 oldnchgcoefs = *nchgcoefs; 8325 cutoff = FALSE; 8326 8327 conshdlrdata = SCIPconshdlrGetData(conshdlr); 8328 assert(conshdlrdata != NULL); 8329 8330 /* determine whether we want to run the clique lifting procedure */ 8331 conshdlrdata->enablecliquelifting = conshdlrdata->enablecliquelifting || conshdlrdata->updatedsetppctype 8332 || conshdlrdata->noldfixedvars != SCIPgetNFixedVars(scip) || conshdlrdata->noldimpls != SCIPgetNImplications(scip) 8333 || conshdlrdata->noldcliques != SCIPgetNCliques(scip) || conshdlrdata->noldupgrs != nconss; 8334 8335 /* remember old values */ 8336 startdelconss = *ndelconss; 8337 conshdlrdata->noldimpls = SCIPgetNImplications(scip); 8338 conshdlrdata->noldcliques = SCIPgetNCliques(scip); 8339 conshdlrdata->updatedsetppctype = FALSE; 8340 8341 /* process constraints */ 8342 firstchange = INT_MAX; 8343 firstclique = INT_MAX; 8344 lastclique = -1; 8345 for( c = 0; c < nconss && !SCIPisStopped(scip); ++c ) 8346 { 8347 SCIP_CONS* cons; 8348 SCIP_CONSDATA* consdata; 8349 8350 assert(*result != SCIP_CUTOFF); 8351 8352 cons = conss[c]; 8353 assert(cons != NULL); 8354 consdata = SCIPconsGetData(cons); 8355 assert(consdata != NULL); 8356 8357 /*SCIPdebugMsg(scip, "presolving set partitioning / packing / covering constraint <%s>\n", SCIPconsGetName(cons));*/ 8358 8359 /* remove all variables that are fixed to zero and replace all aggregated variables */ 8360 if( consdata->nfixedzeros > 0 || nnewaggrvars > 0 || nnewaddconss > 0 || nnewupgdconss > 0 8361 || *naggrvars > oldnaggrvars || (nrounds == 0 && SCIPgetNRuns(scip) > 1) ) 8362 { 8363 SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, &cutoff) ); 8364 8365 if( cutoff ) 8366 { 8367 *result = SCIP_CUTOFF; 8368 return SCIP_OKAY; 8369 } 8370 8371 if( SCIPconsIsDeleted(cons) ) 8372 continue; 8373 } 8374 8375 /* find pairs of negated variables in constraint: 8376 * partitioning/packing: all other variables must be zero, constraint is redundant 8377 * covering: constraint is redundant 8378 * 8379 * find sets of equal variables in constraint: 8380 * partitioning/packing: variable must be zero 8381 * covering: multiple entries of variable can be replaced by single entry 8382 */ 8383 SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, &cutoff) ); 8384 8385 if( cutoff ) 8386 { 8387 *result = SCIP_CUTOFF; 8388 return SCIP_OKAY; 8389 } 8390 8391 /* if constraint was deleted while merging, go to the next constraint */ 8392 if( !SCIPconsIsActive(cons) ) 8393 continue; 8394 8395 /* remove fixings found by merging */ 8396 if( consdata->nfixedzeros > 0 ) 8397 { 8398 SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, &cutoff) ); 8399 8400 if( cutoff ) 8401 { 8402 *result = SCIP_CUTOFF; 8403 return SCIP_OKAY; 8404 } 8405 8406 if( SCIPconsIsDeleted(cons) ) 8407 continue; 8408 } 8409 8410 /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if 8411 * possible 8412 */ 8413 SCIP_CALL( presolvePropagateCons(scip, cons, TRUE, NULL, NULL, NULL, NULL, nfixedvars, naggrvars, ndelconss, &cutoff) ); 8414 8415 if( cutoff ) 8416 { 8417 *result = SCIP_CUTOFF; 8418 return SCIP_OKAY; 8419 } 8420 8421 /* if constraint was deleted while propagation, go to the next constraint */ 8422 if( !SCIPconsIsActive(cons) ) 8423 continue; 8424 8425 /* remove fixings found by presolvePropagateCons() */ 8426 if( consdata->nfixedzeros > 0 ) 8427 { 8428 SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, &cutoff) ); 8429 8430 if( cutoff ) 8431 { 8432 *result = SCIP_CUTOFF; 8433 return SCIP_OKAY; 8434 } 8435 8436 if( SCIPconsIsDeleted(cons) ) 8437 continue; 8438 } 8439 8440 /* perform dual reductions */ 8441 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) ) 8442 { 8443 SCIP_CALL( dualPresolving(scip, cons, nfixedvars, ndelconss, naggrvars, result) ); 8444 8445 /* if dual reduction deleted the constraint we take the next */ 8446 if( !SCIPconsIsActive(cons) ) 8447 continue; 8448 } 8449 8450 /* remember the first changed constraint to begin the next redundancy round with */ 8451 if( firstchange == INT_MAX && consdata->changed ) 8452 firstchange = c; 8453 8454 /* remember the first and last constraints for which we have to add the clique information */ 8455 if( !consdata->cliqueadded && consdata->nvars >= 2 ) 8456 { 8457 if( firstclique == INT_MAX ) 8458 firstclique = c; 8459 lastclique = c; 8460 } 8461 } 8462 8463 /* update result pointer */ 8464 if( oldnfixedvars < *nfixedvars || oldnaggrvars < *naggrvars || oldndelconss < *ndelconss || oldnchgcoefs < *nchgcoefs ) 8465 *result = SCIP_SUCCESS; 8466 8467 if( firstchange < nconss && conshdlrdata->presolusehashing ) 8468 { 8469 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */ 8470 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &firstchange, ndelconss, nchgsides) ); 8471 if( oldndelconss < *ndelconss ) 8472 *result = SCIP_SUCCESS; 8473 } 8474 8475 /* determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and 8476 * negated) in any combination of set-partitioning and set-packing constraints 8477 */ 8478 if( nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 8479 && ((conshdlrdata->nsetpart > 0 && !SCIPdoNotMultaggr(scip) && conshdlrdata->conshdlrlinear != NULL) 8480 || (conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) 8481 && conshdlrdata->nsetpart < nconss && !SCIPdoNotAggr(scip))) ) 8482 { 8483 SCIP_CALL( removeDoubleAndSingletonsAndPerformDualpresolve(scip, conss, nconss, conshdlrdata->dualpresolving 8484 && SCIPallowStrongDualReds(scip), conshdlrdata->conshdlrlinear != NULL, nfixedvars, 8485 naggrvars, ndelconss, nchgcoefs, nchgsides, &cutoff) ); 8486 8487 if( cutoff ) 8488 { 8489 *result = SCIP_CUTOFF; 8490 return SCIP_OKAY; 8491 } 8492 else if( oldnfixedvars < *nfixedvars || oldnaggrvars < *naggrvars || oldndelconss < *ndelconss ) 8493 *result = SCIP_SUCCESS; 8494 } 8495 8496 /* clique lifting */ 8497 if( conshdlrdata->cliquelifting && conshdlrdata->enablecliquelifting && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 ) 8498 { 8499 /* add cliques first before lifting variables */ 8500 SCIP_CALL( addCliques(scip, conss, nconss, firstclique, lastclique, naddconss, ndelconss, nchgbds, &cutoff) ); 8501 8502 if( cutoff ) 8503 { 8504 *result = SCIP_CUTOFF; 8505 return SCIP_OKAY; 8506 } 8507 8508 firstclique = nconss; 8509 lastclique = -1; 8510 8511 /* lift variables and check for fixings due to clique information */ 8512 SCIP_CALL( preprocessCliques(scip, conshdlrdata, conss, nconss, nrounds, &firstchange, &firstclique, 8513 &lastclique, nfixedvars, naggrvars, ndelconss, nchgcoefs, &cutoff) ); 8514 ++(conshdlrdata->nclqpresolve); 8515 8516 if( cutoff ) 8517 { 8518 *result = SCIP_CUTOFF; 8519 return SCIP_OKAY; 8520 } 8521 else if( oldnfixedvars < *nfixedvars || oldnaggrvars < *naggrvars || oldndelconss < *ndelconss || oldnchgcoefs < *nchgcoefs ) 8522 *result = SCIP_SUCCESS; 8523 8524 /* remember the number of fixings */ 8525 conshdlrdata->noldfixedvars = *nfixedvars + *naggrvars; 8526 conshdlrdata->enablecliquelifting = FALSE; 8527 } 8528 8529 if( oldndelconss == *ndelconss && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 ) 8530 { 8531 /* check constraints for redundancy */ 8532 if( conshdlrdata->presolpairwise ) 8533 { 8534 SCIP_Longint npaircomparisons = 0; 8535 8536 oldndelconss = *ndelconss; 8537 oldnfixedvars = *nfixedvars; 8538 8539 for( c = firstchange; c < nconss && !SCIPisStopped(scip); ++c ) 8540 { 8541 assert(*result != SCIP_CUTOFF); 8542 8543 if( SCIPconsIsActive(conss[c]) && !SCIPconsIsModifiable(conss[c]) ) 8544 { 8545 npaircomparisons += (SCIPconsGetData(conss[c])->changed) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange); 8546 8547 SCIP_CALL( removeRedundantConstraints(scip, conss, firstchange, c, &cutoff, nfixedvars, ndelconss, nchgsides) ); 8548 if( cutoff ) 8549 { 8550 *result = SCIP_CUTOFF; 8551 return SCIP_OKAY; 8552 } 8553 8554 if( npaircomparisons > NMINCOMPARISONS ) 8555 { 8556 if( (*ndelconss - oldndelconss + *nfixedvars - oldnfixedvars) / ((SCIP_Real)npaircomparisons) < MINGAINPERNMINCOMPARISONS ) 8557 break; 8558 oldndelconss = *ndelconss; 8559 oldnfixedvars = *nfixedvars; 8560 npaircomparisons = 0; 8561 *result = SCIP_SUCCESS; 8562 } 8563 } 8564 } 8565 } 8566 } 8567 8568 /* add cliques after lifting variables */ 8569 SCIP_CALL( addCliques(scip, conss, nconss, MIN(firstclique, nconss), MIN(lastclique, nconss), naddconss, ndelconss, 8570 nchgbds, &cutoff) ); 8571 8572 if( cutoff ) 8573 *result = SCIP_CUTOFF; 8574 8575 conshdlrdata->noldupgrs = nconss - (*ndelconss - startdelconss); 8576 8577 return SCIP_OKAY; 8578 } 8579 8580 8581 /** propagation conflict resolving method of constraint handler */ 8582 static 8583 SCIP_DECL_CONSRESPROP(consRespropSetppc) 8584 { /*lint --e{715}*/ 8585 SCIP_CONSDATA* consdata; 8586 int v; 8587 8588 assert(conshdlr != NULL); 8589 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 8590 assert(cons != NULL); 8591 assert(infervar != NULL); 8592 assert(result != NULL); 8593 8594 consdata = SCIPconsGetData(cons); 8595 assert(consdata != NULL); 8596 8597 SCIPdebugMsg(scip, "conflict resolving method of set partitioning / packing / covering constraint handler\n"); 8598 8599 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING 8600 || ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING 8601 && SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE) > 0.5) ) 8602 { 8603 #ifndef NDEBUG 8604 SCIP_Bool confvarfound; 8605 #endif 8606 8607 /* the inference constraint is a set partitioning or covering constraint with the inference variable inferred to 1.0: 8608 * the reason for the deduction is the assignment of 0.0 to all other variables 8609 */ 8610 #ifndef NDEBUG 8611 confvarfound = FALSE; 8612 #endif 8613 for( v = 0; v < consdata->nvars; ++v ) 8614 { 8615 if( consdata->vars[v] != infervar ) 8616 { 8617 /* the reason variable must be assigned to zero */ 8618 assert(SCIPgetVarUbAtIndex(scip, consdata->vars[v], bdchgidx, FALSE) < 0.5); 8619 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) ); 8620 } 8621 #ifndef NDEBUG 8622 else 8623 { 8624 assert(!confvarfound); 8625 confvarfound = TRUE; 8626 } 8627 #endif 8628 } 8629 assert(confvarfound); 8630 } 8631 else 8632 { 8633 /* the inference constraint is a set partitioning or packing constraint with the inference variable inferred to 0.0: 8634 * the reason for the deduction is the assignment of 1.0 to a single variable 8635 */ 8636 assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < 0.5); 8637 8638 if( inferinfo >= 0 ) 8639 { 8640 assert(SCIPgetVarLbAtIndex(scip, consdata->vars[inferinfo], bdchgidx, FALSE) > 0.5); 8641 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[inferinfo]) ); 8642 } 8643 else 8644 { 8645 for( v = 0; v < consdata->nvars; ++v ) 8646 { 8647 if( SCIPgetVarLbAtIndex(scip, consdata->vars[v], bdchgidx, FALSE) > 0.5 ) 8648 { 8649 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) ); 8650 break; 8651 } 8652 } 8653 assert(v < consdata->nvars); 8654 } 8655 } 8656 8657 *result = SCIP_SUCCESS; 8658 8659 return SCIP_OKAY; 8660 } 8661 8662 8663 /** variable rounding lock method of constraint handler */ 8664 static 8665 SCIP_DECL_CONSLOCK(consLockSetppc) 8666 { /*lint --e{715}*/ 8667 SCIP_CONSDATA* consdata; 8668 int nlocksdown; 8669 int nlocksup; 8670 int i; 8671 8672 consdata = SCIPconsGetData(cons); 8673 assert(consdata != NULL); 8674 8675 switch( consdata->setppctype ) 8676 { 8677 case SCIP_SETPPCTYPE_PARTITIONING: 8678 nlocksdown = nlockspos + nlocksneg; 8679 nlocksup = nlockspos + nlocksneg; 8680 break; 8681 case SCIP_SETPPCTYPE_PACKING: 8682 nlocksdown = nlocksneg; 8683 nlocksup = nlockspos; 8684 break; 8685 case SCIP_SETPPCTYPE_COVERING: 8686 nlocksdown = nlockspos; 8687 nlocksup = nlocksneg; 8688 break; 8689 default: 8690 SCIPerrorMessage("unknown setppc type\n"); 8691 return SCIP_INVALIDDATA; 8692 } 8693 8694 for( i = 0; i < consdata->nvars; ++i ) 8695 { 8696 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksdown, nlocksup) ); 8697 } 8698 8699 return SCIP_OKAY; 8700 } 8701 8702 8703 /** constraint activation notification method of constraint handler */ 8704 static 8705 SCIP_DECL_CONSACTIVE(consActiveSetppc) 8706 { /*lint --e{715}*/ 8707 assert(cons != NULL); 8708 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 8709 assert(SCIPconsIsTransformed(cons)); 8710 8711 SCIPdebugMsg(scip, "activation information for set partitioning / packing / covering constraint <%s>\n", 8712 SCIPconsGetName(cons)); 8713 8714 /* we only might add the constraint to the propagation list, when we are not activating it in probing mode */ 8715 if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMING ) 8716 { 8717 SCIP_CONSDATA* consdata = SCIPconsGetData(cons); 8718 assert(consdata != NULL); 8719 8720 if( consdata->nfixedones >= 1 || consdata->nfixedzeros >= consdata->nvars - 1 ) 8721 { 8722 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) ); 8723 } 8724 } 8725 8726 #ifdef VARUSES 8727 /* increase the number of uses for each variable in the constraint */ 8728 SCIP_CALL( consdataIncVaruses(scip, SCIPconshdlrGetData(conshdlr), SCIPconsGetData(cons)) ); 8729 #endif 8730 8731 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPisNLPConstructed(scip) ) 8732 { 8733 SCIP_CALL( addNlrow(scip, cons) ); 8734 } 8735 8736 return SCIP_OKAY; 8737 } 8738 8739 8740 /** constraint deactivation notification method of constraint handler */ 8741 static 8742 SCIP_DECL_CONSDEACTIVE(consDeactiveSetppc) 8743 { /*lint --e{715}*/ 8744 SCIP_CONSDATA* consdata; 8745 8746 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 8747 assert(SCIPconsIsTransformed(cons)); 8748 8749 SCIPdebugMsg(scip, "deactivation information for set partitioning / packing / covering constraint <%s>\n", 8750 SCIPconsGetName(cons)); 8751 8752 /* get constraint data */ 8753 consdata = SCIPconsGetData(cons); 8754 assert(consdata != NULL); 8755 8756 #ifdef VARUSES 8757 /* decrease the number of uses for each variable in the constraint */ 8758 SCIP_CALL( consdataDecVaruses(scip, SCIPconshdlrGetData(conshdlr), condata) ); 8759 #endif 8760 8761 if( SCIPconsIsDeleted(cons) ) 8762 { 8763 SCIP_CONSHDLRDATA* conshdlrdata; 8764 8765 /* get event handler */ 8766 conshdlrdata = SCIPconshdlrGetData(conshdlr); 8767 assert(conshdlrdata != NULL); 8768 assert(conshdlrdata->eventhdlr != NULL); 8769 8770 /* if constraint belongs to transformed problem space, drop bound change events on variables */ 8771 if( consdata->nvars > 0 && SCIPvarIsTransformed(consdata->vars[0]) ) 8772 { 8773 SCIP_CALL( dropAllEvents(scip, cons, conshdlrdata->eventhdlr) ); 8774 } 8775 } 8776 8777 /* remove row from NLP, if still in solving 8778 * if we are in exitsolve, the whole NLP will be freed anyway 8779 */ 8780 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL ) 8781 { 8782 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) ); 8783 } 8784 8785 return SCIP_OKAY; 8786 } 8787 8788 /** variable deletion method of constraint handler */ 8789 static 8790 SCIP_DECL_CONSDELVARS(consDelvarsSetppc) 8791 { 8792 assert( scip != NULL ); 8793 assert( conshdlr != NULL ); 8794 assert( conss != NULL || nconss == 0 ); 8795 8796 if( nconss > 0 ) 8797 { 8798 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) ); 8799 } 8800 8801 return SCIP_OKAY; 8802 } 8803 8804 8805 8806 /** constraint display method of constraint handler */ 8807 static 8808 SCIP_DECL_CONSPRINT(consPrintSetppc) 8809 { /*lint --e{715}*/ 8810 assert( scip != NULL ); 8811 assert( conshdlr != NULL ); 8812 assert( cons != NULL ); 8813 8814 SCIP_CALL( consdataPrint(scip, SCIPconsGetData(cons), file) ); 8815 8816 return SCIP_OKAY; 8817 } 8818 8819 /** constraint copying method of constraint handler */ 8820 static 8821 SCIP_DECL_CONSCOPY(consCopySetppc) 8822 { /*lint --e{715}*/ 8823 SCIP_VAR** sourcevars; 8824 const char* consname; 8825 SCIP_Real lhs; 8826 SCIP_Real rhs; 8827 int nvars; 8828 SCIP_SETPPCTYPE type; 8829 8830 /* get variables and coefficients of the source constraint */ 8831 sourcevars = SCIPgetVarsSetppc(sourcescip, sourcecons); 8832 nvars = SCIPgetNVarsSetppc(sourcescip, sourcecons); 8833 8834 /* get setppc type */ 8835 type = SCIPgetTypeSetppc(sourcescip, sourcecons); 8836 lhs = -SCIPinfinity(scip); 8837 rhs = SCIPinfinity(scip); 8838 8839 switch( type ) 8840 { 8841 case SCIP_SETPPCTYPE_PARTITIONING: 8842 lhs = 1.0; 8843 rhs = 1.0; 8844 break; 8845 case SCIP_SETPPCTYPE_PACKING: 8846 rhs = 1.0; 8847 break; 8848 case SCIP_SETPPCTYPE_COVERING: 8849 lhs = 1.0; 8850 break; 8851 default: 8852 SCIPerrorMessage("unknown setppc type\n"); 8853 return SCIP_INVALIDDATA; 8854 } 8855 8856 if( name != NULL ) 8857 consname = name; 8858 else 8859 consname = SCIPconsGetName(sourcecons); 8860 8861 /* copy the logic using the linear constraint copy method */ 8862 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, NULL, 8863 lhs, rhs, varmap, consmap, 8864 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) ); 8865 assert(cons != NULL); 8866 8867 return SCIP_OKAY; 8868 } 8869 8870 /** constraint parsing method of constraint handler */ 8871 static 8872 SCIP_DECL_CONSPARSE(consParseSetppc) 8873 { /*lint --e{715}*/ 8874 SCIP_VAR** vars; 8875 int nvars; 8876 8877 assert(scip != NULL); 8878 assert(success != NULL); 8879 assert(str != NULL); 8880 assert(name != NULL); 8881 assert(cons != NULL); 8882 8883 *success = TRUE; 8884 8885 nvars = 0; 8886 vars = NULL; 8887 8888 /* check if lhs is just 0 */ 8889 if( str[0] == '0' ) 8890 { 8891 assert(str[1] == ' '); 8892 str += 2; 8893 } 8894 else 8895 { 8896 SCIP_Real* coefs; 8897 char* endptr; 8898 int coefssize; 8899 int requsize; 8900 8901 /* initialize buffers for storing the coefficients */ 8902 coefssize = 100; 8903 SCIP_CALL( SCIPallocBufferArray(scip, &vars, coefssize) ); 8904 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, coefssize) ); 8905 8906 /* parse linear sum to get variables and coefficients */ 8907 SCIP_CALL( SCIPparseVarsLinearsum(scip, str, vars, coefs, &nvars, coefssize, &requsize, &endptr, success) ); 8908 8909 if( *success && requsize > coefssize ) 8910 { 8911 /* realloc buffers and try again */ 8912 coefssize = requsize; 8913 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, coefssize) ); 8914 SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, coefssize) ); 8915 8916 SCIP_CALL( SCIPparseVarsLinearsum(scip, str, vars, coefs, &nvars, coefssize, &requsize, &endptr, success) ); 8917 assert(!*success || requsize <= coefssize); /* if successful, then should have had enough space now */ 8918 } 8919 8920 if( !*success ) 8921 { 8922 SCIPerrorMessage("no luck in parsing linear sum '%s'\n", str); 8923 } 8924 else 8925 str = endptr; 8926 8927 /* free coefficient array */ 8928 SCIPfreeBufferArray(scip, &coefs); 8929 } 8930 8931 /* remove white spaces */ 8932 SCIP_CALL( SCIPskipSpace((char**)&str) ); 8933 8934 if( *success ) 8935 { 8936 switch( *str ) 8937 { 8938 case '=' : 8939 SCIP_CALL( SCIPcreateConsSetpart(scip, cons, name, nvars, vars, 8940 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) ); 8941 break; 8942 case '<' : 8943 SCIP_CALL( SCIPcreateConsSetpack(scip, cons, name, nvars, vars, 8944 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) ); 8945 break; 8946 case '>' : 8947 SCIP_CALL( SCIPcreateConsSetcover(scip, cons, name, nvars, vars, 8948 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) ); 8949 break; 8950 default: 8951 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing setppc type\n"); 8952 *success = FALSE; 8953 break; 8954 } 8955 } 8956 8957 /* free variable array */ 8958 SCIPfreeBufferArrayNull(scip, &vars); 8959 8960 return SCIP_OKAY; 8961 } 8962 8963 /** constraint method of constraint handler which returns the variables (if possible) */ 8964 static 8965 SCIP_DECL_CONSGETVARS(consGetVarsSetppc) 8966 { /*lint --e{715}*/ 8967 SCIP_CONSDATA* consdata; 8968 8969 consdata = SCIPconsGetData(cons); 8970 assert(consdata != NULL); 8971 8972 if( varssize < consdata->nvars ) 8973 (*success) = FALSE; 8974 else 8975 { 8976 assert(vars != NULL); 8977 8978 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars); 8979 (*success) = TRUE; 8980 } 8981 8982 return SCIP_OKAY; 8983 } 8984 8985 /** constraint method of constraint handler which returns the number of variables (if possible) */ 8986 static 8987 SCIP_DECL_CONSGETNVARS(consGetNVarsSetppc) 8988 { /*lint --e{715}*/ 8989 SCIP_CONSDATA* consdata; 8990 8991 consdata = SCIPconsGetData(cons); 8992 assert(consdata != NULL); 8993 8994 (*nvars) = consdata->nvars; 8995 (*success) = TRUE; 8996 8997 return SCIP_OKAY; 8998 } 8999 9000 /** constraint handler method which returns the permutation symmetry detection graph of a constraint */ 9001 static 9002 SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphSetppc) 9003 { /*lint --e{715}*/ 9004 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) ); 9005 9006 return SCIP_OKAY; 9007 } 9008 9009 /** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */ 9010 static 9011 SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphSetppc) 9012 { /*lint --e{715}*/ 9013 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) ); 9014 9015 return SCIP_OKAY; 9016 } 9017 9018 /* 9019 * Callback methods of event handler 9020 */ 9021 9022 static 9023 SCIP_DECL_EVENTEXEC(eventExecSetppc) 9024 { /*lint --e{715}*/ 9025 SCIP_CONS* cons; 9026 SCIP_CONSDATA* consdata; 9027 SCIP_EVENTTYPE eventtype; 9028 9029 assert(eventhdlr != NULL); 9030 assert(eventdata != NULL); 9031 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 9032 assert(event != NULL); 9033 9034 /*debugMsg(scip, "Exec method of bound change event handler for set partitioning / packing / covering constraints\n");*/ 9035 9036 cons = (SCIP_CONS*)eventdata; 9037 assert(cons != NULL); 9038 9039 consdata = SCIPconsGetData(cons); 9040 assert(consdata != NULL); 9041 9042 eventtype = SCIPeventGetType(event); 9043 9044 switch( eventtype ) 9045 { 9046 case SCIP_EVENTTYPE_LBTIGHTENED: 9047 consdata->nfixedones++; 9048 break; 9049 case SCIP_EVENTTYPE_LBRELAXED: 9050 consdata->nfixedones--; 9051 break; 9052 case SCIP_EVENTTYPE_UBTIGHTENED: 9053 consdata->nfixedzeros++; 9054 break; 9055 case SCIP_EVENTTYPE_UBRELAXED: 9056 consdata->nfixedzeros--; 9057 break; 9058 case SCIP_EVENTTYPE_VARDELETED: 9059 consdata->varsdeleted = TRUE; 9060 break; 9061 case SCIP_EVENTTYPE_VARFIXED: 9062 if( consdata->merged ) 9063 { 9064 SCIP_VAR* var = SCIPeventGetVar(event); 9065 9066 /* this event should only arise during the presolving stage */ 9067 assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING); 9068 assert(var != NULL); 9069 9070 /* one variable was changed to a negated or aggregated variable, so maybe we can merge again */ 9071 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED && SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5 ) 9072 consdata->merged = FALSE; 9073 } 9074 9075 if( !consdata->existmultaggr ) 9076 { 9077 SCIP_VAR* var = SCIPeventGetVar(event); 9078 assert(var != NULL); 9079 9080 if( SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR ) 9081 consdata->existmultaggr = TRUE; 9082 } 9083 break; 9084 default: 9085 SCIPerrorMessage("invalid event type\n"); 9086 return SCIP_INVALIDDATA; 9087 } 9088 assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars); 9089 assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars); 9090 9091 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED ) 9092 { 9093 if( consdata->nfixedones >= 1 || consdata->nfixedzeros >= consdata->nvars - 1 ) 9094 { 9095 consdata->presolpropagated = FALSE; 9096 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) ); 9097 } 9098 else if( (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE) && (consdata->nfixedzeros >= consdata->nvars - 2) ) 9099 { 9100 consdata->presolpropagated = FALSE; 9101 } 9102 } 9103 9104 /*debugMsg(scip, " -> constraint has %d zero-fixed and %d one-fixed of %d variables\n", 9105 consdata->nfixedzeros, consdata->nfixedones, consdata->nvars);*/ 9106 9107 return SCIP_OKAY; 9108 } 9109 9110 9111 9112 9113 /* 9114 * Callback methods of conflict handler 9115 */ 9116 9117 /** conflict processing method of conflict handler (called when conflict was found) */ 9118 static 9119 SCIP_DECL_CONFLICTEXEC(conflictExecSetppc) 9120 { /*lint --e{715}*/ 9121 SCIP_VAR** vars; 9122 int i; 9123 9124 assert(conflicthdlr != NULL); 9125 assert(strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0); 9126 assert(bdchginfos != NULL || nbdchginfos == 0); 9127 assert(result != NULL); 9128 9129 /* don't process already resolved conflicts */ 9130 if( resolved ) 9131 { 9132 *result = SCIP_DIDNOTRUN; 9133 return SCIP_OKAY; 9134 } 9135 9136 *result = SCIP_DIDNOTFIND; 9137 9138 /* for two (binary) variables we will create a set packing constraint and add the clique information of the conflict is global */ 9139 if( nbdchginfos == 2 ) 9140 { 9141 SCIP_CONS* cons; 9142 char consname[SCIP_MAXSTRLEN]; 9143 SCIP_VAR* twovars[2]; 9144 9145 assert(bdchginfos != NULL); 9146 9147 twovars[0] = SCIPbdchginfoGetVar(bdchginfos[0]); 9148 9149 /* we can only treat binary variables */ 9150 if( !SCIPvarIsBinary(twovars[0]) ) 9151 return SCIP_OKAY; 9152 9153 /* if the variable is fixed to zero in the conflict set, we have to use its negation */ 9154 if( SCIPbdchginfoGetNewbound(bdchginfos[0]) < 0.5 ) 9155 { 9156 SCIP_CALL( SCIPgetNegatedVar(scip, twovars[0], &twovars[0]) ); 9157 } 9158 9159 twovars[1] = SCIPbdchginfoGetVar(bdchginfos[1]); 9160 9161 /* we can only treat binary variables */ 9162 if( !SCIPvarIsBinary(twovars[1]) ) 9163 return SCIP_OKAY; 9164 9165 /* if the variable is fixed to zero in the conflict set, we have to use its negation */ 9166 if( SCIPbdchginfoGetNewbound(bdchginfos[1]) < 0.5 ) 9167 { 9168 SCIP_CALL( SCIPgetNegatedVar(scip, twovars[1], &twovars[1]) ); 9169 } 9170 9171 /* create a constraint out of the conflict set */ 9172 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cf%d_%" SCIP_LONGINT_FORMAT, SCIPgetNRuns(scip), SCIPgetNConflictConssApplied(scip)); 9173 SCIP_CALL( SCIPcreateConsSetpack(scip, &cons, consname, 2, twovars, 9174 FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) ); 9175 9176 /* if the constraint gets globally added, we also add the clique information */ 9177 if( !SCIPconsIsLocal(cons) ) 9178 { 9179 SCIP_Bool infeasible; 9180 int ncliquebdchgs; 9181 9182 SCIP_CALL( SCIPaddClique(scip, twovars, NULL, 2, FALSE, &infeasible, &ncliquebdchgs) ); 9183 9184 SCIPdebugMsg(scip, "new clique of conflict constraint %s led to %d fixings\n", consname, ncliquebdchgs); 9185 9186 if( infeasible ) 9187 { 9188 SCIPdebugMsg(scip, "new clique of conflict constraint %s led to infeasibility\n", consname); 9189 } 9190 } 9191 9192 /* add conflict to SCIP */ 9193 SCIP_CALL( SCIPaddConflict(scip, node, cons, validnode, conftype, cutoffinvolved) ); 9194 9195 *result = SCIP_CONSADDED; 9196 9197 return SCIP_OKAY; 9198 } 9199 9200 /* create array of variables in conflict constraint */ 9201 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nbdchginfos) ); 9202 for( i = 0; i < nbdchginfos; ++i ) 9203 { 9204 assert(bdchginfos != NULL); 9205 9206 vars[i] = SCIPbdchginfoGetVar(bdchginfos[i]); 9207 9208 /* we can only treat binary variables */ 9209 if( !SCIPvarIsBinary(vars[i]) ) 9210 break; 9211 9212 /* if the variable is fixed to one in the conflict set, we have to use its negation */ 9213 if( SCIPbdchginfoGetNewbound(bdchginfos[i]) > 0.5 ) 9214 { 9215 SCIP_CALL( SCIPgetNegatedVar(scip, vars[i], &vars[i]) ); 9216 } 9217 } 9218 9219 if( i == nbdchginfos ) 9220 { 9221 SCIP_CONS* cons; 9222 char consname[SCIP_MAXSTRLEN]; 9223 9224 /* create a constraint out of the conflict set */ 9225 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cf%d_%" SCIP_LONGINT_FORMAT, SCIPgetNRuns(scip), SCIPgetNConflictConssApplied(scip)); 9226 SCIP_CALL( SCIPcreateConsSetcover(scip, &cons, consname, nbdchginfos, vars, 9227 FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) ); 9228 SCIP_CALL( SCIPaddConsNode(scip, node, cons, validnode) ); 9229 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 9230 9231 *result = SCIP_CONSADDED; 9232 } 9233 9234 /* free temporary memory */ 9235 SCIPfreeBufferArray(scip, &vars); 9236 9237 return SCIP_OKAY; 9238 } 9239 9240 9241 9242 9243 /* 9244 * constraint specific interface methods 9245 */ 9246 9247 /** creates the handler for set partitioning / packing / covering constraints and includes it in SCIP */ 9248 SCIP_RETCODE SCIPincludeConshdlrSetppc( 9249 SCIP* scip /**< SCIP data structure */ 9250 ) 9251 { 9252 SCIP_CONSHDLRDATA* conshdlrdata; 9253 SCIP_CONSHDLR* conshdlr; 9254 SCIP_EVENTHDLR* eventhdlr; 9255 9256 /* create event handler for bound change events */ 9257 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, 9258 eventExecSetppc, NULL) ); 9259 9260 /* create conflict handler for setppc constraints */ 9261 SCIP_CALL( SCIPincludeConflicthdlrBasic(scip, NULL, CONFLICTHDLR_NAME, CONFLICTHDLR_DESC, CONFLICTHDLR_PRIORITY, 9262 conflictExecSetppc, NULL) ); 9263 9264 /* create constraint handler data */ 9265 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) ); 9266 9267 /* include constraint handler */ 9268 SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC, 9269 CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS, 9270 consEnfolpSetppc, consEnfopsSetppc, consCheckSetppc, consLockSetppc, 9271 conshdlrdata) ); 9272 assert(conshdlr != NULL); 9273 9274 /* set non-fundamental callbacks via specific setter functions */ 9275 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveSetppc) ); 9276 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveSetppc) ); 9277 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySetppc, consCopySetppc) ); 9278 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSetppc) ); 9279 SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsSetppc) ); 9280 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreSetppc) ); 9281 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSetppc) ); 9282 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolSetppc) ); 9283 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSetppc) ); 9284 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSetppc) ); 9285 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSetppc) ); 9286 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitSetppc) ); 9287 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSetppc) ); 9288 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSetppc) ); 9289 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSetppc, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) ); 9290 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSetppc) ); 9291 SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropSetppc, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP, 9292 CONSHDLR_PROP_TIMING) ); 9293 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSetppc) ); 9294 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSetppc, consSepasolSetppc, CONSHDLR_SEPAFREQ, 9295 CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) ); 9296 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSetppc) ); 9297 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSetppc) ); 9298 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphSetppc) ); 9299 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphSetppc) ); 9300 9301 conshdlrdata->conshdlrlinear = SCIPfindConshdlr(scip,"linear"); 9302 9303 if( conshdlrdata->conshdlrlinear != NULL ) 9304 { 9305 /* include the linear constraint to setppc constraint upgrade in the linear constraint handler */ 9306 SCIP_CALL( SCIPincludeLinconsUpgrade(scip, linconsUpgdSetppc, LINCONSUPGD_PRIORITY, CONSHDLR_NAME) ); 9307 } 9308 if( SCIPfindConshdlr(scip, "nonlinear") != NULL ) 9309 { 9310 /* notify function that upgrades quadratic constraint to setpacking */ 9311 SCIP_CALL( SCIPincludeConsUpgradeNonlinear(scip, nonlinUpgdSetppc, NONLINCONSUPGD_PRIORITY, TRUE, CONSHDLR_NAME) ); 9312 } 9313 9314 /* set partitioning constraint handler parameters */ 9315 SCIP_CALL( SCIPaddIntParam(scip, 9316 "constraints/" CONSHDLR_NAME "/npseudobranches", 9317 "number of children created in pseudo branching (0: disable pseudo branching)", 9318 &conshdlrdata->npseudobranches, TRUE, DEFAULT_NPSEUDOBRANCHES, 0, INT_MAX, NULL, NULL) ); 9319 SCIP_CALL( SCIPaddBoolParam(scip, 9320 "constraints/" CONSHDLR_NAME "/presolpairwise", 9321 "should pairwise constraint comparison be performed in presolving?", 9322 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) ); 9323 SCIP_CALL( SCIPaddBoolParam(scip, 9324 "constraints/" CONSHDLR_NAME "/presolusehashing", 9325 "should hash table be used for detecting redundant constraints in advance", 9326 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) ); 9327 SCIP_CALL( SCIPaddBoolParam(scip, 9328 "constraints/" CONSHDLR_NAME "/dualpresolving", 9329 "should dual presolving steps be performed?", 9330 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) ); 9331 SCIP_CALL( SCIPaddBoolParam(scip, 9332 "constraints/" CONSHDLR_NAME "/cliquelifting", 9333 " should we try to lift variables into other clique constraints, fix variables, aggregate them, and also shrink the amount of variables in clique constraints", 9334 &conshdlrdata->cliquelifting, TRUE, DEFAULT_CLIQUELIFTING, NULL, NULL) ); 9335 SCIP_CALL( SCIPaddBoolParam(scip, 9336 "constraints/" CONSHDLR_NAME "/addvariablesascliques", 9337 "should we try to generate extra cliques out of all binary variables to maybe fasten redundant constraint detection", 9338 &conshdlrdata->addvariablesascliques, TRUE, DEFAULT_ADDVARIABLESASCLIQUES, NULL, NULL) ); 9339 SCIP_CALL( SCIPaddBoolParam(scip, 9340 "constraints/" CONSHDLR_NAME "/cliqueshrinking", 9341 "should we try to shrink the number of variables in a clique constraints, by replacing more than one variable by only one", 9342 &conshdlrdata->cliqueshrinking, TRUE, DEFAULT_CLIQUESHRINKING, NULL, NULL) ); 9343 9344 return SCIP_OKAY; 9345 } 9346 9347 /** creates and captures a set partitioning constraint 9348 * 9349 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons() 9350 */ 9351 SCIP_RETCODE SCIPcreateConsSetpart( 9352 SCIP* scip, /**< SCIP data structure */ 9353 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 9354 const char* name, /**< name of constraint */ 9355 int nvars, /**< number of variables in the constraint */ 9356 SCIP_VAR** vars, /**< array with variables of constraint entries */ 9357 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? 9358 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ 9359 SCIP_Bool separate, /**< should the constraint be separated during LP processing? 9360 * Usually set to TRUE. */ 9361 SCIP_Bool enforce, /**< should the constraint be enforced during node processing? 9362 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 9363 SCIP_Bool check, /**< should the constraint be checked for feasibility? 9364 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 9365 SCIP_Bool propagate, /**< should the constraint be propagated during node processing? 9366 * Usually set to TRUE. */ 9367 SCIP_Bool local, /**< is constraint only valid locally? 9368 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ 9369 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? 9370 * Usually set to FALSE. In column generation applications, set to TRUE if pricing 9371 * adds coefficients to this constraint. */ 9372 SCIP_Bool dynamic, /**< is constraint subject to aging? 9373 * Usually set to FALSE. Set to TRUE for own cuts which 9374 * are separated as constraints. */ 9375 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup? 9376 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */ 9377 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even 9378 * if it may be moved to a more global node? 9379 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */ 9380 ) 9381 { 9382 return createConsSetppc(scip, cons, name, nvars, vars, SCIP_SETPPCTYPE_PARTITIONING, 9383 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode); 9384 } 9385 9386 /** creates and captures a set partitioning constraint with all constraint flags set 9387 * to their default values 9388 * 9389 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons() 9390 */ 9391 SCIP_RETCODE SCIPcreateConsBasicSetpart( 9392 SCIP* scip, /**< SCIP data structure */ 9393 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 9394 const char* name, /**< name of constraint */ 9395 int nvars, /**< number of variables in the constraint */ 9396 SCIP_VAR** vars /**< array with variables of constraint entries */ 9397 ) 9398 { 9399 SCIP_CALL( SCIPcreateConsSetpart(scip, cons, name, nvars, vars, 9400 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); 9401 9402 return SCIP_OKAY; 9403 } 9404 9405 /** creates and captures a set packing constraint 9406 * 9407 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons() 9408 */ 9409 SCIP_RETCODE SCIPcreateConsSetpack( 9410 SCIP* scip, /**< SCIP data structure */ 9411 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 9412 const char* name, /**< name of constraint */ 9413 int nvars, /**< number of variables in the constraint */ 9414 SCIP_VAR** vars, /**< array with variables of constraint entries */ 9415 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? 9416 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ 9417 SCIP_Bool separate, /**< should the constraint be separated during LP processing? 9418 * Usually set to TRUE. */ 9419 SCIP_Bool enforce, /**< should the constraint be enforced during node processing? 9420 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 9421 SCIP_Bool check, /**< should the constraint be checked for feasibility? 9422 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 9423 SCIP_Bool propagate, /**< should the constraint be propagated during node processing? 9424 * Usually set to TRUE. */ 9425 SCIP_Bool local, /**< is constraint only valid locally? 9426 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ 9427 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? 9428 * Usually set to FALSE. In column generation applications, set to TRUE if pricing 9429 * adds coefficients to this constraint. */ 9430 SCIP_Bool dynamic, /**< is constraint subject to aging? 9431 * Usually set to FALSE. Set to TRUE for own cuts which 9432 * are separated as constraints. */ 9433 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup? 9434 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */ 9435 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even 9436 * if it may be moved to a more global node? 9437 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */ 9438 ) 9439 { 9440 return createConsSetppc(scip, cons, name, nvars, vars, SCIP_SETPPCTYPE_PACKING, 9441 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode); 9442 } 9443 9444 /** creates and captures a set packing constraint with all constraint flags set 9445 * to their default values 9446 * 9447 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons() 9448 */ 9449 SCIP_RETCODE SCIPcreateConsBasicSetpack( 9450 SCIP* scip, /**< SCIP data structure */ 9451 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 9452 const char* name, /**< name of constraint */ 9453 int nvars, /**< number of variables in the constraint */ 9454 SCIP_VAR** vars /**< array with variables of constraint entries */ 9455 ) 9456 { 9457 SCIP_CALL( SCIPcreateConsSetpack(scip, cons, name, nvars, vars, 9458 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); 9459 9460 return SCIP_OKAY; 9461 } 9462 9463 /** creates and captures a set covering constraint 9464 * 9465 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons() 9466 */ 9467 SCIP_RETCODE SCIPcreateConsSetcover( 9468 SCIP* scip, /**< SCIP data structure */ 9469 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 9470 const char* name, /**< name of constraint */ 9471 int nvars, /**< number of variables in the constraint */ 9472 SCIP_VAR** vars, /**< array with variables of constraint entries */ 9473 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? 9474 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ 9475 SCIP_Bool separate, /**< should the constraint be separated during LP processing? 9476 * Usually set to TRUE. */ 9477 SCIP_Bool enforce, /**< should the constraint be enforced during node processing? 9478 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 9479 SCIP_Bool check, /**< should the constraint be checked for feasibility? 9480 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 9481 SCIP_Bool propagate, /**< should the constraint be propagated during node processing? 9482 * Usually set to TRUE. */ 9483 SCIP_Bool local, /**< is constraint only valid locally? 9484 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ 9485 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? 9486 * Usually set to FALSE. In column generation applications, set to TRUE if pricing 9487 * adds coefficients to this constraint. */ 9488 SCIP_Bool dynamic, /**< is constraint subject to aging? 9489 * Usually set to FALSE. Set to TRUE for own cuts which 9490 * are separated as constraints. */ 9491 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup? 9492 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */ 9493 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even 9494 * if it may be moved to a more global node? 9495 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */ 9496 ) 9497 { 9498 return createConsSetppc(scip, cons, name, nvars, vars, SCIP_SETPPCTYPE_COVERING, 9499 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode); 9500 } 9501 9502 /** creates and captures a set covering constraint with all constraint flags set 9503 * to their default values 9504 * 9505 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons() 9506 */ 9507 SCIP_RETCODE SCIPcreateConsBasicSetcover( 9508 SCIP* scip, /**< SCIP data structure */ 9509 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 9510 const char* name, /**< name of constraint */ 9511 int nvars, /**< number of variables in the constraint */ 9512 SCIP_VAR** vars /**< array with variables of constraint entries */ 9513 ) 9514 { 9515 SCIP_CALL( SCIPcreateConsSetcover(scip, cons, name, nvars, vars, 9516 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); 9517 9518 return SCIP_OKAY; 9519 } 9520 9521 /** adds coefficient in set partitioning / packing / covering constraint */ 9522 SCIP_RETCODE SCIPaddCoefSetppc( 9523 SCIP* scip, /**< SCIP data structure */ 9524 SCIP_CONS* cons, /**< constraint data */ 9525 SCIP_VAR* var /**< variable to add to the constraint */ 9526 ) 9527 { 9528 assert(var != NULL); 9529 9530 /*debugMsg(scip, "adding variable <%s> to setppc constraint <%s>\n", 9531 SCIPvarGetName(var), SCIPconsGetName(cons));*/ 9532 9533 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 9534 { 9535 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n"); 9536 return SCIP_INVALIDDATA; 9537 } 9538 9539 SCIP_CALL( addCoef(scip, cons, var) ); 9540 9541 return SCIP_OKAY; 9542 } 9543 9544 /** gets number of variables in set partitioning / packing / covering constraint */ 9545 int SCIPgetNVarsSetppc( 9546 SCIP* scip, /**< SCIP data structure */ 9547 SCIP_CONS* cons /**< constraint data */ 9548 ) 9549 { 9550 SCIP_CONSDATA* consdata; 9551 9552 assert(scip != NULL); 9553 9554 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 9555 { 9556 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n"); 9557 SCIPABORT(); 9558 return -1; /*lint !e527*/ 9559 } 9560 9561 consdata = SCIPconsGetData(cons); 9562 assert(consdata != NULL); 9563 9564 return consdata->nvars; 9565 } 9566 9567 /** gets array of variables in set partitioning / packing / covering constraint */ 9568 SCIP_VAR** SCIPgetVarsSetppc( 9569 SCIP* scip, /**< SCIP data structure */ 9570 SCIP_CONS* cons /**< constraint data */ 9571 ) 9572 { 9573 SCIP_CONSDATA* consdata; 9574 9575 assert(scip != NULL); 9576 9577 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 9578 { 9579 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n"); 9580 SCIPABORT(); 9581 return NULL; /*lint !e527*/ 9582 } 9583 9584 consdata = SCIPconsGetData(cons); 9585 assert(consdata != NULL); 9586 9587 return consdata->vars; 9588 } 9589 9590 /** gets type of set partitioning / packing / covering constraint */ 9591 SCIP_SETPPCTYPE SCIPgetTypeSetppc( 9592 SCIP* scip, /**< SCIP data structure */ 9593 SCIP_CONS* cons /**< constraint data */ 9594 ) 9595 { 9596 SCIP_CONSDATA* consdata; 9597 9598 assert(scip != NULL); 9599 9600 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 9601 { 9602 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n"); 9603 SCIPABORT(); 9604 } 9605 9606 consdata = SCIPconsGetData(cons); 9607 assert(consdata != NULL); 9608 9609 return (SCIP_SETPPCTYPE)(consdata->setppctype); 9610 } 9611 9612 /** gets the dual solution of the set partitioning / packing / covering constraint in the current LP */ 9613 SCIP_Real SCIPgetDualsolSetppc( 9614 SCIP* scip, /**< SCIP data structure */ 9615 SCIP_CONS* cons /**< constraint data */ 9616 ) 9617 { 9618 SCIP_CONSDATA* consdata; 9619 9620 assert(scip != NULL); 9621 9622 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 9623 { 9624 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n"); 9625 SCIPABORT(); 9626 return SCIP_INVALID; /*lint !e527*/ 9627 } 9628 9629 consdata = SCIPconsGetData(cons); 9630 assert(consdata != NULL); 9631 9632 if( consdata->row != NULL ) 9633 return SCIProwGetDualsol(consdata->row); 9634 else 9635 return 0.0; 9636 } 9637 9638 /** gets the dual Farkas value of the set partitioning / packing / covering constraint in the current infeasible LP */ 9639 SCIP_Real SCIPgetDualfarkasSetppc( 9640 SCIP* scip, /**< SCIP data structure */ 9641 SCIP_CONS* cons /**< constraint data */ 9642 ) 9643 { 9644 SCIP_CONSDATA* consdata; 9645 9646 assert(scip != NULL); 9647 9648 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 9649 { 9650 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n"); 9651 SCIPABORT(); 9652 return SCIP_INVALID; /*lint !e527*/ 9653 } 9654 9655 consdata = SCIPconsGetData(cons); 9656 assert(consdata != NULL); 9657 9658 if( consdata->row != NULL ) 9659 return SCIProwGetDualfarkas(consdata->row); 9660 else 9661 return 0.0; 9662 } 9663 9664 /** returns the linear relaxation of the given set partitioning / packing / covering constraint; may return NULL if no 9665 * LP row was yet created; the user must not modify the row! 9666 */ 9667 SCIP_ROW* SCIPgetRowSetppc( 9668 SCIP* scip, /**< SCIP data structure */ 9669 SCIP_CONS* cons /**< constraint data */ 9670 ) 9671 { 9672 SCIP_CONSDATA* consdata; 9673 9674 assert(scip != NULL); 9675 9676 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 9677 { 9678 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n"); 9679 SCIPABORT(); 9680 return NULL; /*lint !e527*/ 9681 } 9682 9683 consdata = SCIPconsGetData(cons); 9684 assert(consdata != NULL); 9685 9686 return consdata->row; 9687 } 9688 9689 /** returns current number of variables fixed to one in the constraint */ 9690 int SCIPgetNFixedonesSetppc( 9691 SCIP* scip, /**< SCIP data structure */ 9692 SCIP_CONS* cons /**< constraint data */ 9693 ) 9694 { 9695 SCIP_CONSDATA* consdata; 9696 9697 assert(scip != NULL); 9698 9699 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 9700 { 9701 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n"); 9702 SCIPABORT(); 9703 return -1; /*lint !e527*/ 9704 } 9705 9706 consdata = SCIPconsGetData(cons); 9707 assert(consdata != NULL); 9708 9709 return consdata->nfixedones; 9710 } 9711 9712 9713 /** returns current number of variables fixed to zero in the constraint */ 9714 int SCIPgetNFixedzerosSetppc( 9715 SCIP* scip, /**< SCIP data structure */ 9716 SCIP_CONS* cons /**< constraint data */ 9717 ) 9718 { 9719 SCIP_CONSDATA* consdata; 9720 9721 assert(scip != NULL); 9722 9723 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 9724 { 9725 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n"); 9726 SCIPABORT(); 9727 return -1; /*lint !e527*/ 9728 } 9729 9730 consdata = SCIPconsGetData(cons); 9731 assert(consdata != NULL); 9732 9733 return consdata->nfixedzeros; 9734 } 9735 9736 /** cleans up (multi-)aggregations and fixings from setppc constraints */ 9737 SCIP_RETCODE SCIPcleanupConssSetppc( 9738 SCIP* scip, /**< SCIP data structure */ 9739 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */ 9740 SCIP_Bool* infeasible, /**< pointer to return whether problem was detected to be infeasible */ 9741 int* naddconss, /**< pointer to count number of added (linear) constraints */ 9742 int* ndelconss, /**< pointer to count number of deleted (setppc) constraints */ 9743 int* nchgcoefs, /**< pointer to count number of changed coefficients */ 9744 int* nfixedvars /**< pointer to count number of fixed variables */ 9745 ) 9746 { 9747 SCIP_CONSHDLR* conshdlr; 9748 SCIP_CONS** conss; 9749 int nconss; 9750 int i; 9751 9752 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME); 9753 if( conshdlr == NULL ) 9754 return SCIP_OKAY; 9755 9756 assert(naddconss != NULL); 9757 assert(ndelconss != NULL); 9758 assert(nfixedvars != NULL); 9759 assert(infeasible != NULL); 9760 *infeasible = FALSE; 9761 9762 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr); 9763 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr); 9764 9765 /* loop backwards since then deleted constraints do not interfere with the loop */ 9766 for( i = nconss - 1; i > 0; --i ) 9767 { 9768 SCIP_CONS* cons = conss[i]; 9769 9770 SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, infeasible) ); 9771 9772 if( *infeasible ) 9773 break; 9774 9775 if( SCIPconsIsDeleted(cons) ) 9776 continue; 9777 9778 /* merging unmerged constraints */ 9779 SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, infeasible) ); 9780 9781 if( *infeasible ) 9782 break; 9783 } 9784 9785 return SCIP_OKAY; 9786 } 9787