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