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 var.c 26 * @ingroup OTHER_CFILES 27 * @brief methods for problem variables 28 * @author Tobias Achterberg 29 * @author Timo Berthold 30 * @author Gerald Gamrath 31 * @author Stefan Heinz 32 * @author Marc Pfetsch 33 * @author Michael Winkler 34 * @author Kati Wolter 35 * @author Stefan Vigerske 36 * 37 * @todo Possibly implement the access of bounds of multi-aggregated variables by accessing the 38 * corresponding linear constraint if it exists. This seems to require some work, since the linear 39 * constraint has to be stored. Moreover, it has even to be created in case the original constraint 40 * was deleted after multi-aggregation, but the bounds of the multi-aggregated variable should be 41 * changed. This has to be done with care in order to not loose the performance gains of 42 * multi-aggregation. 43 */ 44 45 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 46 47 #include "scip/cons.h" 48 #include "scip/event.h" 49 #include "scip/history.h" 50 #include "scip/implics.h" 51 #include "scip/lp.h" 52 #include "scip/primal.h" 53 #include "scip/prob.h" 54 #include "scip/pub_cons.h" 55 #include "scip/pub_history.h" 56 #include "scip/pub_implics.h" 57 #include "scip/pub_lp.h" 58 #include "scip/pub_message.h" 59 #include "scip/pub_misc.h" 60 #include "scip/pub_misc_sort.h" 61 #include "scip/pub_prop.h" 62 #include "scip/pub_var.h" 63 #include "scip/relax.h" 64 #include "scip/set.h" 65 #include "scip/sol.h" 66 #include "scip/stat.h" 67 #include "scip/struct_event.h" 68 #include "scip/struct_lp.h" 69 #include "scip/struct_prob.h" 70 #include "scip/struct_set.h" 71 #include "scip/struct_stat.h" 72 #include "scip/struct_var.h" 73 #include "scip/tree.h" 74 #include "scip/var.h" 75 #include <string.h> 76 77 #define MAXIMPLSCLOSURE 100 /**< maximal number of descendants of implied variable for building closure 78 * in implication graph */ 79 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds added due to implications */ 80 81 82 /* 83 * Debugging variable release and capture 84 * 85 * Define DEBUGUSES_VARNAME to the name of the variable for which to print 86 * a backtrace when it is captured and released. 87 * Optionally define DEBUGUSES_PROBNAME to the name of a SCIP problem to consider. 88 * Have DEBUGUSES_NOADDR2LINE defined if you do not have addr2line installed on your system. 89 */ 90 /* #define DEBUGUSES_VARNAME "t_t_b7" */ 91 /* #define DEBUGUSES_PROBNAME "t_st_e35_rens" */ 92 /* #define DEBUGUSES_NOADDR2LINE */ 93 94 #ifdef DEBUGUSES_VARNAME 95 #include <execinfo.h> 96 #include <stdio.h> 97 #include <stdlib.h> 98 #include "scip/struct_scip.h" 99 100 /** obtains a backtrace and prints it to stdout. */ 101 static 102 void print_backtrace(void) 103 { 104 void* array[10]; 105 char** strings; 106 int size; 107 int i; 108 109 size = backtrace(array, 10); 110 strings = backtrace_symbols(array, size); 111 if( strings == NULL ) 112 return; 113 114 /* skip first entry, which is the print_backtrace function */ 115 for( i = 1; i < size; ++i ) 116 { 117 /* if string is something like 118 * /path/to/scip/bin/../lib/shared/libscip-7.0.1.3.linux.x86_64.gnu.dbg.so(+0x2675dd3) 119 * (that is, no function name because it is a inlined function), then call 120 * addr2line -e <libname> <addr> to get func and code line 121 * dladdr() may be an alternative 122 */ 123 char* openpar; 124 char* closepar = NULL; 125 #ifndef DEBUGUSES_NOADDR2LINE 126 openpar = strchr(strings[i], '('); 127 if( openpar != NULL && openpar[1] == '+' ) 128 closepar = strchr(openpar+2, ')'); 129 #endif 130 if( closepar != NULL ) 131 { 132 char cmd[SCIP_MAXSTRLEN]; 133 (void) SCIPsnprintf(cmd, SCIP_MAXSTRLEN, "addr2line -f -p -e \"%.*s\" %.*s", openpar - strings[i], strings[i], closepar-openpar-1, openpar+1); 134 printf(" "); 135 fflush(stdout); 136 system(cmd); 137 } 138 else 139 printf(" %s\n", strings[i]); 140 } 141 142 free(strings); 143 } 144 #endif 145 146 /* 147 * hole, holelist, and domain methods 148 */ 149 150 /** creates a new holelist element */ 151 static 152 SCIP_RETCODE holelistCreate( 153 SCIP_HOLELIST** holelist, /**< pointer to holelist to create */ 154 BMS_BLKMEM* blkmem, /**< block memory for target holelist */ 155 SCIP_SET* set, /**< global SCIP settings */ 156 SCIP_Real left, /**< left bound of open interval in new hole */ 157 SCIP_Real right /**< right bound of open interval in new hole */ 158 ) 159 { 160 assert(holelist != NULL); 161 assert(blkmem != NULL); 162 assert(SCIPsetIsLT(set, left, right)); 163 164 SCIPsetDebugMsg(set, "create hole list element (%.15g,%.15g) in blkmem %p\n", left, right, (void*)blkmem); 165 166 SCIP_ALLOC( BMSallocBlockMemory(blkmem, holelist) ); 167 (*holelist)->hole.left = left; 168 (*holelist)->hole.right = right; 169 (*holelist)->next = NULL; 170 171 return SCIP_OKAY; 172 } 173 174 /** frees all elements in the holelist */ 175 static 176 void holelistFree( 177 SCIP_HOLELIST** holelist, /**< pointer to holelist to free */ 178 BMS_BLKMEM* blkmem /**< block memory for target holelist */ 179 ) 180 { 181 assert(holelist != NULL); 182 assert(blkmem != NULL); 183 184 while( *holelist != NULL ) 185 { 186 SCIP_HOLELIST* next; 187 188 SCIPdebugMessage("free hole list element (%.15g,%.15g) in blkmem %p\n", 189 (*holelist)->hole.left, (*holelist)->hole.right, (void*)blkmem); 190 191 next = (*holelist)->next; 192 BMSfreeBlockMemory(blkmem, holelist); 193 assert(*holelist == NULL); 194 195 *holelist = next; 196 } 197 assert(*holelist == NULL); 198 } 199 200 /** duplicates a list of holes */ 201 static 202 SCIP_RETCODE holelistDuplicate( 203 SCIP_HOLELIST** target, /**< pointer to target holelist */ 204 BMS_BLKMEM* blkmem, /**< block memory for target holelist */ 205 SCIP_SET* set, /**< global SCIP settings */ 206 SCIP_HOLELIST* source /**< holelist to duplicate */ 207 ) 208 { 209 assert(target != NULL); 210 211 while( source != NULL ) 212 { 213 assert(source->next == NULL || SCIPsetIsGE(set, source->next->hole.left, source->hole.right)); 214 SCIP_CALL( holelistCreate(target, blkmem, set, source->hole.left, source->hole.right) ); 215 source = source->next; 216 target = &(*target)->next; 217 } 218 219 return SCIP_OKAY; 220 } 221 222 /** adds a hole to the domain */ 223 static 224 SCIP_RETCODE domAddHole( 225 SCIP_DOM* dom, /**< domain to add hole to */ 226 BMS_BLKMEM* blkmem, /**< block memory */ 227 SCIP_SET* set, /**< global SCIP settings */ 228 SCIP_Real left, /**< left bound of open interval in new hole */ 229 SCIP_Real right, /**< right bound of open interval in new hole */ 230 SCIP_Bool* added /**< pointer to store whether the hole was added (variable didn't had that hole before), or NULL */ 231 ) 232 { 233 SCIP_HOLELIST** insertpos; 234 SCIP_HOLELIST* next; 235 236 assert(dom != NULL); 237 assert(added != NULL); 238 239 /* search for the position of the new hole */ 240 insertpos = &dom->holelist; 241 while( *insertpos != NULL && (*insertpos)->hole.left < left ) 242 insertpos = &(*insertpos)->next; 243 244 /* check if new hole already exists in the hole list or is a sub hole of an existing one */ 245 if( *insertpos != NULL && (*insertpos)->hole.left == left && (*insertpos)->hole.right >= right ) /*lint !e777 */ 246 { 247 SCIPsetDebugMsg(set, "new hole (%.15g,%.15g) is redundant through known hole (%.15g,%.15g)\n", 248 left, right, (*insertpos)->hole.left, (*insertpos)->hole.right); 249 *added = FALSE; 250 return SCIP_OKAY; 251 } 252 253 /* add hole */ 254 *added = TRUE; 255 256 next = *insertpos; 257 SCIP_CALL( holelistCreate(insertpos, blkmem, set, left, right) ); 258 (*insertpos)->next = next; 259 260 return SCIP_OKAY; 261 } 262 263 /** merges overlapping holes into single holes, computes and moves lower and upper bound, respectively */ 264 /**@todo the domMerge() method is currently called if a lower or an upper bound locally or globally changed; this could 265 * be more efficient if performed with the knowledge if it was a lower or an upper bound which triggered this 266 * merge */ 267 static 268 void domMerge( 269 SCIP_DOM* dom, /**< domain to merge */ 270 BMS_BLKMEM* blkmem, /**< block memory */ 271 SCIP_SET* set, /**< global SCIP settings */ 272 SCIP_Real* newlb, /**< pointer to store new lower bound */ 273 SCIP_Real* newub /**< pointer to store new upper bound */ 274 ) 275 { 276 SCIP_HOLELIST** holelistptr; 277 SCIP_HOLELIST** lastnextptr; 278 SCIP_Real* lastrightptr; 279 280 assert(dom != NULL); 281 assert(SCIPsetIsLE(set, dom->lb, dom->ub)); 282 283 #ifndef NDEBUG 284 { 285 /* check if the holelist is sorted w.r.t. to the left interval bounds */ 286 SCIP_Real lastleft; 287 288 holelistptr = &dom->holelist; 289 290 lastleft = -SCIPsetInfinity(set); 291 292 while( *holelistptr != NULL ) 293 { 294 if( (*holelistptr)->next != NULL ) 295 { 296 assert( SCIPsetIsLE(set, lastleft, (*holelistptr)->hole.left) ); 297 lastleft = (*holelistptr)->hole.left; 298 } 299 300 holelistptr = &(*holelistptr)->next; 301 } 302 } 303 #endif 304 305 SCIPsetDebugMsg(set, "merge hole list\n"); 306 307 holelistptr = &dom->holelist; 308 lastrightptr = &dom->lb; /* lower bound is the right bound of the hole (-infinity,lb) */ 309 lastnextptr = holelistptr; 310 311 while( *holelistptr != NULL ) 312 { 313 SCIPsetDebugMsg(set, "check hole (%.15g,%.15g) last right interval was <%.15g>\n", (*holelistptr)->hole.left, (*holelistptr)->hole.right, *lastrightptr); 314 315 /* check that the hole is not empty */ 316 assert(SCIPsetIsLT(set, (*holelistptr)->hole.left, (*holelistptr)->hole.right)); 317 318 if( SCIPsetIsGE(set, (*holelistptr)->hole.left, dom->ub) ) 319 { 320 /* the remaining holes start behind the upper bound: remove them */ 321 SCIPsetDebugMsg(set, "remove remaining hole since upper bound <%.15g> is less then the left hand side of the current hole\n", dom->ub); 322 holelistFree(holelistptr, blkmem); 323 assert(*holelistptr == NULL); 324 325 /* unlink this hole from the previous hole */ 326 *lastnextptr = NULL; 327 } 328 else if( SCIPsetIsGT(set, (*holelistptr)->hole.right, dom->ub) ) 329 { 330 /* the hole overlaps the upper bound: decrease upper bound, remove this hole and all remaining holes */ 331 SCIPsetDebugMsg(set, "upper bound <%.15g> lays in current hole; store new upper bound and remove this and all remaining holes\n", dom->ub); 332 333 assert(SCIPsetIsLT(set, (*holelistptr)->hole.left, dom->ub)); 334 335 /* adjust upper bound */ 336 dom->ub = (*holelistptr)->hole.left; 337 338 if(newub != NULL ) 339 *newub = (*holelistptr)->hole.left; 340 341 /* remove remaining hole list */ 342 holelistFree(holelistptr, blkmem); 343 assert(*holelistptr == NULL); 344 345 /* unlink this hole from the previous hole */ 346 *lastnextptr = NULL; 347 } 348 else if( SCIPsetIsGT(set, *lastrightptr, (*holelistptr)->hole.left) ) 349 { 350 /* the right bound of the last hole is greater than the left bound of this hole: increase the right bound of 351 * the last hole, delete this hole */ 352 SCIP_HOLELIST* nextholelist; 353 354 if( SCIPsetIsEQ(set, *lastrightptr, dom->lb ) ) 355 { 356 /* the reason for the overlap results from the lower bound hole (-infinity,lb); therefore, we can increase 357 * the lower bound */ 358 SCIPsetDebugMsg(set, "lower bound <%.15g> lays in current hole; store new lower bound and remove hole\n", dom->lb); 359 *lastrightptr = MAX(*lastrightptr, (*holelistptr)->hole.right); 360 361 /* adjust lower bound */ 362 dom->lb = *lastrightptr; 363 364 if(newlb != NULL ) 365 *newlb = *lastrightptr; 366 } 367 else 368 { 369 SCIPsetDebugMsg(set, "current hole overlaps with the previous one (...,%.15g); merge to (...,%.15g)\n", 370 *lastrightptr, MAX(*lastrightptr, (*holelistptr)->hole.right) ); 371 *lastrightptr = MAX(*lastrightptr, (*holelistptr)->hole.right); 372 } 373 nextholelist = (*holelistptr)->next; 374 (*holelistptr)->next = NULL; 375 holelistFree(holelistptr, blkmem); 376 377 /* connect the linked list after removing the hole */ 378 *lastnextptr = nextholelist; 379 380 /* get next hole */ 381 *holelistptr = nextholelist; 382 } 383 else 384 { 385 /* the holes do not overlap: update lastholelist and lastrightptr */ 386 lastrightptr = &(*holelistptr)->hole.right; 387 lastnextptr = &(*holelistptr)->next; 388 389 /* get next hole */ 390 holelistptr = &(*holelistptr)->next; 391 } 392 } 393 394 #ifndef NDEBUG 395 { 396 /* check that holes are merged */ 397 SCIP_Real lastright; 398 399 lastright = dom->lb; /* lower bound is the right bound of the hole (-infinity,lb) */ 400 holelistptr = &dom->holelist; 401 402 while( *holelistptr != NULL ) 403 { 404 /* check the the last right interval is smaller or equal to the current left interval (none overlapping) */ 405 assert( SCIPsetIsLE(set, lastright, (*holelistptr)->hole.left) ); 406 407 /* check the hole property (check that the hole is not empty) */ 408 assert( SCIPsetIsLT(set, (*holelistptr)->hole.left, (*holelistptr)->hole.right) ); 409 lastright = (*holelistptr)->hole.right; 410 411 /* get next hole */ 412 holelistptr = &(*holelistptr)->next; 413 } 414 415 /* check the the last right interval is smaller or equal to the upper bound (none overlapping) */ 416 assert( SCIPsetIsLE(set, lastright, dom->ub) ); 417 } 418 #endif 419 } 420 421 /* 422 * domain change methods 423 */ 424 425 /** ensures, that bound change info array for lower bound changes can store at least num entries */ 426 static 427 SCIP_RETCODE varEnsureLbchginfosSize( 428 SCIP_VAR* var, /**< problem variable */ 429 BMS_BLKMEM* blkmem, /**< block memory */ 430 SCIP_SET* set, /**< global SCIP settings */ 431 int num /**< minimum number of entries to store */ 432 ) 433 { 434 assert(var != NULL); 435 assert(var->nlbchginfos <= var->lbchginfossize); 436 assert(SCIPvarIsTransformed(var)); 437 438 if( num > var->lbchginfossize ) 439 { 440 int newsize; 441 442 newsize = SCIPsetCalcMemGrowSize(set, num); 443 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->lbchginfos, var->lbchginfossize, newsize) ); 444 var->lbchginfossize = newsize; 445 } 446 assert(num <= var->lbchginfossize); 447 448 return SCIP_OKAY; 449 } 450 451 /** ensures, that bound change info array for upper bound changes can store at least num entries */ 452 static 453 SCIP_RETCODE varEnsureUbchginfosSize( 454 SCIP_VAR* var, /**< problem variable */ 455 BMS_BLKMEM* blkmem, /**< block memory */ 456 SCIP_SET* set, /**< global SCIP settings */ 457 int num /**< minimum number of entries to store */ 458 ) 459 { 460 assert(var != NULL); 461 assert(var->nubchginfos <= var->ubchginfossize); 462 assert(SCIPvarIsTransformed(var)); 463 464 if( num > var->ubchginfossize ) 465 { 466 int newsize; 467 468 newsize = SCIPsetCalcMemGrowSize(set, num); 469 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->ubchginfos, var->ubchginfossize, newsize) ); 470 var->ubchginfossize = newsize; 471 } 472 assert(num <= var->ubchginfossize); 473 474 return SCIP_OKAY; 475 } 476 477 /** adds domain change info to the variable's lower bound change info array */ 478 static 479 SCIP_RETCODE varAddLbchginfo( 480 SCIP_VAR* var, /**< problem variable */ 481 BMS_BLKMEM* blkmem, /**< block memory */ 482 SCIP_SET* set, /**< global SCIP settings */ 483 SCIP_Real oldbound, /**< old value for bound */ 484 SCIP_Real newbound, /**< new value for bound */ 485 int depth, /**< depth in the tree, where the bound change takes place */ 486 int pos, /**< position of the bound change in its bound change array */ 487 SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself) */ 488 SCIP_CONS* infercons, /**< constraint that inferred this bound change, or NULL */ 489 SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */ 490 int inferinfo, /**< user information for inference to help resolving the conflict */ 491 SCIP_BOUNDTYPE inferboundtype, /**< type of bound for inference var: lower or upper bound */ 492 SCIP_BOUNDCHGTYPE boundchgtype /**< bound change type: branching decision or inferred bound change */ 493 ) 494 { 495 assert(var != NULL); 496 assert(SCIPsetIsLT(set, oldbound, newbound)); 497 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, oldbound)); 498 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 499 assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, oldbound, 0.0)); 500 assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, 1.0)); 501 assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL); 502 assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL)); 503 assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL); 504 505 SCIPsetDebugMsg(set, "adding lower bound change info to var <%s>[%g,%g]: depth=%d, pos=%d, infer%s=<%s>, inferinfo=%d, %g -> %g\n", 506 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, depth, pos, infercons != NULL ? "cons" : "prop", 507 infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo, 508 oldbound, newbound); 509 510 SCIP_CALL( varEnsureLbchginfosSize(var, blkmem, set, var->nlbchginfos+1) ); 511 var->lbchginfos[var->nlbchginfos].oldbound = oldbound; 512 var->lbchginfos[var->nlbchginfos].newbound = newbound; 513 var->lbchginfos[var->nlbchginfos].var = var; 514 var->lbchginfos[var->nlbchginfos].bdchgidx.depth = depth; 515 var->lbchginfos[var->nlbchginfos].bdchgidx.pos = pos; 516 var->lbchginfos[var->nlbchginfos].pos = var->nlbchginfos; /*lint !e732*/ 517 var->lbchginfos[var->nlbchginfos].boundchgtype = boundchgtype; /*lint !e641*/ 518 var->lbchginfos[var->nlbchginfos].boundtype = SCIP_BOUNDTYPE_LOWER; /*lint !e641*/ 519 var->lbchginfos[var->nlbchginfos].redundant = FALSE; 520 var->lbchginfos[var->nlbchginfos].inferboundtype = inferboundtype; /*lint !e641*/ 521 var->lbchginfos[var->nlbchginfos].inferencedata.var = infervar; 522 var->lbchginfos[var->nlbchginfos].inferencedata.info = inferinfo; 523 524 /**@note The "pos" data member of the bound change info has a size of 27 bits */ 525 assert(var->nlbchginfos < 1 << 27); 526 527 switch( boundchgtype ) 528 { 529 case SCIP_BOUNDCHGTYPE_BRANCHING: 530 break; 531 case SCIP_BOUNDCHGTYPE_CONSINFER: 532 assert(infercons != NULL); 533 var->lbchginfos[var->nlbchginfos].inferencedata.reason.cons = infercons; 534 break; 535 case SCIP_BOUNDCHGTYPE_PROPINFER: 536 var->lbchginfos[var->nlbchginfos].inferencedata.reason.prop = inferprop; 537 break; 538 default: 539 SCIPerrorMessage("invalid bound change type %d\n", boundchgtype); 540 return SCIP_INVALIDDATA; 541 } 542 543 var->nlbchginfos++; 544 545 assert(var->nlbchginfos < 2 546 || SCIPbdchgidxIsEarlier(&var->lbchginfos[var->nlbchginfos-2].bdchgidx, 547 &var->lbchginfos[var->nlbchginfos-1].bdchgidx)); 548 549 return SCIP_OKAY; 550 } 551 552 /** adds domain change info to the variable's upper bound change info array */ 553 static 554 SCIP_RETCODE varAddUbchginfo( 555 SCIP_VAR* var, /**< problem variable */ 556 BMS_BLKMEM* blkmem, /**< block memory */ 557 SCIP_SET* set, /**< global SCIP settings */ 558 SCIP_Real oldbound, /**< old value for bound */ 559 SCIP_Real newbound, /**< new value for bound */ 560 int depth, /**< depth in the tree, where the bound change takes place */ 561 int pos, /**< position of the bound change in its bound change array */ 562 SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself) */ 563 SCIP_CONS* infercons, /**< constraint that inferred this bound change, or NULL */ 564 SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */ 565 int inferinfo, /**< user information for inference to help resolving the conflict */ 566 SCIP_BOUNDTYPE inferboundtype, /**< type of bound for inference var: lower or upper bound */ 567 SCIP_BOUNDCHGTYPE boundchgtype /**< bound change type: branching decision or inferred bound change */ 568 ) 569 { 570 assert(var != NULL); 571 assert(SCIPsetIsGT(set, oldbound, newbound)); 572 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, oldbound)); 573 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 574 assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, oldbound, 1.0)); 575 assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, 0.0)); 576 assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL); 577 assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL)); 578 assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL); 579 580 SCIPsetDebugMsg(set, "adding upper bound change info to var <%s>[%g,%g]: depth=%d, pos=%d, infer%s=<%s>, inferinfo=%d, %g -> %g\n", 581 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, depth, pos, infercons != NULL ? "cons" : "prop", 582 infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo, 583 oldbound, newbound); 584 585 SCIP_CALL( varEnsureUbchginfosSize(var, blkmem, set, var->nubchginfos+1) ); 586 var->ubchginfos[var->nubchginfos].oldbound = oldbound; 587 var->ubchginfos[var->nubchginfos].newbound = newbound; 588 var->ubchginfos[var->nubchginfos].var = var; 589 var->ubchginfos[var->nubchginfos].bdchgidx.depth = depth; 590 var->ubchginfos[var->nubchginfos].bdchgidx.pos = pos; 591 var->ubchginfos[var->nubchginfos].pos = var->nubchginfos; /*lint !e732*/ 592 var->ubchginfos[var->nubchginfos].boundchgtype = boundchgtype; /*lint !e641*/ 593 var->ubchginfos[var->nubchginfos].boundtype = SCIP_BOUNDTYPE_UPPER; /*lint !e641*/ 594 var->ubchginfos[var->nubchginfos].redundant = FALSE; 595 var->ubchginfos[var->nubchginfos].inferboundtype = inferboundtype; /*lint !e641*/ 596 var->ubchginfos[var->nubchginfos].inferencedata.var = infervar; 597 var->ubchginfos[var->nubchginfos].inferencedata.info = inferinfo; 598 599 /**@note The "pos" data member of the bound change info has a size of 27 bits */ 600 assert(var->nubchginfos < 1 << 27); 601 602 switch( boundchgtype ) 603 { 604 case SCIP_BOUNDCHGTYPE_BRANCHING: 605 break; 606 case SCIP_BOUNDCHGTYPE_CONSINFER: 607 assert(infercons != NULL); 608 var->ubchginfos[var->nubchginfos].inferencedata.reason.cons = infercons; 609 break; 610 case SCIP_BOUNDCHGTYPE_PROPINFER: 611 var->ubchginfos[var->nubchginfos].inferencedata.reason.prop = inferprop; 612 break; 613 default: 614 SCIPerrorMessage("invalid bound change type %d\n", boundchgtype); 615 return SCIP_INVALIDDATA; 616 } 617 618 var->nubchginfos++; 619 620 assert(var->nubchginfos < 2 621 || SCIPbdchgidxIsEarlier(&var->ubchginfos[var->nubchginfos-2].bdchgidx, 622 &var->ubchginfos[var->nubchginfos-1].bdchgidx)); 623 624 return SCIP_OKAY; 625 } 626 627 /** applies single bound change */ 628 SCIP_RETCODE SCIPboundchgApply( 629 SCIP_BOUNDCHG* boundchg, /**< bound change to apply */ 630 BMS_BLKMEM* blkmem, /**< block memory */ 631 SCIP_SET* set, /**< global SCIP settings */ 632 SCIP_STAT* stat, /**< problem statistics */ 633 SCIP_LP* lp, /**< current LP data */ 634 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 635 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 636 int depth, /**< depth in the tree, where the bound change takes place */ 637 int pos, /**< position of the bound change in its bound change array */ 638 SCIP_Bool* cutoff /**< pointer to store whether an infeasible bound change was detected */ 639 ) 640 { 641 SCIP_VAR* var; 642 643 assert(boundchg != NULL); 644 assert(stat != NULL); 645 assert(depth > 0); 646 assert(pos >= 0); 647 assert(cutoff != NULL); 648 649 *cutoff = FALSE; 650 651 /* ignore redundant bound changes */ 652 if( boundchg->redundant ) 653 return SCIP_OKAY; 654 655 var = boundchg->var; 656 assert(var != NULL); 657 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 658 assert(!SCIPvarIsIntegral(var) || SCIPsetIsFeasIntegral(set, boundchg->newbound)); 659 660 /* apply bound change */ 661 switch( boundchg->boundtype ) 662 { 663 case SCIP_BOUNDTYPE_LOWER: 664 /* check, if the bound change is still active (could be replaced by inference due to repropagation of higher node) */ 665 if( SCIPsetIsGT(set, boundchg->newbound, var->locdom.lb) ) 666 { 667 if( SCIPsetIsLE(set, boundchg->newbound, var->locdom.ub) ) 668 { 669 /* add the bound change info to the variable's bound change info array */ 670 switch( boundchg->boundchgtype ) 671 { 672 case SCIP_BOUNDCHGTYPE_BRANCHING: 673 SCIPsetDebugMsg(set, " -> branching: new lower bound of <%s>[%g,%g]: %g\n", 674 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound); 675 SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos, 676 NULL, NULL, NULL, 0, SCIP_BOUNDTYPE_LOWER, SCIP_BOUNDCHGTYPE_BRANCHING) ); 677 stat->lastbranchvar = var; 678 stat->lastbranchdir = SCIP_BRANCHDIR_UPWARDS; 679 stat->lastbranchvalue = boundchg->newbound; 680 break; 681 682 case SCIP_BOUNDCHGTYPE_CONSINFER: 683 assert(boundchg->data.inferencedata.reason.cons != NULL); 684 SCIPsetDebugMsg(set, " -> constraint <%s> inference: new lower bound of <%s>[%g,%g]: %g\n", 685 SCIPconsGetName(boundchg->data.inferencedata.reason.cons), 686 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound); 687 SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos, 688 boundchg->data.inferencedata.var, boundchg->data.inferencedata.reason.cons, NULL, 689 boundchg->data.inferencedata.info, 690 (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_CONSINFER) ); 691 break; 692 693 case SCIP_BOUNDCHGTYPE_PROPINFER: 694 SCIPsetDebugMsg(set, " -> propagator <%s> inference: new lower bound of <%s>[%g,%g]: %g\n", 695 boundchg->data.inferencedata.reason.prop != NULL 696 ? SCIPpropGetName(boundchg->data.inferencedata.reason.prop) : "-", 697 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound); 698 SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos, 699 boundchg->data.inferencedata.var, NULL, boundchg->data.inferencedata.reason.prop, 700 boundchg->data.inferencedata.info, 701 (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_PROPINFER) ); 702 break; 703 704 default: 705 SCIPerrorMessage("invalid bound change type %d\n", boundchg->boundchgtype); 706 return SCIP_INVALIDDATA; 707 } 708 709 /* change local bound of variable */ 710 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, boundchg->newbound) ); 711 } 712 else 713 { 714 SCIPsetDebugMsg(set, " -> cutoff: new lower bound of <%s>[%g,%g]: %g\n", 715 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound); 716 *cutoff = TRUE; 717 boundchg->redundant = TRUE; /* bound change has not entered the lbchginfos array of the variable! */ 718 } 719 } 720 else 721 { 722 /* mark bound change to be inactive */ 723 SCIPsetDebugMsg(set, " -> inactive %s: new lower bound of <%s>[%g,%g]: %g\n", 724 (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference", 725 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound); 726 boundchg->redundant = TRUE; 727 } 728 break; 729 730 case SCIP_BOUNDTYPE_UPPER: 731 /* check, if the bound change is still active (could be replaced by inference due to repropagation of higher node) */ 732 if( SCIPsetIsLT(set, boundchg->newbound, var->locdom.ub) ) 733 { 734 if( SCIPsetIsGE(set, boundchg->newbound, var->locdom.lb) ) 735 { 736 /* add the bound change info to the variable's bound change info array */ 737 switch( boundchg->boundchgtype ) 738 { 739 case SCIP_BOUNDCHGTYPE_BRANCHING: 740 SCIPsetDebugMsg(set, " -> branching: new upper bound of <%s>[%g,%g]: %g\n", 741 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound); 742 SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos, 743 NULL, NULL, NULL, 0, SCIP_BOUNDTYPE_UPPER, SCIP_BOUNDCHGTYPE_BRANCHING) ); 744 stat->lastbranchvar = var; 745 stat->lastbranchdir = SCIP_BRANCHDIR_DOWNWARDS; 746 stat->lastbranchvalue = boundchg->newbound; 747 break; 748 749 case SCIP_BOUNDCHGTYPE_CONSINFER: 750 assert(boundchg->data.inferencedata.reason.cons != NULL); 751 SCIPsetDebugMsg(set, " -> constraint <%s> inference: new upper bound of <%s>[%g,%g]: %g\n", 752 SCIPconsGetName(boundchg->data.inferencedata.reason.cons), 753 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound); 754 SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos, 755 boundchg->data.inferencedata.var, boundchg->data.inferencedata.reason.cons, NULL, 756 boundchg->data.inferencedata.info, 757 (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_CONSINFER) ); 758 break; 759 760 case SCIP_BOUNDCHGTYPE_PROPINFER: 761 SCIPsetDebugMsg(set, " -> propagator <%s> inference: new upper bound of <%s>[%g,%g]: %g\n", 762 boundchg->data.inferencedata.reason.prop != NULL 763 ? SCIPpropGetName(boundchg->data.inferencedata.reason.prop) : "-", 764 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound); 765 SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos, 766 boundchg->data.inferencedata.var, NULL, boundchg->data.inferencedata.reason.prop, 767 boundchg->data.inferencedata.info, 768 (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_PROPINFER) ); 769 break; 770 771 default: 772 SCIPerrorMessage("invalid bound change type %d\n", boundchg->boundchgtype); 773 return SCIP_INVALIDDATA; 774 } 775 776 /* change local bound of variable */ 777 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, boundchg->newbound) ); 778 } 779 else 780 { 781 SCIPsetDebugMsg(set, " -> cutoff: new upper bound of <%s>[%g,%g]: %g\n", 782 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound); 783 *cutoff = TRUE; 784 boundchg->redundant = TRUE; /* bound change has not entered the ubchginfos array of the variable! */ 785 } 786 } 787 else 788 { 789 /* mark bound change to be inactive */ 790 SCIPsetDebugMsg(set, " -> inactive %s: new upper bound of <%s>[%g,%g]: %g\n", 791 (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference", 792 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound); 793 boundchg->redundant = TRUE; 794 } 795 break; 796 797 default: 798 SCIPerrorMessage("unknown bound type\n"); 799 return SCIP_INVALIDDATA; 800 } 801 802 /* update the branching and inference history */ 803 if( !boundchg->applied && !boundchg->redundant ) 804 { 805 assert(var == boundchg->var); 806 807 if( (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ) 808 { 809 SCIP_CALL( SCIPvarIncNBranchings(var, blkmem, set, stat, 810 (SCIP_BOUNDTYPE)boundchg->boundtype == SCIP_BOUNDTYPE_LOWER 811 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS, boundchg->newbound, depth) ); 812 } 813 else if( stat->lastbranchvar != NULL ) 814 { 815 /**@todo if last branching variable is unknown, retrieve it from the nodes' boundchg arrays */ 816 SCIP_CALL( SCIPvarIncInferenceSum(stat->lastbranchvar, blkmem, set, stat, stat->lastbranchdir, stat->lastbranchvalue, 1.0) ); 817 } 818 boundchg->applied = TRUE; 819 } 820 821 return SCIP_OKAY; 822 } 823 824 /** undoes single bound change */ 825 SCIP_RETCODE SCIPboundchgUndo( 826 SCIP_BOUNDCHG* boundchg, /**< bound change to remove */ 827 BMS_BLKMEM* blkmem, /**< block memory */ 828 SCIP_SET* set, /**< global SCIP settings */ 829 SCIP_STAT* stat, /**< problem statistics */ 830 SCIP_LP* lp, /**< current LP data */ 831 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 832 SCIP_EVENTQUEUE* eventqueue /**< event queue */ 833 ) 834 { 835 SCIP_VAR* var; 836 837 assert(boundchg != NULL); 838 assert(stat != NULL); 839 840 /* ignore redundant bound changes */ 841 if( boundchg->redundant ) 842 return SCIP_OKAY; 843 844 var = boundchg->var; 845 assert(var != NULL); 846 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 847 848 /* undo bound change: apply the previous bound change of variable */ 849 switch( boundchg->boundtype ) 850 { 851 case SCIP_BOUNDTYPE_LOWER: 852 var->nlbchginfos--; 853 assert(var->nlbchginfos >= 0); 854 assert(var->lbchginfos != NULL); 855 assert( SCIPsetIsFeasEQ(set, var->lbchginfos[var->nlbchginfos].newbound, var->locdom.lb) ); /*lint !e777*/ 856 assert( SCIPsetIsFeasLE(set, boundchg->newbound, var->locdom.lb) ); /* current lb might be larger to intermediate global bound change */ 857 858 SCIPsetDebugMsg(set, "removed lower bound change info of var <%s>[%g,%g]: depth=%d, pos=%d, %g -> %g\n", 859 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, 860 var->lbchginfos[var->nlbchginfos].bdchgidx.depth, var->lbchginfos[var->nlbchginfos].bdchgidx.pos, 861 var->lbchginfos[var->nlbchginfos].oldbound, var->lbchginfos[var->nlbchginfos].newbound); 862 863 /* reinstall the previous local bound */ 864 SCIP_CALL( SCIPvarChgLbLocal(boundchg->var, blkmem, set, stat, lp, branchcand, eventqueue, 865 var->lbchginfos[var->nlbchginfos].oldbound) ); 866 867 /* in case all bound changes are removed the local bound should match the global bound */ 868 assert(var->nlbchginfos > 0 || SCIPsetIsFeasEQ(set, var->locdom.lb, var->glbdom.lb)); 869 870 break; 871 872 case SCIP_BOUNDTYPE_UPPER: 873 var->nubchginfos--; 874 assert(var->nubchginfos >= 0); 875 assert(var->ubchginfos != NULL); 876 assert( SCIPsetIsFeasEQ(set, var->ubchginfos[var->nubchginfos].newbound, var->locdom.ub) ); /*lint !e777*/ 877 assert( SCIPsetIsFeasGE(set, boundchg->newbound, var->locdom.ub) ); /* current ub might be smaller to intermediate global bound change */ 878 879 SCIPsetDebugMsg(set, "removed upper bound change info of var <%s>[%g,%g]: depth=%d, pos=%d, %g -> %g\n", 880 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, 881 var->ubchginfos[var->nubchginfos].bdchgidx.depth, var->ubchginfos[var->nubchginfos].bdchgidx.pos, 882 var->ubchginfos[var->nubchginfos].oldbound, var->ubchginfos[var->nubchginfos].newbound); 883 884 /* reinstall the previous local bound */ 885 SCIP_CALL( SCIPvarChgUbLocal(boundchg->var, blkmem, set, stat, lp, branchcand, eventqueue, 886 var->ubchginfos[var->nubchginfos].oldbound) ); 887 888 /* in case all bound changes are removed the local bound should match the global bound */ 889 assert(var->nubchginfos > 0 || SCIPsetIsFeasEQ(set, var->locdom.ub, var->glbdom.ub)); 890 891 break; 892 893 default: 894 SCIPerrorMessage("unknown bound type\n"); 895 return SCIP_INVALIDDATA; 896 } 897 898 /* update last branching variable */ 899 if( (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ) 900 { 901 stat->lastbranchvar = NULL; 902 stat->lastbranchvalue = SCIP_UNKNOWN; 903 } 904 905 return SCIP_OKAY; 906 } 907 908 /** applies single bound change to the global problem by changing the global bound of the corresponding variable */ 909 static 910 SCIP_RETCODE boundchgApplyGlobal( 911 SCIP_BOUNDCHG* boundchg, /**< bound change to apply */ 912 BMS_BLKMEM* blkmem, /**< block memory */ 913 SCIP_SET* set, /**< global SCIP settings */ 914 SCIP_STAT* stat, /**< problem statistics */ 915 SCIP_LP* lp, /**< current LP data */ 916 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 917 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 918 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 919 SCIP_Bool* cutoff /**< pointer to store whether an infeasible bound change was detected */ 920 ) 921 { 922 SCIP_VAR* var; 923 SCIP_Real newbound; 924 SCIP_BOUNDTYPE boundtype; 925 926 assert(boundchg != NULL); 927 assert(cutoff != NULL); 928 929 *cutoff = FALSE; 930 931 /* ignore redundant bound changes */ 932 if( boundchg->redundant ) 933 return SCIP_OKAY; 934 935 var = SCIPboundchgGetVar(boundchg); 936 newbound = SCIPboundchgGetNewbound(boundchg); 937 boundtype = SCIPboundchgGetBoundtype(boundchg); 938 939 /* check if the bound change is redundant which can happen due to a (better) global bound change which was performed 940 * after that bound change was applied 941 * 942 * @note a global bound change is not captured by the redundant member of the bound change data structure 943 */ 944 if( (boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasLE(set, newbound, SCIPvarGetLbGlobal(var))) 945 || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasGE(set, newbound, SCIPvarGetUbGlobal(var))) ) 946 { 947 return SCIP_OKAY; 948 } 949 950 SCIPsetDebugMsg(set, "applying global bound change: <%s>[%g,%g] %s %g\n", 951 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), 952 boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", newbound); 953 954 /* check for cutoff */ 955 if( (boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, newbound, SCIPvarGetUbGlobal(var))) 956 || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, newbound, SCIPvarGetLbGlobal(var))) ) 957 { 958 *cutoff = TRUE; 959 return SCIP_OKAY; 960 } 961 962 /* apply bound change */ 963 SCIP_CALL( SCIPvarChgBdGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound, boundtype) ); 964 965 return SCIP_OKAY; 966 } 967 968 /** captures branching and inference data of bound change */ 969 static 970 SCIP_RETCODE boundchgCaptureData( 971 SCIP_BOUNDCHG* boundchg /**< bound change to remove */ 972 ) 973 { 974 assert(boundchg != NULL); 975 976 /* capture variable associated with the bound change */ 977 assert(boundchg->var != NULL); 978 SCIPvarCapture(boundchg->var); 979 980 switch( boundchg->boundchgtype ) 981 { 982 case SCIP_BOUNDCHGTYPE_BRANCHING: 983 case SCIP_BOUNDCHGTYPE_PROPINFER: 984 break; 985 986 case SCIP_BOUNDCHGTYPE_CONSINFER: 987 assert(boundchg->data.inferencedata.var != NULL); 988 assert(boundchg->data.inferencedata.reason.cons != NULL); 989 SCIPconsCapture(boundchg->data.inferencedata.reason.cons); 990 break; 991 992 default: 993 SCIPerrorMessage("invalid bound change type\n"); 994 return SCIP_INVALIDDATA; 995 } 996 997 return SCIP_OKAY; 998 } 999 1000 /** releases branching and inference data of bound change */ 1001 static 1002 SCIP_RETCODE boundchgReleaseData( 1003 SCIP_BOUNDCHG* boundchg, /**< bound change to remove */ 1004 BMS_BLKMEM* blkmem, /**< block memory */ 1005 SCIP_SET* set, /**< global SCIP settings */ 1006 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 1007 SCIP_LP* lp /**< current LP data */ 1008 1009 ) 1010 { 1011 assert(boundchg != NULL); 1012 1013 switch( boundchg->boundchgtype ) 1014 { 1015 case SCIP_BOUNDCHGTYPE_BRANCHING: 1016 case SCIP_BOUNDCHGTYPE_PROPINFER: 1017 break; 1018 1019 case SCIP_BOUNDCHGTYPE_CONSINFER: 1020 assert(boundchg->data.inferencedata.var != NULL); 1021 assert(boundchg->data.inferencedata.reason.cons != NULL); 1022 SCIP_CALL( SCIPconsRelease(&boundchg->data.inferencedata.reason.cons, blkmem, set) ); 1023 break; 1024 1025 default: 1026 SCIPerrorMessage("invalid bound change type\n"); 1027 return SCIP_INVALIDDATA; 1028 } 1029 1030 /* release variable */ 1031 assert(boundchg->var != NULL); 1032 SCIP_CALL( SCIPvarRelease(&boundchg->var, blkmem, set, eventqueue, lp) ); 1033 1034 return SCIP_OKAY; 1035 } 1036 1037 /** creates empty domain change data with dynamic arrays */ 1038 static 1039 SCIP_RETCODE domchgCreate( 1040 SCIP_DOMCHG** domchg, /**< pointer to domain change data */ 1041 BMS_BLKMEM* blkmem /**< block memory */ 1042 ) 1043 { 1044 assert(domchg != NULL); 1045 assert(blkmem != NULL); 1046 1047 SCIP_ALLOC( BMSallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN)) ); 1048 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/ 1049 (*domchg)->domchgdyn.nboundchgs = 0; 1050 (*domchg)->domchgdyn.boundchgs = NULL; 1051 (*domchg)->domchgdyn.nholechgs = 0; 1052 (*domchg)->domchgdyn.holechgs = NULL; 1053 (*domchg)->domchgdyn.boundchgssize = 0; 1054 (*domchg)->domchgdyn.holechgssize = 0; 1055 1056 return SCIP_OKAY; 1057 } 1058 1059 /** frees domain change data */ 1060 SCIP_RETCODE SCIPdomchgFree( 1061 SCIP_DOMCHG** domchg, /**< pointer to domain change */ 1062 BMS_BLKMEM* blkmem, /**< block memory */ 1063 SCIP_SET* set, /**< global SCIP settings */ 1064 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 1065 SCIP_LP* lp /**< current LP data */ 1066 ) 1067 { 1068 assert(domchg != NULL); 1069 assert(blkmem != NULL); 1070 1071 if( *domchg != NULL ) 1072 { 1073 int i; 1074 1075 /* release variables, branching and inference data associated with the bound changes */ 1076 for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i ) 1077 { 1078 SCIP_CALL( boundchgReleaseData(&(*domchg)->domchgbound.boundchgs[i], blkmem, set, eventqueue, lp) ); 1079 } 1080 1081 /* free memory for bound and hole changes */ 1082 switch( (*domchg)->domchgdyn.domchgtype ) 1083 { 1084 case SCIP_DOMCHGTYPE_BOUND: 1085 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgbound.boundchgs, (*domchg)->domchgbound.nboundchgs); 1086 BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOUND)); 1087 break; 1088 case SCIP_DOMCHGTYPE_BOTH: 1089 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgboth.boundchgs, (*domchg)->domchgboth.nboundchgs); 1090 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgboth.holechgs, (*domchg)->domchgboth.nholechgs); 1091 BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH)); 1092 break; 1093 case SCIP_DOMCHGTYPE_DYNAMIC: 1094 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.boundchgs, (*domchg)->domchgdyn.boundchgssize); 1095 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.holechgs, (*domchg)->domchgdyn.holechgssize); 1096 BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN)); 1097 break; 1098 default: 1099 SCIPerrorMessage("invalid domain change type\n"); 1100 return SCIP_INVALIDDATA; 1101 } 1102 } 1103 1104 return SCIP_OKAY; 1105 } 1106 1107 /** converts a static domain change data into a dynamic one */ 1108 static 1109 SCIP_RETCODE domchgMakeDynamic( 1110 SCIP_DOMCHG** domchg, /**< pointer to domain change data */ 1111 BMS_BLKMEM* blkmem /**< block memory */ 1112 ) 1113 { 1114 assert(domchg != NULL); 1115 assert(blkmem != NULL); 1116 1117 SCIPdebugMessage("making domain change data %p pointing to %p dynamic\n", (void*)domchg, (void*)*domchg); 1118 1119 if( *domchg == NULL ) 1120 { 1121 SCIP_CALL( domchgCreate(domchg, blkmem) ); 1122 } 1123 else 1124 { 1125 switch( (*domchg)->domchgdyn.domchgtype ) 1126 { 1127 case SCIP_DOMCHGTYPE_BOUND: 1128 SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOUND), sizeof(SCIP_DOMCHGDYN)) ); 1129 (*domchg)->domchgdyn.nholechgs = 0; 1130 (*domchg)->domchgdyn.holechgs = NULL; 1131 (*domchg)->domchgdyn.boundchgssize = (int) (*domchg)->domchgdyn.nboundchgs; 1132 (*domchg)->domchgdyn.holechgssize = 0; 1133 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/ 1134 break; 1135 case SCIP_DOMCHGTYPE_BOTH: 1136 SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH), sizeof(SCIP_DOMCHGDYN)) ); 1137 (*domchg)->domchgdyn.boundchgssize = (int) (*domchg)->domchgdyn.nboundchgs; 1138 (*domchg)->domchgdyn.holechgssize = (*domchg)->domchgdyn.nholechgs; 1139 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/ 1140 break; 1141 case SCIP_DOMCHGTYPE_DYNAMIC: 1142 break; 1143 default: 1144 SCIPerrorMessage("invalid domain change type\n"); 1145 return SCIP_INVALIDDATA; 1146 } 1147 } 1148 #ifndef NDEBUG 1149 { 1150 int i; 1151 for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i ) 1152 assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS 1153 || EPSISINT((*domchg)->domchgbound.boundchgs[i].newbound, 1e-06)); 1154 } 1155 #endif 1156 1157 return SCIP_OKAY; 1158 } 1159 1160 /** converts a dynamic domain change data into a static one, using less memory than for a dynamic one */ 1161 SCIP_RETCODE SCIPdomchgMakeStatic( 1162 SCIP_DOMCHG** domchg, /**< pointer to domain change data */ 1163 BMS_BLKMEM* blkmem, /**< block memory */ 1164 SCIP_SET* set, /**< global SCIP settings */ 1165 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 1166 SCIP_LP* lp /**< current LP data */ 1167 ) 1168 { 1169 assert(domchg != NULL); 1170 assert(blkmem != NULL); 1171 1172 SCIPsetDebugMsg(set, "making domain change data %p pointing to %p static\n", (void*)domchg, (void*)*domchg); 1173 1174 if( *domchg != NULL ) 1175 { 1176 switch( (*domchg)->domchgdyn.domchgtype ) 1177 { 1178 case SCIP_DOMCHGTYPE_BOUND: 1179 if( (*domchg)->domchgbound.nboundchgs == 0 ) 1180 { 1181 SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) ); 1182 } 1183 break; 1184 case SCIP_DOMCHGTYPE_BOTH: 1185 if( (*domchg)->domchgboth.nholechgs == 0 ) 1186 { 1187 if( (*domchg)->domchgbound.nboundchgs == 0 ) 1188 { 1189 SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) ); 1190 } 1191 else 1192 { 1193 SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH), sizeof(SCIP_DOMCHGBOUND)) ); 1194 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOUND; /*lint !e641*/ 1195 } 1196 } 1197 break; 1198 case SCIP_DOMCHGTYPE_DYNAMIC: 1199 if( (*domchg)->domchgboth.nholechgs == 0 ) 1200 { 1201 if( (*domchg)->domchgbound.nboundchgs == 0 ) 1202 { 1203 SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) ); 1204 } 1205 else 1206 { 1207 /* shrink dynamic size arrays to their minimal sizes */ 1208 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.boundchgs, \ 1209 (*domchg)->domchgdyn.boundchgssize, (*domchg)->domchgdyn.nboundchgs) ); /*lint !e571*/ 1210 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.holechgs, (*domchg)->domchgdyn.holechgssize); 1211 1212 /* convert into static domain change */ 1213 SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN), sizeof(SCIP_DOMCHGBOUND)) ); 1214 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOUND; /*lint !e641*/ 1215 } 1216 } 1217 else 1218 { 1219 /* shrink dynamic size arrays to their minimal sizes */ 1220 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.boundchgs, \ 1221 (*domchg)->domchgdyn.boundchgssize, (*domchg)->domchgdyn.nboundchgs) ); /*lint !e571*/ 1222 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.holechgs, \ 1223 (*domchg)->domchgdyn.holechgssize, (*domchg)->domchgdyn.nholechgs) ); 1224 1225 /* convert into static domain change */ 1226 SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN), sizeof(SCIP_DOMCHGBOTH)) ); 1227 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOTH; /*lint !e641*/ 1228 } 1229 break; 1230 default: 1231 SCIPerrorMessage("invalid domain change type\n"); 1232 return SCIP_INVALIDDATA; 1233 } 1234 #ifndef NDEBUG 1235 if( *domchg != NULL ) 1236 { 1237 int i; 1238 for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i ) 1239 assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS 1240 || SCIPsetIsFeasIntegral(set, (*domchg)->domchgbound.boundchgs[i].newbound)); 1241 } 1242 #endif 1243 } 1244 1245 return SCIP_OKAY; 1246 } 1247 1248 /** ensures, that boundchgs array can store at least num entries */ 1249 static 1250 SCIP_RETCODE domchgEnsureBoundchgsSize( 1251 SCIP_DOMCHG* domchg, /**< domain change data structure */ 1252 BMS_BLKMEM* blkmem, /**< block memory */ 1253 SCIP_SET* set, /**< global SCIP settings */ 1254 int num /**< minimum number of entries to store */ 1255 ) 1256 { 1257 assert(domchg != NULL); 1258 assert(domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/ 1259 1260 if( num > domchg->domchgdyn.boundchgssize ) 1261 { 1262 int newsize; 1263 1264 newsize = SCIPsetCalcMemGrowSize(set, num); 1265 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &domchg->domchgdyn.boundchgs, domchg->domchgdyn.boundchgssize, newsize) ); 1266 domchg->domchgdyn.boundchgssize = newsize; 1267 } 1268 assert(num <= domchg->domchgdyn.boundchgssize); 1269 1270 return SCIP_OKAY; 1271 } 1272 1273 /** ensures, that holechgs array can store at least num additional entries */ 1274 static 1275 SCIP_RETCODE domchgEnsureHolechgsSize( 1276 SCIP_DOMCHG* domchg, /**< domain change data structure */ 1277 BMS_BLKMEM* blkmem, /**< block memory */ 1278 SCIP_SET* set, /**< global SCIP settings */ 1279 int num /**< minimum number of additional entries to store */ 1280 ) 1281 { 1282 assert(domchg != NULL); 1283 assert(domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/ 1284 1285 if( num > domchg->domchgdyn.holechgssize ) 1286 { 1287 int newsize; 1288 1289 newsize = SCIPsetCalcMemGrowSize(set, num); 1290 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &domchg->domchgdyn.holechgs, domchg->domchgdyn.holechgssize, newsize) ); 1291 domchg->domchgdyn.holechgssize = newsize; 1292 } 1293 assert(num <= domchg->domchgdyn.holechgssize); 1294 1295 return SCIP_OKAY; 1296 } 1297 1298 /** applies domain change */ 1299 SCIP_RETCODE SCIPdomchgApply( 1300 SCIP_DOMCHG* domchg, /**< domain change to apply */ 1301 BMS_BLKMEM* blkmem, /**< block memory */ 1302 SCIP_SET* set, /**< global SCIP settings */ 1303 SCIP_STAT* stat, /**< problem statistics */ 1304 SCIP_LP* lp, /**< current LP data */ 1305 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 1306 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 1307 int depth, /**< depth in the tree, where the domain change takes place */ 1308 SCIP_Bool* cutoff /**< pointer to store whether an infeasible domain change was detected */ 1309 ) 1310 { 1311 int i; 1312 1313 assert(cutoff != NULL); 1314 1315 *cutoff = FALSE; 1316 1317 SCIPsetDebugMsg(set, "applying domain changes at %p in depth %d\n", (void*)domchg, depth); 1318 1319 if( domchg == NULL ) 1320 return SCIP_OKAY; 1321 1322 /* apply bound changes */ 1323 for( i = 0; i < (int)domchg->domchgbound.nboundchgs; ++i ) 1324 { 1325 SCIP_CALL( SCIPboundchgApply(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp, 1326 branchcand, eventqueue, depth, i, cutoff) ); 1327 if( *cutoff ) 1328 break; 1329 } 1330 SCIPsetDebugMsg(set, " -> %u bound changes (cutoff %u)\n", domchg->domchgbound.nboundchgs, *cutoff); 1331 1332 /* mark all bound changes after a cutoff redundant */ 1333 for( ; i < (int)domchg->domchgbound.nboundchgs; ++i ) 1334 domchg->domchgbound.boundchgs[i].redundant = TRUE; 1335 1336 /* apply holelist changes */ 1337 if( domchg->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_BOUND ) /*lint !e641*/ 1338 { 1339 for( i = 0; i < domchg->domchgboth.nholechgs; ++i ) 1340 *(domchg->domchgboth.holechgs[i].ptr) = domchg->domchgboth.holechgs[i].newlist; 1341 SCIPsetDebugMsg(set, " -> %d hole changes\n", domchg->domchgboth.nholechgs); 1342 } 1343 1344 return SCIP_OKAY; 1345 } 1346 1347 /** undoes domain change */ 1348 SCIP_RETCODE SCIPdomchgUndo( 1349 SCIP_DOMCHG* domchg, /**< domain change to remove */ 1350 BMS_BLKMEM* blkmem, /**< block memory */ 1351 SCIP_SET* set, /**< global SCIP settings */ 1352 SCIP_STAT* stat, /**< problem statistics */ 1353 SCIP_LP* lp, /**< current LP data */ 1354 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 1355 SCIP_EVENTQUEUE* eventqueue /**< event queue */ 1356 ) 1357 { 1358 int i; 1359 1360 SCIPsetDebugMsg(set, "undoing domain changes at %p\n", (void*)domchg); 1361 if( domchg == NULL ) 1362 return SCIP_OKAY; 1363 1364 /* undo holelist changes */ 1365 if( domchg->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_BOUND ) /*lint !e641*/ 1366 { 1367 for( i = domchg->domchgboth.nholechgs-1; i >= 0; --i ) 1368 *(domchg->domchgboth.holechgs[i].ptr) = domchg->domchgboth.holechgs[i].oldlist; 1369 SCIPsetDebugMsg(set, " -> %d hole changes\n", domchg->domchgboth.nholechgs); 1370 } 1371 1372 /* undo bound changes */ 1373 for( i = domchg->domchgbound.nboundchgs-1; i >= 0; --i ) 1374 { 1375 SCIP_CALL( SCIPboundchgUndo(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp, branchcand, eventqueue) ); 1376 } 1377 SCIPsetDebugMsg(set, " -> %u bound changes\n", domchg->domchgbound.nboundchgs); 1378 1379 return SCIP_OKAY; 1380 } 1381 1382 /** applies domain change to the global problem */ 1383 SCIP_RETCODE SCIPdomchgApplyGlobal( 1384 SCIP_DOMCHG* domchg, /**< domain change to apply */ 1385 BMS_BLKMEM* blkmem, /**< block memory */ 1386 SCIP_SET* set, /**< global SCIP settings */ 1387 SCIP_STAT* stat, /**< problem statistics */ 1388 SCIP_LP* lp, /**< current LP data */ 1389 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 1390 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 1391 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 1392 SCIP_Bool* cutoff /**< pointer to store whether an infeasible domain change was detected */ 1393 ) 1394 { 1395 int i; 1396 1397 assert(cutoff != NULL); 1398 1399 *cutoff = FALSE; 1400 1401 if( domchg == NULL ) 1402 return SCIP_OKAY; 1403 1404 SCIPsetDebugMsg(set, "applying domain changes at %p to the global problem\n", (void*)domchg); 1405 1406 /* apply bound changes */ 1407 for( i = 0; i < (int)domchg->domchgbound.nboundchgs; ++i ) 1408 { 1409 SCIP_CALL( boundchgApplyGlobal(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp, 1410 branchcand, eventqueue, cliquetable, cutoff) ); 1411 if( *cutoff ) 1412 break; 1413 } 1414 SCIPsetDebugMsg(set, " -> %u global bound changes\n", domchg->domchgbound.nboundchgs); 1415 1416 /**@todo globally apply holelist changes - how can this be done without confusing pointer updates? */ 1417 1418 return SCIP_OKAY; 1419 } 1420 1421 /** adds bound change to domain changes */ 1422 SCIP_RETCODE SCIPdomchgAddBoundchg( 1423 SCIP_DOMCHG** domchg, /**< pointer to domain change data structure */ 1424 BMS_BLKMEM* blkmem, /**< block memory */ 1425 SCIP_SET* set, /**< global SCIP settings */ 1426 SCIP_VAR* var, /**< variable to change the bounds for */ 1427 SCIP_Real newbound, /**< new value for bound */ 1428 SCIP_BOUNDTYPE boundtype, /**< type of bound for var: lower or upper bound */ 1429 SCIP_BOUNDCHGTYPE boundchgtype, /**< type of bound change: branching decision or inference */ 1430 SCIP_Real lpsolval, /**< solval of variable in last LP on path to node, or SCIP_INVALID if unknown */ 1431 SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself), or NULL */ 1432 SCIP_CONS* infercons, /**< constraint that deduced the bound change, or NULL */ 1433 SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */ 1434 int inferinfo, /**< user information for inference to help resolving the conflict */ 1435 SCIP_BOUNDTYPE inferboundtype /**< type of bound for inference var: lower or upper bound */ 1436 ) 1437 { 1438 SCIP_BOUNDCHG* boundchg; 1439 1440 assert(domchg != NULL); 1441 assert(var != NULL); 1442 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 1443 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 1444 assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, boundtype == SCIP_BOUNDTYPE_LOWER ? 1.0 : 0.0)); 1445 assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL); 1446 assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL)); 1447 assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL); 1448 1449 SCIPsetDebugMsg(set, "adding %s bound change <%s: %g> of variable <%s> to domain change at %p pointing to %p\n", 1450 boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference", 1451 newbound, var->name, (void*)domchg, (void*)*domchg); 1452 1453 /* if domain change data doesn't exist, create it; 1454 * if domain change is static, convert it into dynamic change 1455 */ 1456 if( *domchg == NULL ) 1457 { 1458 SCIP_CALL( domchgCreate(domchg, blkmem) ); 1459 } 1460 else if( (*domchg)->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_DYNAMIC ) /*lint !e641*/ 1461 { 1462 SCIP_CALL( domchgMakeDynamic(domchg, blkmem) ); 1463 } 1464 assert(*domchg != NULL && (*domchg)->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/ 1465 1466 /* get memory for additional bound change */ 1467 SCIP_CALL( domchgEnsureBoundchgsSize(*domchg, blkmem, set, (*domchg)->domchgdyn.nboundchgs+1) ); 1468 1469 /* fill in the bound change data */ 1470 boundchg = &(*domchg)->domchgdyn.boundchgs[(*domchg)->domchgdyn.nboundchgs]; 1471 boundchg->var = var; 1472 switch( boundchgtype ) 1473 { 1474 case SCIP_BOUNDCHGTYPE_BRANCHING: 1475 boundchg->data.branchingdata.lpsolval = lpsolval; 1476 break; 1477 case SCIP_BOUNDCHGTYPE_CONSINFER: 1478 assert(infercons != NULL); 1479 boundchg->data.inferencedata.var = infervar; 1480 boundchg->data.inferencedata.reason.cons = infercons; 1481 boundchg->data.inferencedata.info = inferinfo; 1482 break; 1483 case SCIP_BOUNDCHGTYPE_PROPINFER: 1484 boundchg->data.inferencedata.var = infervar; 1485 boundchg->data.inferencedata.reason.prop = inferprop; 1486 boundchg->data.inferencedata.info = inferinfo; 1487 break; 1488 default: 1489 SCIPerrorMessage("invalid bound change type %d\n", boundchgtype); 1490 return SCIP_INVALIDDATA; 1491 } 1492 1493 boundchg->newbound = newbound; 1494 boundchg->boundchgtype = boundchgtype; /*lint !e641*/ 1495 boundchg->boundtype = boundtype; /*lint !e641*/ 1496 boundchg->inferboundtype = inferboundtype; /*lint !e641*/ 1497 boundchg->applied = FALSE; 1498 boundchg->redundant = FALSE; 1499 (*domchg)->domchgdyn.nboundchgs++; 1500 1501 /* capture branching and inference data associated with the bound changes */ 1502 SCIP_CALL( boundchgCaptureData(boundchg) ); 1503 1504 #ifdef SCIP_DISABLED_CODE /* expensive debug check */ 1505 #ifdef SCIP_MORE_DEBUG 1506 { 1507 int i; 1508 for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i ) 1509 assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS 1510 || SCIPsetIsFeasIntegral(set, (*domchg)->domchgbound.boundchgs[i].newbound)); 1511 } 1512 #endif 1513 #endif 1514 1515 return SCIP_OKAY; 1516 } 1517 1518 /** adds hole change to domain changes */ 1519 SCIP_RETCODE SCIPdomchgAddHolechg( 1520 SCIP_DOMCHG** domchg, /**< pointer to domain change data structure */ 1521 BMS_BLKMEM* blkmem, /**< block memory */ 1522 SCIP_SET* set, /**< global SCIP settings */ 1523 SCIP_HOLELIST** ptr, /**< changed list pointer */ 1524 SCIP_HOLELIST* newlist, /**< new value of list pointer */ 1525 SCIP_HOLELIST* oldlist /**< old value of list pointer */ 1526 ) 1527 { 1528 SCIP_HOLECHG* holechg; 1529 1530 assert(domchg != NULL); 1531 assert(ptr != NULL); 1532 1533 /* if domain change data doesn't exist, create it; 1534 * if domain change is static, convert it into dynamic change 1535 */ 1536 if( *domchg == NULL ) 1537 { 1538 SCIP_CALL( domchgCreate(domchg, blkmem) ); 1539 } 1540 else if( (*domchg)->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_DYNAMIC ) /*lint !e641*/ 1541 { 1542 SCIP_CALL( domchgMakeDynamic(domchg, blkmem) ); 1543 } 1544 assert(*domchg != NULL && (*domchg)->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/ 1545 1546 /* get memory for additional hole change */ 1547 SCIP_CALL( domchgEnsureHolechgsSize(*domchg, blkmem, set, (*domchg)->domchgdyn.nholechgs+1) ); 1548 1549 /* fill in the hole change data */ 1550 holechg = &(*domchg)->domchgdyn.holechgs[(*domchg)->domchgdyn.nholechgs]; 1551 holechg->ptr = ptr; 1552 holechg->newlist = newlist; 1553 holechg->oldlist = oldlist; 1554 (*domchg)->domchgdyn.nholechgs++; 1555 1556 return SCIP_OKAY; 1557 } 1558 1559 1560 1561 1562 /* 1563 * methods for variables 1564 */ 1565 1566 /** returns adjusted lower bound value, which is rounded for integral variable types */ 1567 static 1568 SCIP_Real adjustedLb( 1569 SCIP_SET* set, /**< global SCIP settings */ 1570 SCIP_VARTYPE vartype, /**< type of variable */ 1571 SCIP_Real lb /**< lower bound to adjust */ 1572 ) 1573 { 1574 if( lb < 0.0 && SCIPsetIsInfinity(set, -lb) ) 1575 return -SCIPsetInfinity(set); 1576 else if( lb > 0.0 && SCIPsetIsInfinity(set, lb) ) 1577 return SCIPsetInfinity(set); 1578 else if( vartype != SCIP_VARTYPE_CONTINUOUS ) 1579 return SCIPsetFeasCeil(set, lb); 1580 else if( lb > 0.0 && lb < SCIPsetEpsilon(set) ) 1581 return 0.0; 1582 else 1583 return lb; 1584 } 1585 1586 /** returns adjusted upper bound value, which is rounded for integral variable types */ 1587 static 1588 SCIP_Real adjustedUb( 1589 SCIP_SET* set, /**< global SCIP settings */ 1590 SCIP_VARTYPE vartype, /**< type of variable */ 1591 SCIP_Real ub /**< upper bound to adjust */ 1592 ) 1593 { 1594 if( ub > 0.0 && SCIPsetIsInfinity(set, ub) ) 1595 return SCIPsetInfinity(set); 1596 else if( ub < 0.0 && SCIPsetIsInfinity(set, -ub) ) 1597 return -SCIPsetInfinity(set); 1598 else if( vartype != SCIP_VARTYPE_CONTINUOUS ) 1599 return SCIPsetFeasFloor(set, ub); 1600 else if( ub < 0.0 && ub > -SCIPsetEpsilon(set) ) 1601 return 0.0; 1602 else 1603 return ub; 1604 } 1605 1606 /** removes (redundant) cliques, implications and variable bounds of variable from all other variables' implications and variable 1607 * bounds arrays, and optionally removes them also from the variable itself 1608 */ 1609 SCIP_RETCODE SCIPvarRemoveCliquesImplicsVbs( 1610 SCIP_VAR* var, /**< problem variable */ 1611 BMS_BLKMEM* blkmem, /**< block memory */ 1612 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 1613 SCIP_SET* set, /**< global SCIP settings */ 1614 SCIP_Bool irrelevantvar, /**< has the variable become irrelevant? */ 1615 SCIP_Bool onlyredundant, /**< should only the redundant implications and variable bounds be removed? */ 1616 SCIP_Bool removefromvar /**< should the implications and variable bounds be removed from the var itself? */ 1617 ) 1618 { 1619 SCIP_Real lb; 1620 SCIP_Real ub; 1621 1622 assert(var != NULL); 1623 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 1624 assert(SCIPvarIsActive(var) || SCIPvarGetType(var) != SCIP_VARTYPE_BINARY); 1625 1626 lb = SCIPvarGetLbGlobal(var); 1627 ub = SCIPvarGetUbGlobal(var); 1628 1629 SCIPsetDebugMsg(set, "removing %s implications and vbounds of %s<%s>[%g,%g]\n", 1630 onlyredundant ? "redundant" : "all", irrelevantvar ? "irrelevant " : "", SCIPvarGetName(var), lb, ub); 1631 1632 /* remove implications of (fixed) binary variable */ 1633 if( var->implics != NULL && (!onlyredundant || lb > 0.5 || ub < 0.5) ) 1634 { 1635 SCIP_Bool varfixing; 1636 1637 assert(SCIPvarIsBinary(var)); 1638 1639 varfixing = FALSE; 1640 do 1641 { 1642 SCIP_VAR** implvars; 1643 SCIP_BOUNDTYPE* impltypes; 1644 int nimpls; 1645 int i; 1646 1647 nimpls = SCIPimplicsGetNImpls(var->implics, varfixing); 1648 implvars = SCIPimplicsGetVars(var->implics, varfixing); 1649 impltypes = SCIPimplicsGetTypes(var->implics, varfixing); 1650 1651 for( i = 0; i < nimpls; i++ ) 1652 { 1653 SCIP_VAR* implvar; 1654 SCIP_BOUNDTYPE impltype; 1655 1656 implvar = implvars[i]; 1657 impltype = impltypes[i]; 1658 assert(implvar != var); 1659 1660 /* remove for all implications z == 0 / 1 ==> x <= p / x >= p (x not binary) 1661 * the following variable bound from x's variable bounds 1662 * x <= b*z+d (z in vubs of x) , for z == 0 / 1 ==> x <= p 1663 * x >= b*z+d (z in vlbs of x) , for z == 0 / 1 ==> x >= p 1664 */ 1665 if( impltype == SCIP_BOUNDTYPE_UPPER ) 1666 { 1667 if( implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */ 1668 { 1669 SCIPsetDebugMsg(set, "deleting variable bound: <%s> == %u ==> <%s> <= %g\n", 1670 SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar), 1671 SCIPimplicsGetBounds(var->implics, varfixing)[i]); 1672 SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, varfixing) ); 1673 implvar->closestvblpcount = -1; 1674 var->closestvblpcount = -1; 1675 } 1676 } 1677 else 1678 { 1679 if( implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */ 1680 { 1681 SCIPsetDebugMsg(set, "deleting variable bound: <%s> == %u ==> <%s> >= %g\n", 1682 SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar), 1683 SCIPimplicsGetBounds(var->implics, varfixing)[i]); 1684 SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, !varfixing) ); 1685 implvar->closestvblpcount = -1; 1686 var->closestvblpcount = -1; 1687 } 1688 } 1689 } 1690 varfixing = !varfixing; 1691 } 1692 while( varfixing == TRUE ); 1693 1694 if( removefromvar ) 1695 { 1696 /* free the implications data structures */ 1697 SCIPimplicsFree(&var->implics, blkmem); 1698 } 1699 } 1700 1701 /* remove the (redundant) variable lower bounds */ 1702 if( var->vlbs != NULL ) 1703 { 1704 SCIP_VAR** vars; 1705 SCIP_Real* coefs; 1706 SCIP_Real* constants; 1707 int nvbds; 1708 int newnvbds; 1709 int i; 1710 1711 nvbds = SCIPvboundsGetNVbds(var->vlbs); 1712 vars = SCIPvboundsGetVars(var->vlbs); 1713 coefs = SCIPvboundsGetCoefs(var->vlbs); 1714 constants = SCIPvboundsGetConstants(var->vlbs); 1715 1716 /* remove for all variable bounds x >= b*z+d the following implication from z's implications 1717 * z == ub ==> x >= b*ub + d , if b > 0 1718 * z == lb ==> x >= b*lb + d , if b < 0 1719 */ 1720 newnvbds = 0; 1721 for( i = 0; i < nvbds; i++ ) 1722 { 1723 SCIP_VAR* implvar; 1724 SCIP_Real coef; 1725 1726 assert(newnvbds <= i); 1727 1728 implvar = vars[i]; 1729 assert(implvar != NULL); 1730 1731 coef = coefs[i]; 1732 assert(!SCIPsetIsZero(set, coef)); 1733 1734 /* check, if we want to remove the variable bound */ 1735 if( onlyredundant ) 1736 { 1737 SCIP_Real vbound; 1738 1739 vbound = MAX(coef * SCIPvarGetUbGlobal(implvar), coef * SCIPvarGetLbGlobal(implvar)) + constants[i]; /*lint !e666*/ 1740 if( SCIPsetIsFeasGT(set, vbound, lb) ) 1741 { 1742 /* the variable bound is not redundant: keep it */ 1743 if( removefromvar ) 1744 { 1745 if( newnvbds < i ) 1746 { 1747 vars[newnvbds] = implvar; 1748 coefs[newnvbds] = coef; 1749 constants[newnvbds] = constants[i]; 1750 } 1751 newnvbds++; 1752 } 1753 continue; 1754 } 1755 } 1756 1757 /* remove the corresponding implication */ 1758 if( implvar->implics != NULL ) /* variable may have been aggregated in the mean time */ 1759 { 1760 SCIPsetDebugMsg(set, "deleting implication: <%s> == %d ==> <%s> >= %g\n", 1761 SCIPvarGetName(implvar), (coef > 0.0), SCIPvarGetName(var), MAX(coef, 0.0) + constants[i]); 1762 SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (coef > 0.0), var, SCIP_BOUNDTYPE_LOWER) ); 1763 } 1764 if( coef > 0.0 && implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */ 1765 { 1766 SCIPsetDebugMsg(set, "deleting variable upper bound from <%s> involving variable %s\n", 1767 SCIPvarGetName(implvar), SCIPvarGetName(var)); 1768 SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, FALSE) ); 1769 implvar->closestvblpcount = -1; 1770 var->closestvblpcount = -1; 1771 } 1772 else if( coef < 0.0 && implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */ 1773 { 1774 SCIPsetDebugMsg(set, "deleting variable lower bound from <%s> involving variable %s\n", 1775 SCIPvarGetName(implvar), SCIPvarGetName(var)); 1776 SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, TRUE) ); 1777 implvar->closestvblpcount = -1; 1778 var->closestvblpcount = -1; 1779 } 1780 } 1781 1782 if( removefromvar ) 1783 { 1784 /* update the number of variable bounds */ 1785 SCIPvboundsShrink(&var->vlbs, blkmem, newnvbds); 1786 var->closestvblpcount = -1; 1787 } 1788 } 1789 1790 /**@todo in general, variable bounds like x >= b*z + d corresponding to an implication like z = ub ==> x >= b*ub + d 1791 * might be missing because we only add variable bounds with reasonably small value of b. thus, we currently 1792 * cannot remove such variables x from z's implications. 1793 */ 1794 1795 /* remove the (redundant) variable upper bounds */ 1796 if( var->vubs != NULL ) 1797 { 1798 SCIP_VAR** vars; 1799 SCIP_Real* coefs; 1800 SCIP_Real* constants; 1801 int nvbds; 1802 int newnvbds; 1803 int i; 1804 1805 nvbds = SCIPvboundsGetNVbds(var->vubs); 1806 vars = SCIPvboundsGetVars(var->vubs); 1807 coefs = SCIPvboundsGetCoefs(var->vubs); 1808 constants = SCIPvboundsGetConstants(var->vubs); 1809 1810 /* remove for all variable bounds x <= b*z+d the following implication from z's implications 1811 * z == lb ==> x <= b*lb + d , if b > 0 1812 * z == ub ==> x <= b*ub + d , if b < 0 1813 */ 1814 newnvbds = 0; 1815 for( i = 0; i < nvbds; i++ ) 1816 { 1817 SCIP_VAR* implvar; 1818 SCIP_Real coef; 1819 1820 assert(newnvbds <= i); 1821 1822 implvar = vars[i]; 1823 assert(implvar != NULL); 1824 1825 coef = coefs[i]; 1826 assert(!SCIPsetIsZero(set, coef)); 1827 1828 /* check, if we want to remove the variable bound */ 1829 if( onlyredundant ) 1830 { 1831 SCIP_Real vbound; 1832 1833 vbound = MIN(coef * SCIPvarGetUbGlobal(implvar), coef * SCIPvarGetLbGlobal(implvar)) + constants[i]; /*lint !e666*/ 1834 if( SCIPsetIsFeasLT(set, vbound, ub) ) 1835 { 1836 /* the variable bound is not redundant: keep it */ 1837 if( removefromvar ) 1838 { 1839 if( newnvbds < i ) 1840 { 1841 vars[newnvbds] = implvar; 1842 coefs[newnvbds] = coefs[i]; 1843 constants[newnvbds] = constants[i]; 1844 } 1845 newnvbds++; 1846 } 1847 continue; 1848 } 1849 } 1850 1851 /* remove the corresponding implication */ 1852 if( implvar->implics != NULL ) /* variable may have been aggregated in the mean time */ 1853 { 1854 SCIPsetDebugMsg(set, "deleting implication: <%s> == %d ==> <%s> <= %g\n", 1855 SCIPvarGetName(implvar), (coef < 0.0), SCIPvarGetName(var), MIN(coef, 0.0) + constants[i]); 1856 SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (coef < 0.0), var, SCIP_BOUNDTYPE_UPPER) ); 1857 } 1858 if( coef < 0.0 && implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */ 1859 { 1860 SCIPsetDebugMsg(set, "deleting variable upper bound from <%s> involving variable %s\n", 1861 SCIPvarGetName(implvar), SCIPvarGetName(var)); 1862 SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, TRUE) ); 1863 implvar->closestvblpcount = -1; 1864 var->closestvblpcount = -1; 1865 } 1866 else if( coef > 0.0 && implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */ 1867 { 1868 SCIPsetDebugMsg(set, "deleting variable lower bound from <%s> involving variable %s\n", 1869 SCIPvarGetName(implvar), SCIPvarGetName(var)); 1870 SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, FALSE) ); 1871 implvar->closestvblpcount = -1; 1872 var->closestvblpcount = -1; 1873 } 1874 } 1875 1876 if( removefromvar ) 1877 { 1878 /* update the number of variable bounds */ 1879 SCIPvboundsShrink(&var->vubs, blkmem, newnvbds); 1880 var->closestvblpcount = -1; 1881 } 1882 } 1883 1884 /* remove the variable from all cliques */ 1885 if( SCIPvarIsBinary(var) ) 1886 SCIPcliquelistRemoveFromCliques(var->cliquelist, cliquetable, var, irrelevantvar); 1887 1888 /**@todo variable bounds like x <= b*z + d with z general integer are not removed from x's vbd arrays, because 1889 * z has no link (like in the binary case) to x 1890 */ 1891 1892 return SCIP_OKAY; 1893 } 1894 1895 /** sets the variable name */ 1896 static 1897 SCIP_RETCODE varSetName( 1898 SCIP_VAR* var, /**< problem variable */ 1899 BMS_BLKMEM* blkmem, /**< block memory */ 1900 SCIP_STAT* stat, /**< problem statistics, or NULL */ 1901 const char* name /**< name of variable, or NULL for automatic name creation */ 1902 ) 1903 { 1904 assert(blkmem != NULL); 1905 assert(var != NULL); 1906 1907 if( name == NULL ) 1908 { 1909 char s[SCIP_MAXSTRLEN]; 1910 1911 assert(stat != NULL); 1912 1913 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "_var%d_", stat->nvaridx); 1914 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->name, s, strlen(s)+1) ); 1915 } 1916 else 1917 { 1918 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->name, name, strlen(name)+1) ); 1919 } 1920 1921 return SCIP_OKAY; 1922 } 1923 1924 1925 /** creates variable; if variable is of integral type, fractional bounds are automatically rounded; an integer variable 1926 * with bounds zero and one is automatically converted into a binary variable 1927 */ 1928 static 1929 SCIP_RETCODE varCreate( 1930 SCIP_VAR** var, /**< pointer to variable data */ 1931 BMS_BLKMEM* blkmem, /**< block memory */ 1932 SCIP_SET* set, /**< global SCIP settings */ 1933 SCIP_STAT* stat, /**< problem statistics */ 1934 const char* name, /**< name of variable, or NULL for automatic name creation */ 1935 SCIP_Real lb, /**< lower bound of variable */ 1936 SCIP_Real ub, /**< upper bound of variable */ 1937 SCIP_Real obj, /**< objective function value */ 1938 SCIP_VARTYPE vartype, /**< type of variable */ 1939 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */ 1940 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */ 1941 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */ 1942 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */ 1943 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */ 1944 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */ 1945 SCIP_VARDATA* vardata /**< user data for this specific variable */ 1946 ) 1947 { 1948 int i; 1949 1950 assert(var != NULL); 1951 assert(blkmem != NULL); 1952 assert(stat != NULL); 1953 1954 /* adjust bounds of variable */ 1955 lb = adjustedLb(set, vartype, lb); 1956 ub = adjustedUb(set, vartype, ub); 1957 1958 /* convert [0,1]-integers into binary variables and check that binary variables have correct bounds */ 1959 if( (SCIPsetIsEQ(set, lb, 0.0) || SCIPsetIsEQ(set, lb, 1.0)) 1960 && (SCIPsetIsEQ(set, ub, 0.0) || SCIPsetIsEQ(set, ub, 1.0)) ) 1961 { 1962 if( vartype == SCIP_VARTYPE_INTEGER ) 1963 vartype = SCIP_VARTYPE_BINARY; 1964 } 1965 else 1966 { 1967 if( vartype == SCIP_VARTYPE_BINARY ) 1968 { 1969 SCIPerrorMessage("invalid bounds [%.2g,%.2g] for binary variable <%s>\n", lb, ub, name); 1970 return SCIP_INVALIDDATA; 1971 } 1972 } 1973 1974 assert(vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, lb, 0.0) || SCIPsetIsEQ(set, lb, 1.0)); 1975 assert(vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, ub, 0.0) || SCIPsetIsEQ(set, ub, 1.0)); 1976 1977 SCIP_ALLOC( BMSallocBlockMemory(blkmem, var) ); 1978 1979 /* set variable's name */ 1980 SCIP_CALL( varSetName(*var, blkmem, stat, name) ); 1981 1982 #ifndef NDEBUG 1983 (*var)->scip = set->scip; 1984 #endif 1985 (*var)->obj = obj; 1986 (*var)->unchangedobj = obj; 1987 (*var)->branchfactor = 1.0; 1988 (*var)->rootsol = 0.0; 1989 (*var)->bestrootsol = 0.0; 1990 (*var)->bestrootredcost = 0.0; 1991 (*var)->bestrootlpobjval = SCIP_INVALID; 1992 (*var)->relaxsol = 0.0; 1993 (*var)->nlpsol = 0.0; 1994 (*var)->primsolavg = 0.5 * (lb + ub); 1995 (*var)->conflictlb = SCIP_REAL_MIN; 1996 (*var)->conflictub = SCIP_REAL_MAX; 1997 (*var)->conflictrelaxedlb = (*var)->conflictlb; 1998 (*var)->conflictrelaxedub = (*var)->conflictub; 1999 (*var)->lazylb = -SCIPsetInfinity(set); 2000 (*var)->lazyub = SCIPsetInfinity(set); 2001 (*var)->glbdom.holelist = NULL; 2002 (*var)->glbdom.lb = lb; 2003 (*var)->glbdom.ub = ub; 2004 (*var)->locdom.holelist = NULL; 2005 (*var)->locdom.lb = lb; 2006 (*var)->locdom.ub = ub; 2007 (*var)->varcopy = varcopy; 2008 (*var)->vardelorig = vardelorig; 2009 (*var)->vartrans = vartrans; 2010 (*var)->vardeltrans = vardeltrans; 2011 (*var)->vardata = vardata; 2012 (*var)->parentvars = NULL; 2013 (*var)->negatedvar = NULL; 2014 (*var)->vlbs = NULL; 2015 (*var)->vubs = NULL; 2016 (*var)->implics = NULL; 2017 (*var)->cliquelist = NULL; 2018 (*var)->eventfilter = NULL; 2019 (*var)->lbchginfos = NULL; 2020 (*var)->ubchginfos = NULL; 2021 (*var)->index = stat->nvaridx; 2022 (*var)->probindex = -1; 2023 (*var)->pseudocandindex = -1; 2024 (*var)->eventqueueindexobj = -1; 2025 (*var)->eventqueueindexlb = -1; 2026 (*var)->eventqueueindexub = -1; 2027 (*var)->parentvarssize = 0; 2028 (*var)->nparentvars = 0; 2029 (*var)->nuses = 0; 2030 (*var)->branchpriority = 0; 2031 (*var)->branchdirection = SCIP_BRANCHDIR_AUTO; /*lint !e641*/ 2032 (*var)->lbchginfossize = 0; 2033 (*var)->nlbchginfos = 0; 2034 (*var)->ubchginfossize = 0; 2035 (*var)->nubchginfos = 0; 2036 (*var)->conflictlbcount = 0; 2037 (*var)->conflictubcount = 0; 2038 (*var)->closestvlbidx = -1; 2039 (*var)->closestvubidx = -1; 2040 (*var)->closestvblpcount = -1; 2041 (*var)->initial = initial; 2042 (*var)->removable = removable; 2043 (*var)->deleted = FALSE; 2044 (*var)->donotaggr = FALSE; 2045 (*var)->donotmultaggr = FALSE; 2046 (*var)->vartype = vartype; /*lint !e641*/ 2047 (*var)->pseudocostflag = FALSE; 2048 (*var)->eventqueueimpl = FALSE; 2049 (*var)->deletable = FALSE; 2050 (*var)->delglobalstructs = FALSE; 2051 (*var)->relaxationonly = FALSE; 2052 2053 for( i = 0; i < NLOCKTYPES; i++ ) 2054 { 2055 (*var)->nlocksdown[i] = 0; 2056 (*var)->nlocksup[i] = 0; 2057 } 2058 2059 stat->nvaridx++; 2060 2061 /* create branching and inference history entries */ 2062 SCIP_CALL( SCIPhistoryCreate(&(*var)->history, blkmem) ); 2063 SCIP_CALL( SCIPhistoryCreate(&(*var)->historycrun, blkmem) ); 2064 2065 /* the value based history is only created on demand */ 2066 (*var)->valuehistory = NULL; 2067 2068 return SCIP_OKAY; 2069 } 2070 2071 /** creates and captures an original problem variable; an integer variable with bounds 2072 * zero and one is automatically converted into a binary variable 2073 */ 2074 SCIP_RETCODE SCIPvarCreateOriginal( 2075 SCIP_VAR** var, /**< pointer to variable data */ 2076 BMS_BLKMEM* blkmem, /**< block memory */ 2077 SCIP_SET* set, /**< global SCIP settings */ 2078 SCIP_STAT* stat, /**< problem statistics */ 2079 const char* name, /**< name of variable, or NULL for automatic name creation */ 2080 SCIP_Real lb, /**< lower bound of variable */ 2081 SCIP_Real ub, /**< upper bound of variable */ 2082 SCIP_Real obj, /**< objective function value */ 2083 SCIP_VARTYPE vartype, /**< type of variable */ 2084 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */ 2085 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */ 2086 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */ 2087 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */ 2088 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */ 2089 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */ 2090 SCIP_VARDATA* vardata /**< user data for this specific variable */ 2091 ) 2092 { 2093 assert(var != NULL); 2094 assert(blkmem != NULL); 2095 assert(stat != NULL); 2096 2097 /* create variable */ 2098 SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable, 2099 varcopy, vardelorig, vartrans, vardeltrans, vardata) ); 2100 2101 /* set variable status and data */ 2102 (*var)->varstatus = SCIP_VARSTATUS_ORIGINAL; /*lint !e641*/ 2103 (*var)->data.original.origdom.holelist = NULL; 2104 (*var)->data.original.origdom.lb = lb; 2105 (*var)->data.original.origdom.ub = ub; 2106 (*var)->data.original.transvar = NULL; 2107 2108 /* capture variable */ 2109 SCIPvarCapture(*var); 2110 2111 return SCIP_OKAY; 2112 } 2113 2114 /** creates and captures a loose variable belonging to the transformed problem; an integer variable with bounds 2115 * zero and one is automatically converted into a binary variable 2116 */ 2117 SCIP_RETCODE SCIPvarCreateTransformed( 2118 SCIP_VAR** var, /**< pointer to variable data */ 2119 BMS_BLKMEM* blkmem, /**< block memory */ 2120 SCIP_SET* set, /**< global SCIP settings */ 2121 SCIP_STAT* stat, /**< problem statistics */ 2122 const char* name, /**< name of variable, or NULL for automatic name creation */ 2123 SCIP_Real lb, /**< lower bound of variable */ 2124 SCIP_Real ub, /**< upper bound of variable */ 2125 SCIP_Real obj, /**< objective function value */ 2126 SCIP_VARTYPE vartype, /**< type of variable */ 2127 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */ 2128 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */ 2129 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */ 2130 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */ 2131 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */ 2132 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */ 2133 SCIP_VARDATA* vardata /**< user data for this specific variable */ 2134 ) 2135 { 2136 assert(var != NULL); 2137 assert(blkmem != NULL); 2138 2139 /* create variable */ 2140 SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable, 2141 varcopy, vardelorig, vartrans, vardeltrans, vardata) ); 2142 2143 /* create event filter for transformed variable */ 2144 SCIP_CALL( SCIPeventfilterCreate(&(*var)->eventfilter, blkmem) ); 2145 2146 /* set variable status and data */ 2147 (*var)->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/ 2148 2149 /* capture variable */ 2150 SCIPvarCapture(*var); 2151 2152 return SCIP_OKAY; 2153 } 2154 2155 /** copies and captures a variable from source to target SCIP; an integer variable with bounds zero and one is 2156 * automatically converted into a binary variable; in case the variable data cannot be copied the variable is not 2157 * copied at all 2158 */ 2159 SCIP_RETCODE SCIPvarCopy( 2160 SCIP_VAR** var, /**< pointer to store the target variable */ 2161 BMS_BLKMEM* blkmem, /**< block memory */ 2162 SCIP_SET* set, /**< global SCIP settings */ 2163 SCIP_STAT* stat, /**< problem statistics */ 2164 SCIP* sourcescip, /**< source SCIP data structure */ 2165 SCIP_VAR* sourcevar, /**< source variable */ 2166 SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of source variables corresponding 2167 * target variables */ 2168 SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of source constraints to the corresponding 2169 * target constraints */ 2170 SCIP_Bool global /**< should global or local bounds be used? */ 2171 ) 2172 { 2173 SCIP_VARDATA* targetdata; 2174 SCIP_RESULT result; 2175 SCIP_Real lb; 2176 SCIP_Real ub; 2177 2178 assert(set != NULL); 2179 assert(blkmem != NULL); 2180 assert(stat != NULL); 2181 assert(sourcescip != NULL); 2182 assert(sourcevar != NULL); 2183 assert(var != NULL); 2184 assert(set->stage == SCIP_STAGE_PROBLEM); 2185 assert(varmap != NULL); 2186 assert(consmap != NULL); 2187 2188 /** @todo copy hole lists */ 2189 assert(global || SCIPvarGetHolelistLocal(sourcevar) == NULL); 2190 assert(!global || SCIPvarGetHolelistGlobal(sourcevar) == NULL); 2191 2192 result = SCIP_DIDNOTRUN; 2193 targetdata = NULL; 2194 2195 if( SCIPvarGetStatus(sourcevar) == SCIP_VARSTATUS_ORIGINAL ) 2196 { 2197 lb = SCIPvarGetLbOriginal(sourcevar); 2198 ub = SCIPvarGetUbOriginal(sourcevar); 2199 } 2200 else 2201 { 2202 lb = global ? SCIPvarGetLbGlobal(sourcevar) : SCIPvarGetLbLocal(sourcevar); 2203 ub = global ? SCIPvarGetUbGlobal(sourcevar) : SCIPvarGetUbLocal(sourcevar); 2204 } 2205 2206 /* creates and captures the variable in the target SCIP and initialize callback methods and variable data to NULL */ 2207 SCIP_CALL( SCIPvarCreateOriginal(var, blkmem, set, stat, SCIPvarGetName(sourcevar), 2208 lb, ub, SCIPvarGetObj(sourcevar), SCIPvarGetType(sourcevar), 2209 SCIPvarIsInitial(sourcevar), SCIPvarIsRemovable(sourcevar), 2210 NULL, NULL, NULL, NULL, NULL) ); 2211 assert(*var != NULL); 2212 2213 /* directly copy donot(mult)aggr flag */ 2214 (*var)->donotaggr = sourcevar->donotaggr; 2215 (*var)->donotmultaggr = sourcevar->donotmultaggr; 2216 2217 /* insert variable into mapping between source SCIP and the target SCIP */ 2218 assert(!SCIPhashmapExists(varmap, sourcevar)); 2219 SCIP_CALL( SCIPhashmapInsert(varmap, sourcevar, *var) ); 2220 2221 /* in case there exists variable data and the variable data copy callback, try to copy variable data */ 2222 if( sourcevar->vardata != NULL && sourcevar->varcopy != NULL ) 2223 { 2224 SCIP_CALL( sourcevar->varcopy(set->scip, sourcescip, sourcevar, sourcevar->vardata, 2225 varmap, consmap, (*var), &targetdata, &result) ); 2226 2227 /* evaluate result */ 2228 if( result != SCIP_DIDNOTRUN && result != SCIP_SUCCESS ) 2229 { 2230 SCIPerrorMessage("variable data copying method returned invalid result <%d>\n", result); 2231 return SCIP_INVALIDRESULT; 2232 } 2233 2234 assert(targetdata == NULL || result == SCIP_SUCCESS); 2235 2236 /* if copying was successful, add the created variable data to the variable as well as all callback methods */ 2237 if( result == SCIP_SUCCESS ) 2238 { 2239 (*var)->varcopy = sourcevar->varcopy; 2240 (*var)->vardelorig = sourcevar->vardelorig; 2241 (*var)->vartrans = sourcevar->vartrans; 2242 (*var)->vardeltrans = sourcevar->vardeltrans; 2243 (*var)->vardata = targetdata; 2244 } 2245 } 2246 2247 /* we initialize histories of the variables by copying the source variable-information */ 2248 if( set->history_allowtransfer ) 2249 { 2250 SCIPvarMergeHistories((*var), sourcevar, stat); 2251 } 2252 2253 /* in case the copying was successfully, add the created variable data to the variable as well as all callback 2254 * methods 2255 */ 2256 if( result == SCIP_SUCCESS ) 2257 { 2258 (*var)->varcopy = sourcevar->varcopy; 2259 (*var)->vardelorig = sourcevar->vardelorig; 2260 (*var)->vartrans = sourcevar->vartrans; 2261 (*var)->vardeltrans = sourcevar->vardeltrans; 2262 (*var)->vardata = targetdata; 2263 } 2264 2265 SCIPsetDebugMsg(set, "created copy <%s> of variable <%s>\n", SCIPvarGetName(*var), SCIPvarGetName(sourcevar)); 2266 2267 return SCIP_OKAY; 2268 } 2269 2270 /** parse given string for a SCIP_Real bound */ 2271 static 2272 SCIP_RETCODE parseValue( 2273 SCIP_SET* set, /**< global SCIP settings */ 2274 const char* str, /**< string to parse */ 2275 SCIP_Real* value, /**< pointer to store the parsed value */ 2276 char** endptr /**< pointer to store the final string position if successfully parsed */ 2277 ) 2278 { 2279 /* first check for infinity value */ 2280 if( strncmp(str, "+inf", 4) == 0 ) 2281 { 2282 *value = SCIPsetInfinity(set); 2283 (*endptr) = (char*)str + 4; 2284 } 2285 else if( strncmp(str, "-inf", 4) == 0 ) 2286 { 2287 *value = -SCIPsetInfinity(set); 2288 (*endptr) = (char*)str + 4; 2289 } 2290 else 2291 { 2292 if( !SCIPstrToRealValue(str, value, endptr) ) 2293 { 2294 SCIPerrorMessage("expected value: %s.\n", str); 2295 return SCIP_READERROR; 2296 } 2297 } 2298 2299 return SCIP_OKAY; 2300 } 2301 2302 /** parse the characters as bounds */ 2303 static 2304 SCIP_RETCODE parseBounds( 2305 SCIP_SET* set, /**< global SCIP settings */ 2306 const char* str, /**< string to parse */ 2307 char* type, /**< bound type (global, local, or lazy) */ 2308 SCIP_Real* lb, /**< pointer to store the lower bound */ 2309 SCIP_Real* ub, /**< pointer to store the upper bound */ 2310 char** endptr /**< pointer to store the final string position if successfully parsed (or NULL if an error occured) */ 2311 ) 2312 { 2313 char token[SCIP_MAXSTRLEN]; 2314 char* tmpend; 2315 2316 SCIPsetDebugMsg(set, "parsing bounds: '%s'\n", str); 2317 2318 /* get bound type */ 2319 SCIPstrCopySection(str, ' ', ' ', type, SCIP_MAXSTRLEN, endptr); 2320 if ( *endptr == str 2321 || ( strncmp(type, "original", 8) != 0 && strncmp(type, "global", 6) != 0 && strncmp(type, "local", 5) != 0 && strncmp(type, "lazy", 4) != 0 ) ) 2322 { 2323 SCIPsetDebugMsg(set, "unkown bound type\n"); 2324 *endptr = NULL; 2325 return SCIP_OKAY; 2326 } 2327 2328 SCIPsetDebugMsg(set, "parsed bound type <%s>\n", type); 2329 2330 /* get lower bound */ 2331 SCIPstrCopySection(str, '[', ',', token, SCIP_MAXSTRLEN, endptr); 2332 str = *endptr; 2333 SCIP_CALL( parseValue(set, token, lb, &tmpend) ); 2334 2335 /* get upper bound */ 2336 SCIP_CALL( parseValue(set, str, ub, endptr) ); 2337 2338 SCIPsetDebugMsg(set, "parsed bounds: [%g,%g]\n", *lb, *ub); 2339 2340 /* skip end of bounds */ 2341 while ( **endptr != '\0' && (**endptr == ']' || **endptr == ',') ) 2342 ++(*endptr); 2343 2344 return SCIP_OKAY; 2345 } 2346 2347 /** parses a given string for a variable informations */ 2348 static 2349 SCIP_RETCODE varParse( 2350 SCIP_SET* set, /**< global SCIP settings */ 2351 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 2352 const char* str, /**< string to parse */ 2353 char* name, /**< pointer to store the variable name */ 2354 SCIP_Real* lb, /**< pointer to store the lower bound */ 2355 SCIP_Real* ub, /**< pointer to store the upper bound */ 2356 SCIP_Real* obj, /**< pointer to store the objective coefficient */ 2357 SCIP_VARTYPE* vartype, /**< pointer to store the variable type */ 2358 SCIP_Real* lazylb, /**< pointer to store if the lower bound is lazy */ 2359 SCIP_Real* lazyub, /**< pointer to store if the upper bound is lazy */ 2360 SCIP_Bool local, /**< should the local bound be applied */ 2361 char** endptr, /**< pointer to store the final string position if successfully */ 2362 SCIP_Bool* success /**< pointer store if the paring process was successful */ 2363 ) 2364 { 2365 SCIP_Real parsedlb; 2366 SCIP_Real parsedub; 2367 char token[SCIP_MAXSTRLEN]; 2368 char* strptr; 2369 int i; 2370 2371 assert(lb != NULL); 2372 assert(ub != NULL); 2373 assert(obj != NULL); 2374 assert(vartype != NULL); 2375 assert(lazylb != NULL); 2376 assert(lazyub != NULL); 2377 assert(success != NULL); 2378 2379 (*success) = TRUE; 2380 2381 /* copy variable type */ 2382 SCIPstrCopySection(str, '[', ']', token, SCIP_MAXSTRLEN, endptr); 2383 assert(*endptr != str); 2384 SCIPsetDebugMsg(set, "parsed variable type <%s>\n", token); 2385 2386 /* get variable type */ 2387 if( strncmp(token, "binary", 3) == 0 ) 2388 (*vartype) = SCIP_VARTYPE_BINARY; 2389 else if( strncmp(token, "integer", 3) == 0 ) 2390 (*vartype) = SCIP_VARTYPE_INTEGER; 2391 else if( strncmp(token, "implicit", 3) == 0 ) 2392 (*vartype) = SCIP_VARTYPE_IMPLINT; 2393 else if( strncmp(token, "continuous", 3) == 0 ) 2394 (*vartype) = SCIP_VARTYPE_CONTINUOUS; 2395 else 2396 { 2397 SCIPmessagePrintWarning(messagehdlr, "unknown variable type\n"); 2398 (*success) = FALSE; 2399 return SCIP_OKAY; 2400 } 2401 2402 /* move string pointer behind variable type */ 2403 str = *endptr; 2404 2405 /* get variable name */ 2406 SCIPstrCopySection(str, '<', '>', name, SCIP_MAXSTRLEN, endptr); 2407 assert(*endptr != str); 2408 SCIPsetDebugMsg(set, "parsed variable name <%s>\n", name); 2409 2410 /* move string pointer behind variable name */ 2411 str = *endptr; 2412 2413 /* cut out objective coefficient */ 2414 SCIPstrCopySection(str, '=', ',', token, SCIP_MAXSTRLEN, endptr); 2415 2416 /* move string pointer behind objective coefficient */ 2417 str = *endptr; 2418 2419 /* get objective coefficient */ 2420 if( !SCIPstrToRealValue(token, obj, endptr) ) 2421 { 2422 *endptr = NULL; 2423 return SCIP_READERROR; 2424 } 2425 2426 SCIPsetDebugMsg(set, "parsed objective coefficient <%g>\n", *obj); 2427 2428 /* parse global/original bounds */ 2429 SCIP_CALL( parseBounds(set, str, token, lb, ub, endptr) ); 2430 if ( *endptr == NULL ) 2431 { 2432 SCIPerrorMessage("Expected bound type: %s.\n", token); 2433 return SCIP_READERROR; 2434 } 2435 assert(strncmp(token, "global", 6) == 0 || strncmp(token, "original", 8) == 0); 2436 2437 /* initialize the lazy bound */ 2438 *lazylb = -SCIPsetInfinity(set); 2439 *lazyub = SCIPsetInfinity(set); 2440 2441 /* store pointer */ 2442 strptr = *endptr; 2443 2444 /* possibly parse optional local and lazy bounds */ 2445 for( i = 0; i < 2 && *endptr != NULL && **endptr != '\0'; ++i ) 2446 { 2447 /* start after previous bounds */ 2448 strptr = *endptr; 2449 2450 /* parse global bounds */ 2451 SCIP_CALL( parseBounds(set, strptr, token, &parsedlb, &parsedub, endptr) ); 2452 2453 /* stop if parsing of bounds failed */ 2454 if( *endptr == NULL ) 2455 break; 2456 2457 if( strncmp(token, "local", 5) == 0 && local ) 2458 { 2459 *lb = parsedlb; 2460 *ub = parsedub; 2461 } 2462 else if( strncmp(token, "lazy", 4) == 0 ) 2463 { 2464 *lazylb = parsedlb; 2465 *lazyub = parsedub; 2466 } 2467 } 2468 2469 /* restore pointer */ 2470 if ( *endptr == NULL ) 2471 *endptr = strptr; 2472 2473 /* check bounds for binary variables */ 2474 if ( (*vartype) == SCIP_VARTYPE_BINARY ) 2475 { 2476 if ( SCIPsetIsLT(set, *lb, 0.0) || SCIPsetIsGT(set, *ub, 1.0) ) 2477 { 2478 SCIPerrorMessage("Parsed invalid bounds for binary variable <%s>: [%f, %f].\n", name, *lb, *ub); 2479 return SCIP_READERROR; 2480 } 2481 if ( !SCIPsetIsInfinity(set, -(*lazylb)) && !SCIPsetIsInfinity(set, *lazyub) && 2482 ( SCIPsetIsLT(set, *lazylb, 0.0) || SCIPsetIsGT(set, *lazyub, 1.0) ) ) 2483 { 2484 SCIPerrorMessage("Parsed invalid lazy bounds for binary variable <%s>: [%f, %f].\n", name, *lazylb, *lazyub); 2485 return SCIP_READERROR; 2486 } 2487 } 2488 2489 return SCIP_OKAY; 2490 } 2491 2492 /** parses variable information (in cip format) out of a string; if the parsing process was successful an original 2493 * variable is created and captured; if variable is of integral type, fractional bounds are automatically rounded; an 2494 * integer variable with bounds zero and one is automatically converted into a binary variable 2495 */ 2496 SCIP_RETCODE SCIPvarParseOriginal( 2497 SCIP_VAR** var, /**< pointer to variable data */ 2498 BMS_BLKMEM* blkmem, /**< block memory */ 2499 SCIP_SET* set, /**< global SCIP settings */ 2500 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 2501 SCIP_STAT* stat, /**< problem statistics */ 2502 const char* str, /**< string to parse */ 2503 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */ 2504 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */ 2505 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */ 2506 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable */ 2507 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data */ 2508 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable */ 2509 SCIP_VARDATA* vardata, /**< user data for this specific variable */ 2510 char** endptr, /**< pointer to store the final string position if successfully */ 2511 SCIP_Bool* success /**< pointer store if the paring process was successful */ 2512 ) 2513 { 2514 char name[SCIP_MAXSTRLEN]; 2515 SCIP_Real lb; 2516 SCIP_Real ub; 2517 SCIP_Real obj; 2518 SCIP_VARTYPE vartype; 2519 SCIP_Real lazylb; 2520 SCIP_Real lazyub; 2521 2522 assert(var != NULL); 2523 assert(blkmem != NULL); 2524 assert(stat != NULL); 2525 assert(endptr != NULL); 2526 assert(success != NULL); 2527 2528 /* parse string in cip format for variable information */ 2529 SCIP_CALL( varParse(set, messagehdlr, str, name, &lb, &ub, &obj, &vartype, &lazylb, &lazyub, FALSE, endptr, success) ); 2530 2531 if( *success ) /*lint !e774*/ 2532 { 2533 /* create variable */ 2534 SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable, 2535 varcopy, vardelorig, vartrans, vardeltrans, vardata) ); 2536 2537 /* set variable status and data */ 2538 (*var)->varstatus = SCIP_VARSTATUS_ORIGINAL; /*lint !e641*/ 2539 (*var)->data.original.origdom.holelist = NULL; 2540 (*var)->data.original.origdom.lb = lb; 2541 (*var)->data.original.origdom.ub = ub; 2542 (*var)->data.original.transvar = NULL; 2543 2544 /* set lazy status of variable bounds */ 2545 (*var)->lazylb = lazylb; 2546 (*var)->lazyub = lazyub; 2547 2548 /* capture variable */ 2549 SCIPvarCapture(*var); 2550 } 2551 2552 return SCIP_OKAY; 2553 } 2554 2555 /** parses variable information (in cip format) out of a string; if the parsing process was successful a loose variable 2556 * belonging to the transformed problem is created and captured; if variable is of integral type, fractional bounds are 2557 * automatically rounded; an integer variable with bounds zero and one is automatically converted into a binary 2558 * variable 2559 */ 2560 SCIP_RETCODE SCIPvarParseTransformed( 2561 SCIP_VAR** var, /**< pointer to variable data */ 2562 BMS_BLKMEM* blkmem, /**< block memory */ 2563 SCIP_SET* set, /**< global SCIP settings */ 2564 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 2565 SCIP_STAT* stat, /**< problem statistics */ 2566 const char* str, /**< string to parse */ 2567 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */ 2568 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */ 2569 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */ 2570 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable */ 2571 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data */ 2572 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable */ 2573 SCIP_VARDATA* vardata, /**< user data for this specific variable */ 2574 char** endptr, /**< pointer to store the final string position if successfully */ 2575 SCIP_Bool* success /**< pointer store if the paring process was successful */ 2576 ) 2577 { 2578 char name[SCIP_MAXSTRLEN]; 2579 SCIP_Real lb; 2580 SCIP_Real ub; 2581 SCIP_Real obj; 2582 SCIP_VARTYPE vartype; 2583 SCIP_Real lazylb; 2584 SCIP_Real lazyub; 2585 2586 assert(var != NULL); 2587 assert(blkmem != NULL); 2588 assert(endptr != NULL); 2589 assert(success != NULL); 2590 2591 /* parse string in cip format for variable information */ 2592 SCIP_CALL( varParse(set, messagehdlr, str, name, &lb, &ub, &obj, &vartype, &lazylb, &lazyub, TRUE, endptr, success) ); 2593 2594 if( *success ) /*lint !e774*/ 2595 { 2596 /* create variable */ 2597 SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable, 2598 varcopy, vardelorig, vartrans, vardeltrans, vardata) ); 2599 2600 /* create event filter for transformed variable */ 2601 SCIP_CALL( SCIPeventfilterCreate(&(*var)->eventfilter, blkmem) ); 2602 2603 /* set variable status and data */ 2604 (*var)->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/ 2605 2606 /* set lazy status of variable bounds */ 2607 (*var)->lazylb = lazylb; 2608 (*var)->lazyub = lazyub; 2609 2610 /* capture variable */ 2611 SCIPvarCapture(*var); 2612 } 2613 2614 return SCIP_OKAY; 2615 } 2616 2617 /** ensures, that parentvars array of var can store at least num entries */ 2618 static 2619 SCIP_RETCODE varEnsureParentvarsSize( 2620 SCIP_VAR* var, /**< problem variable */ 2621 BMS_BLKMEM* blkmem, /**< block memory */ 2622 SCIP_SET* set, /**< global SCIP settings */ 2623 int num /**< minimum number of entries to store */ 2624 ) 2625 { 2626 assert(var->nparentvars <= var->parentvarssize); 2627 2628 if( num > var->parentvarssize ) 2629 { 2630 int newsize; 2631 2632 newsize = SCIPsetCalcMemGrowSize(set, num); 2633 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->parentvars, var->parentvarssize, newsize) ); 2634 var->parentvarssize = newsize; 2635 } 2636 assert(num <= var->parentvarssize); 2637 2638 return SCIP_OKAY; 2639 } 2640 2641 /** adds variable to parent list of a variable and captures parent variable */ 2642 static 2643 SCIP_RETCODE varAddParent( 2644 SCIP_VAR* var, /**< variable to add parent to */ 2645 BMS_BLKMEM* blkmem, /**< block memory of transformed problem */ 2646 SCIP_SET* set, /**< global SCIP settings */ 2647 SCIP_VAR* parentvar /**< parent variable to add */ 2648 ) 2649 { 2650 assert(var != NULL); 2651 assert(parentvar != NULL); 2652 2653 /* the direct original counterpart must be stored as first parent */ 2654 assert(var->nparentvars == 0 || SCIPvarGetStatus(parentvar) != SCIP_VARSTATUS_ORIGINAL); 2655 2656 SCIPsetDebugMsg(set, "adding parent <%s>[%p] to variable <%s>[%p] in slot %d\n", 2657 parentvar->name, (void*)parentvar, var->name, (void*)var, var->nparentvars); 2658 2659 SCIP_CALL( varEnsureParentvarsSize(var, blkmem, set, var->nparentvars+1) ); 2660 2661 var->parentvars[var->nparentvars] = parentvar; 2662 var->nparentvars++; 2663 2664 SCIPvarCapture(parentvar); 2665 2666 return SCIP_OKAY; 2667 } 2668 2669 /** deletes and releases all variables from the parent list of a variable, frees the memory of parents array */ 2670 static 2671 SCIP_RETCODE varFreeParents( 2672 SCIP_VAR** var, /**< pointer to variable */ 2673 BMS_BLKMEM* blkmem, /**< block memory */ 2674 SCIP_SET* set, /**< global SCIP settings */ 2675 SCIP_EVENTQUEUE* eventqueue, /**< event queue (or NULL, if it's an original variable) */ 2676 SCIP_LP* lp /**< current LP data (or NULL, if it's an original variable) */ 2677 ) 2678 { 2679 SCIP_VAR* parentvar; 2680 int i; 2681 2682 SCIPsetDebugMsg(set, "free parents of <%s>\n", (*var)->name); 2683 2684 /* release the parent variables and remove the link from the parent variable to the child */ 2685 for( i = 0; i < (*var)->nparentvars; ++i ) 2686 { 2687 assert((*var)->parentvars != NULL); 2688 parentvar = (*var)->parentvars[i]; 2689 assert(parentvar != NULL); 2690 2691 switch( SCIPvarGetStatus(parentvar) ) 2692 { 2693 case SCIP_VARSTATUS_ORIGINAL: 2694 assert(parentvar->data.original.transvar == *var); 2695 assert(&parentvar->data.original.transvar != var); 2696 parentvar->data.original.transvar = NULL; 2697 break; 2698 2699 case SCIP_VARSTATUS_AGGREGATED: 2700 assert(parentvar->data.aggregate.var == *var); 2701 assert(&parentvar->data.aggregate.var != var); 2702 parentvar->data.aggregate.var = NULL; 2703 break; 2704 2705 #if 0 2706 /* The following code is unclear: should the current variable be removed from its parents? */ 2707 case SCIP_VARSTATUS_MULTAGGR: 2708 assert(parentvar->data.multaggr.vars != NULL); 2709 for( v = 0; v < parentvar->data.multaggr.nvars && parentvar->data.multaggr.vars[v] != *var; ++v ) 2710 {} 2711 assert(v < parentvar->data.multaggr.nvars && parentvar->data.multaggr.vars[v] == *var); 2712 if( v < parentvar->data.multaggr.nvars-1 ) 2713 { 2714 parentvar->data.multaggr.vars[v] = parentvar->data.multaggr.vars[parentvar->data.multaggr.nvars-1]; 2715 parentvar->data.multaggr.scalars[v] = parentvar->data.multaggr.scalars[parentvar->data.multaggr.nvars-1]; 2716 } 2717 parentvar->data.multaggr.nvars--; 2718 break; 2719 #endif 2720 2721 case SCIP_VARSTATUS_NEGATED: 2722 assert(parentvar->negatedvar == *var); 2723 assert((*var)->negatedvar == parentvar); 2724 parentvar->negatedvar = NULL; 2725 (*var)->negatedvar = NULL; 2726 break; 2727 2728 default: 2729 SCIPerrorMessage("parent variable is neither ORIGINAL, AGGREGATED nor NEGATED\n"); 2730 return SCIP_INVALIDDATA; 2731 } /*lint !e788*/ 2732 2733 SCIP_CALL( SCIPvarRelease(&(*var)->parentvars[i], blkmem, set, eventqueue, lp) ); 2734 } 2735 2736 /* free parentvars array */ 2737 BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->parentvars, (*var)->parentvarssize); 2738 2739 return SCIP_OKAY; 2740 } 2741 2742 /** frees a variable */ 2743 static 2744 SCIP_RETCODE varFree( 2745 SCIP_VAR** var, /**< pointer to variable */ 2746 BMS_BLKMEM* blkmem, /**< block memory */ 2747 SCIP_SET* set, /**< global SCIP settings */ 2748 SCIP_EVENTQUEUE* eventqueue, /**< event queue (may be NULL, if it's not a column variable) */ 2749 SCIP_LP* lp /**< current LP data (may be NULL, if it's not a column variable) */ 2750 ) 2751 { 2752 assert(var != NULL); 2753 assert(*var != NULL); 2754 assert(SCIPvarGetStatus(*var) != SCIP_VARSTATUS_COLUMN || &(*var)->data.col->var != var); 2755 assert((*var)->nuses == 0); 2756 assert((*var)->probindex == -1); 2757 assert((*var)->nlocksup[SCIP_LOCKTYPE_MODEL] == 0); 2758 assert((*var)->nlocksdown[SCIP_LOCKTYPE_MODEL] == 0); 2759 2760 SCIPsetDebugMsg(set, "free variable <%s> with status=%d\n", (*var)->name, SCIPvarGetStatus(*var)); 2761 2762 switch( SCIPvarGetStatus(*var) ) 2763 { 2764 case SCIP_VARSTATUS_ORIGINAL: 2765 assert((*var)->data.original.transvar == NULL); /* cannot free variable, if transformed variable is still existing */ 2766 holelistFree(&(*var)->data.original.origdom.holelist, blkmem); 2767 assert((*var)->data.original.origdom.holelist == NULL); 2768 break; 2769 case SCIP_VARSTATUS_LOOSE: 2770 break; 2771 case SCIP_VARSTATUS_COLUMN: 2772 SCIP_CALL( SCIPcolFree(&(*var)->data.col, blkmem, set, eventqueue, lp) ); /* free corresponding LP column */ 2773 break; 2774 case SCIP_VARSTATUS_FIXED: 2775 case SCIP_VARSTATUS_AGGREGATED: 2776 break; 2777 case SCIP_VARSTATUS_MULTAGGR: 2778 BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.vars, (*var)->data.multaggr.varssize); 2779 BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.scalars, (*var)->data.multaggr.varssize); 2780 break; 2781 case SCIP_VARSTATUS_NEGATED: 2782 break; 2783 default: 2784 SCIPerrorMessage("unknown variable status\n"); 2785 return SCIP_INVALIDDATA; 2786 } 2787 2788 /* release all parent variables and free the parentvars array */ 2789 SCIP_CALL( varFreeParents(var, blkmem, set, eventqueue, lp) ); 2790 2791 /* free user data */ 2792 if( SCIPvarGetStatus(*var) == SCIP_VARSTATUS_ORIGINAL ) 2793 { 2794 if( (*var)->vardelorig != NULL ) 2795 { 2796 SCIP_CALL( (*var)->vardelorig(set->scip, *var, &(*var)->vardata) ); 2797 } 2798 } 2799 else 2800 { 2801 if( (*var)->vardeltrans != NULL ) 2802 { 2803 SCIP_CALL( (*var)->vardeltrans(set->scip, *var, &(*var)->vardata) ); 2804 } 2805 } 2806 2807 /* free event filter */ 2808 if( (*var)->eventfilter != NULL ) 2809 { 2810 SCIP_CALL( SCIPeventfilterFree(&(*var)->eventfilter, blkmem, set) ); 2811 } 2812 assert((*var)->eventfilter == NULL); 2813 2814 /* free hole lists */ 2815 holelistFree(&(*var)->glbdom.holelist, blkmem); 2816 holelistFree(&(*var)->locdom.holelist, blkmem); 2817 assert((*var)->glbdom.holelist == NULL); 2818 assert((*var)->locdom.holelist == NULL); 2819 2820 /* free variable bounds data structures */ 2821 SCIPvboundsFree(&(*var)->vlbs, blkmem); 2822 SCIPvboundsFree(&(*var)->vubs, blkmem); 2823 2824 /* free implications data structures */ 2825 SCIPimplicsFree(&(*var)->implics, blkmem); 2826 2827 /* free clique list data structures */ 2828 SCIPcliquelistFree(&(*var)->cliquelist, blkmem); 2829 2830 /* free bound change information arrays */ 2831 BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->lbchginfos, (*var)->lbchginfossize); 2832 BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->ubchginfos, (*var)->ubchginfossize); 2833 2834 /* free branching and inference history entries */ 2835 SCIPhistoryFree(&(*var)->history, blkmem); 2836 SCIPhistoryFree(&(*var)->historycrun, blkmem); 2837 SCIPvaluehistoryFree(&(*var)->valuehistory, blkmem); 2838 2839 /* free variable data structure */ 2840 BMSfreeBlockMemoryArray(blkmem, &(*var)->name, strlen((*var)->name)+1); 2841 BMSfreeBlockMemory(blkmem, var); 2842 2843 return SCIP_OKAY; 2844 } 2845 2846 /** increases usage counter of variable */ 2847 void SCIPvarCapture( 2848 SCIP_VAR* var /**< variable */ 2849 ) 2850 { 2851 assert(var != NULL); 2852 assert(var->nuses >= 0); 2853 2854 SCIPdebugMessage("capture variable <%s> with nuses=%d\n", var->name, var->nuses); 2855 var->nuses++; 2856 2857 #ifdef DEBUGUSES_VARNAME 2858 if( strcmp(var->name, DEBUGUSES_VARNAME) == 0 2859 #ifdef DEBUGUSES_PROBNAME 2860 && ((var->scip->transprob != NULL && strcmp(SCIPprobGetName(var->scip->transprob), DEBUGUSES_PROBNAME) == 0) || 2861 strcmp(SCIPprobGetName(var->scip->origprob), DEBUGUSES_PROBNAME) == 0) 2862 #endif 2863 ) 2864 { 2865 printf("Captured variable " DEBUGUSES_VARNAME " in SCIP %p, now %d uses; captured at\n", (void*)var->scip, var->nuses); 2866 print_backtrace(); 2867 } 2868 #endif 2869 } 2870 2871 /** decreases usage counter of variable, and frees memory if necessary */ 2872 SCIP_RETCODE SCIPvarRelease( 2873 SCIP_VAR** var, /**< pointer to variable */ 2874 BMS_BLKMEM* blkmem, /**< block memory */ 2875 SCIP_SET* set, /**< global SCIP settings */ 2876 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 2877 SCIP_LP* lp /**< current LP data (or NULL, if it's an original variable) */ 2878 ) 2879 { 2880 assert(var != NULL); 2881 assert(*var != NULL); 2882 assert((*var)->nuses >= 1); 2883 assert(blkmem != NULL); 2884 assert((*var)->scip == set->scip); 2885 2886 SCIPsetDebugMsg(set, "release variable <%s> with nuses=%d\n", (*var)->name, (*var)->nuses); 2887 (*var)->nuses--; 2888 2889 #ifdef DEBUGUSES_VARNAME 2890 if( strcmp((*var)->name, DEBUGUSES_VARNAME) == 0 2891 #ifdef DEBUGUSES_PROBNAME 2892 && (((*var)->scip->transprob != NULL && strcmp(SCIPprobGetName((*var)->scip->transprob), DEBUGUSES_PROBNAME) == 0) || 2893 strcmp(SCIPprobGetName((*var)->scip->origprob), DEBUGUSES_PROBNAME) == 0) 2894 #endif 2895 ) 2896 { 2897 printf("Released variable " DEBUGUSES_VARNAME " in SCIP %p, now %d uses; released at\n", (void*)(*var)->scip, (*var)->nuses); 2898 print_backtrace(); 2899 } 2900 #endif 2901 2902 if( (*var)->nuses == 0 ) 2903 { 2904 SCIP_CALL( varFree(var, blkmem, set, eventqueue, lp) ); 2905 } 2906 2907 *var = NULL; 2908 2909 return SCIP_OKAY; 2910 } 2911 2912 /** change variable name */ 2913 SCIP_RETCODE SCIPvarChgName( 2914 SCIP_VAR* var, /**< problem variable */ 2915 BMS_BLKMEM* blkmem, /**< block memory */ 2916 const char* name /**< name of variable */ 2917 ) 2918 { 2919 assert(name != NULL); 2920 2921 /* remove old variable name */ 2922 BMSfreeBlockMemoryArray(blkmem, &var->name, strlen(var->name)+1); 2923 2924 /* set new variable name */ 2925 SCIP_CALL( varSetName(var, blkmem, NULL, name) ); 2926 2927 return SCIP_OKAY; 2928 } 2929 2930 /** initializes variable data structure for solving */ 2931 void SCIPvarInitSolve( 2932 SCIP_VAR* var /**< problem variable */ 2933 ) 2934 { 2935 assert(var != NULL); 2936 2937 SCIPhistoryReset(var->historycrun); 2938 var->conflictlbcount = 0; 2939 var->conflictubcount = 0; 2940 } 2941 2942 /** outputs the given bounds into the file stream */ 2943 static 2944 void printBounds( 2945 SCIP_SET* set, /**< global SCIP settings */ 2946 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 2947 FILE* file, /**< output file (or NULL for standard output) */ 2948 SCIP_Real lb, /**< lower bound */ 2949 SCIP_Real ub, /**< upper bound */ 2950 const char* name /**< bound type name */ 2951 ) 2952 { 2953 assert(set != NULL); 2954 2955 SCIPmessageFPrintInfo(messagehdlr, file, ", %s=", name); 2956 if( SCIPsetIsInfinity(set, lb) ) 2957 SCIPmessageFPrintInfo(messagehdlr, file, "[+inf,"); 2958 else if( SCIPsetIsInfinity(set, -lb) ) 2959 SCIPmessageFPrintInfo(messagehdlr, file, "[-inf,"); 2960 else 2961 SCIPmessageFPrintInfo(messagehdlr, file, "[%.15g,", lb); 2962 if( SCIPsetIsInfinity(set, ub) ) 2963 SCIPmessageFPrintInfo(messagehdlr, file, "+inf]"); 2964 else if( SCIPsetIsInfinity(set, -ub) ) 2965 SCIPmessageFPrintInfo(messagehdlr, file, "-inf]"); 2966 else 2967 SCIPmessageFPrintInfo(messagehdlr, file, "%.15g]", ub); 2968 } 2969 2970 /** prints hole list to file stream */ 2971 static 2972 void printHolelist( 2973 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 2974 FILE* file, /**< output file (or NULL for standard output) */ 2975 SCIP_HOLELIST* holelist, /**< hole list pointer to hole of interest */ 2976 const char* name /**< hole type name */ 2977 ) 2978 { /*lint --e{715}*/ 2979 SCIP_Real left; 2980 SCIP_Real right; 2981 2982 if( holelist == NULL ) 2983 return; 2984 2985 left = SCIPholelistGetLeft(holelist); 2986 right = SCIPholelistGetRight(holelist); 2987 2988 /* display first hole */ 2989 SCIPmessageFPrintInfo(messagehdlr, file, ", %s=(%g,%g)", name, left, right); 2990 holelist = SCIPholelistGetNext(holelist); 2991 2992 while(holelist != NULL ) 2993 { 2994 left = SCIPholelistGetLeft(holelist); 2995 right = SCIPholelistGetRight(holelist); 2996 2997 /* display hole */ 2998 SCIPmessageFPrintInfo(messagehdlr, file, "(%g,%g)", left, right); 2999 3000 /* get next hole */ 3001 holelist = SCIPholelistGetNext(holelist); 3002 } 3003 } 3004 3005 /** outputs variable information into file stream */ 3006 SCIP_RETCODE SCIPvarPrint( 3007 SCIP_VAR* var, /**< problem variable */ 3008 SCIP_SET* set, /**< global SCIP settings */ 3009 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 3010 FILE* file /**< output file (or NULL for standard output) */ 3011 ) 3012 { 3013 SCIP_HOLELIST* holelist; 3014 SCIP_Real lb; 3015 SCIP_Real ub; 3016 int i; 3017 3018 assert(var != NULL); 3019 assert(var->scip == set->scip); 3020 3021 /* type of variable */ 3022 switch( SCIPvarGetType(var) ) 3023 { 3024 case SCIP_VARTYPE_BINARY: 3025 SCIPmessageFPrintInfo(messagehdlr, file, " [binary]"); 3026 break; 3027 case SCIP_VARTYPE_INTEGER: 3028 SCIPmessageFPrintInfo(messagehdlr, file, " [integer]"); 3029 break; 3030 case SCIP_VARTYPE_IMPLINT: 3031 SCIPmessageFPrintInfo(messagehdlr, file, " [implicit]"); 3032 break; 3033 case SCIP_VARTYPE_CONTINUOUS: 3034 SCIPmessageFPrintInfo(messagehdlr, file, " [continuous]"); 3035 break; 3036 default: 3037 SCIPerrorMessage("unknown variable type\n"); 3038 SCIPABORT(); 3039 return SCIP_ERROR; /*lint !e527*/ 3040 } 3041 3042 /* name */ 3043 SCIPmessageFPrintInfo(messagehdlr, file, " <%s>:", var->name); 3044 3045 /* objective value */ 3046 SCIPmessageFPrintInfo(messagehdlr, file, " obj=%.15g", var->obj); 3047 3048 /* bounds (global bounds for transformed variables, original bounds for original variables) */ 3049 if( !SCIPvarIsTransformed(var) ) 3050 { 3051 /* output original bound */ 3052 lb = SCIPvarGetLbOriginal(var); 3053 ub = SCIPvarGetUbOriginal(var); 3054 printBounds(set, messagehdlr, file, lb, ub, "original bounds"); 3055 3056 /* output lazy bound */ 3057 lb = SCIPvarGetLbLazy(var); 3058 ub = SCIPvarGetUbLazy(var); 3059 3060 /* only display the lazy bounds if they are different from [-infinity,infinity] */ 3061 if( !SCIPsetIsInfinity(set, -lb) || !SCIPsetIsInfinity(set, ub) ) 3062 printBounds(set, messagehdlr, file, lb, ub, "lazy bounds"); 3063 3064 holelist = SCIPvarGetHolelistOriginal(var); 3065 printHolelist(messagehdlr, file, holelist, "original holes"); 3066 } 3067 else 3068 { 3069 /* output global bound */ 3070 lb = SCIPvarGetLbGlobal(var); 3071 ub = SCIPvarGetUbGlobal(var); 3072 printBounds(set, messagehdlr, file, lb, ub, "global bounds"); 3073 3074 /* output local bound */ 3075 lb = SCIPvarGetLbLocal(var); 3076 ub = SCIPvarGetUbLocal(var); 3077 printBounds(set, messagehdlr, file, lb, ub, "local bounds"); 3078 3079 /* output lazy bound */ 3080 lb = SCIPvarGetLbLazy(var); 3081 ub = SCIPvarGetUbLazy(var); 3082 3083 /* only display the lazy bounds if they are different from [-infinity,infinity] */ 3084 if( !SCIPsetIsInfinity(set, -lb) || !SCIPsetIsInfinity(set, ub) ) 3085 printBounds(set, messagehdlr, file, lb, ub, "lazy bounds"); 3086 3087 /* global hole list */ 3088 holelist = SCIPvarGetHolelistGlobal(var); 3089 printHolelist(messagehdlr, file, holelist, "global holes"); 3090 3091 /* local hole list */ 3092 holelist = SCIPvarGetHolelistLocal(var); 3093 printHolelist(messagehdlr, file, holelist, "local holes"); 3094 } 3095 3096 /* fixings and aggregations */ 3097 switch( SCIPvarGetStatus(var) ) 3098 { 3099 case SCIP_VARSTATUS_ORIGINAL: 3100 case SCIP_VARSTATUS_LOOSE: 3101 case SCIP_VARSTATUS_COLUMN: 3102 break; 3103 3104 case SCIP_VARSTATUS_FIXED: 3105 SCIPmessageFPrintInfo(messagehdlr, file, ", fixed:"); 3106 if( SCIPsetIsInfinity(set, var->glbdom.lb) ) 3107 SCIPmessageFPrintInfo(messagehdlr, file, "+inf"); 3108 else if( SCIPsetIsInfinity(set, -var->glbdom.lb) ) 3109 SCIPmessageFPrintInfo(messagehdlr, file, "-inf"); 3110 else 3111 SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", var->glbdom.lb); 3112 break; 3113 3114 case SCIP_VARSTATUS_AGGREGATED: 3115 SCIPmessageFPrintInfo(messagehdlr, file, ", aggregated:"); 3116 if( !SCIPsetIsZero(set, var->data.aggregate.constant) ) 3117 SCIPmessageFPrintInfo(messagehdlr, file, " %.15g", var->data.aggregate.constant); 3118 SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g<%s>", var->data.aggregate.scalar, SCIPvarGetName(var->data.aggregate.var)); 3119 break; 3120 3121 case SCIP_VARSTATUS_MULTAGGR: 3122 SCIPmessageFPrintInfo(messagehdlr, file, ", aggregated:"); 3123 if( var->data.multaggr.nvars == 0 || !SCIPsetIsZero(set, var->data.multaggr.constant) ) 3124 SCIPmessageFPrintInfo(messagehdlr, file, " %.15g", var->data.multaggr.constant); 3125 for( i = 0; i < var->data.multaggr.nvars; ++i ) 3126 SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g<%s>", var->data.multaggr.scalars[i], SCIPvarGetName(var->data.multaggr.vars[i])); 3127 break; 3128 3129 case SCIP_VARSTATUS_NEGATED: 3130 SCIPmessageFPrintInfo(messagehdlr, file, ", negated: %.15g - <%s>", var->data.negate.constant, SCIPvarGetName(var->negatedvar)); 3131 break; 3132 3133 default: 3134 SCIPerrorMessage("unknown variable status\n"); 3135 SCIPABORT(); 3136 return SCIP_ERROR; /*lint !e527*/ 3137 } 3138 3139 SCIPmessageFPrintInfo(messagehdlr, file, "\n"); 3140 3141 return SCIP_OKAY; 3142 } 3143 3144 /** issues a VARUNLOCKED event on the given variable */ 3145 static 3146 SCIP_RETCODE varEventVarUnlocked( 3147 SCIP_VAR* var, /**< problem variable to change */ 3148 BMS_BLKMEM* blkmem, /**< block memory */ 3149 SCIP_SET* set, /**< global SCIP settings */ 3150 SCIP_EVENTQUEUE* eventqueue /**< event queue */ 3151 ) 3152 { 3153 SCIP_EVENT* event; 3154 3155 assert(var != NULL); 3156 assert(var->nlocksdown[SCIP_LOCKTYPE_MODEL] <= 1 && var->nlocksup[SCIP_LOCKTYPE_MODEL] <= 1); 3157 assert(var->scip == set->scip); 3158 3159 /* issue VARUNLOCKED event on variable */ 3160 SCIP_CALL( SCIPeventCreateVarUnlocked(&event, blkmem, var) ); 3161 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) ); 3162 3163 return SCIP_OKAY; 3164 } 3165 3166 /** modifies lock numbers for rounding */ 3167 SCIP_RETCODE SCIPvarAddLocks( 3168 SCIP_VAR* var, /**< problem variable */ 3169 BMS_BLKMEM* blkmem, /**< block memory */ 3170 SCIP_SET* set, /**< global SCIP settings */ 3171 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 3172 SCIP_LOCKTYPE locktype, /**< type of the variable locks */ 3173 int addnlocksdown, /**< increase in number of rounding down locks */ 3174 int addnlocksup /**< increase in number of rounding up locks */ 3175 ) 3176 { 3177 SCIP_VAR* lockvar; 3178 3179 assert(var != NULL); 3180 assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/ 3181 assert(var->nlocksup[locktype] >= 0); 3182 assert(var->nlocksdown[locktype] >= 0); 3183 assert(var->scip == set->scip); 3184 3185 if( addnlocksdown == 0 && addnlocksup == 0 ) 3186 return SCIP_OKAY; 3187 3188 #ifdef SCIP_DEBUG 3189 SCIPsetDebugMsg(set, "add rounding locks %d/%d to variable <%s> (locks=%d/%d, type=%u)\n", 3190 addnlocksdown, addnlocksup, var->name, var->nlocksdown[locktype], var->nlocksup[locktype], locktype); 3191 #endif 3192 3193 lockvar = var; 3194 3195 while( TRUE ) /*lint !e716 */ 3196 { 3197 assert(lockvar != NULL); 3198 3199 switch( SCIPvarGetStatus(lockvar) ) 3200 { 3201 case SCIP_VARSTATUS_ORIGINAL: 3202 if( lockvar->data.original.transvar != NULL ) 3203 { 3204 lockvar = lockvar->data.original.transvar; 3205 break; 3206 } 3207 else 3208 { 3209 lockvar->nlocksdown[locktype] += addnlocksdown; 3210 lockvar->nlocksup[locktype] += addnlocksup; 3211 3212 assert(lockvar->nlocksdown[locktype] >= 0); 3213 assert(lockvar->nlocksup[locktype] >= 0); 3214 3215 return SCIP_OKAY; 3216 } 3217 case SCIP_VARSTATUS_LOOSE: 3218 case SCIP_VARSTATUS_COLUMN: 3219 case SCIP_VARSTATUS_FIXED: 3220 lockvar->nlocksdown[locktype] += addnlocksdown; 3221 lockvar->nlocksup[locktype] += addnlocksup; 3222 3223 assert(lockvar->nlocksdown[locktype] >= 0); 3224 assert(lockvar->nlocksup[locktype] >= 0); 3225 3226 if( locktype == SCIP_LOCKTYPE_MODEL && lockvar->nlocksdown[locktype] <= 1 3227 && lockvar->nlocksup[locktype] <= 1 ) 3228 { 3229 SCIP_CALL( varEventVarUnlocked(lockvar, blkmem, set, eventqueue) ); 3230 } 3231 3232 return SCIP_OKAY; 3233 case SCIP_VARSTATUS_AGGREGATED: 3234 assert(!lockvar->donotaggr); 3235 3236 if( lockvar->data.aggregate.scalar < 0.0 ) 3237 { 3238 int tmp = addnlocksup; 3239 3240 addnlocksup = addnlocksdown; 3241 addnlocksdown = tmp; 3242 } 3243 3244 lockvar = lockvar->data.aggregate.var; 3245 break; 3246 case SCIP_VARSTATUS_MULTAGGR: 3247 { 3248 int v; 3249 3250 assert(!lockvar->donotmultaggr); 3251 3252 lockvar->nlocksdown[locktype] += addnlocksdown; 3253 lockvar->nlocksup[locktype] += addnlocksup; 3254 3255 assert(lockvar->nlocksdown[locktype] >= 0); 3256 assert(lockvar->nlocksup[locktype] >= 0); 3257 3258 for( v = lockvar->data.multaggr.nvars - 1; v >= 0; --v ) 3259 { 3260 if( lockvar->data.multaggr.scalars[v] > 0.0 ) 3261 { 3262 SCIP_CALL( SCIPvarAddLocks(lockvar->data.multaggr.vars[v], blkmem, set, eventqueue, locktype, addnlocksdown, 3263 addnlocksup) ); 3264 } 3265 else 3266 { 3267 SCIP_CALL( SCIPvarAddLocks(lockvar->data.multaggr.vars[v], blkmem, set, eventqueue, locktype, addnlocksup, 3268 addnlocksdown) ); 3269 } 3270 } 3271 return SCIP_OKAY; 3272 } 3273 case SCIP_VARSTATUS_NEGATED: 3274 { 3275 int tmp = addnlocksup; 3276 3277 assert(lockvar->negatedvar != NULL); 3278 assert(SCIPvarGetStatus(lockvar->negatedvar) != SCIP_VARSTATUS_NEGATED); 3279 assert(lockvar->negatedvar->negatedvar == lockvar); 3280 3281 addnlocksup = addnlocksdown; 3282 addnlocksdown = tmp; 3283 3284 lockvar = lockvar->negatedvar; 3285 break; 3286 } 3287 default: 3288 SCIPerrorMessage("unknown variable status\n"); 3289 return SCIP_INVALIDDATA; 3290 } 3291 } 3292 } 3293 3294 /** gets number of locks for rounding down of a special type */ 3295 int SCIPvarGetNLocksDownType( 3296 SCIP_VAR* var, /**< problem variable */ 3297 SCIP_LOCKTYPE locktype /**< type of variable locks */ 3298 ) 3299 { 3300 int nlocks; 3301 int i; 3302 3303 assert(var != NULL); 3304 assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/ 3305 assert(var->nlocksdown[locktype] >= 0); 3306 3307 switch( SCIPvarGetStatus(var) ) 3308 { 3309 case SCIP_VARSTATUS_ORIGINAL: 3310 if( var->data.original.transvar != NULL ) 3311 return SCIPvarGetNLocksDownType(var->data.original.transvar, locktype); 3312 else 3313 return var->nlocksdown[locktype]; 3314 3315 case SCIP_VARSTATUS_LOOSE: 3316 case SCIP_VARSTATUS_COLUMN: 3317 case SCIP_VARSTATUS_FIXED: 3318 return var->nlocksdown[locktype]; 3319 3320 case SCIP_VARSTATUS_AGGREGATED: 3321 assert(!var->donotaggr); 3322 if( var->data.aggregate.scalar > 0.0 ) 3323 return SCIPvarGetNLocksDownType(var->data.aggregate.var, locktype); 3324 else 3325 return SCIPvarGetNLocksUpType(var->data.aggregate.var, locktype); 3326 3327 case SCIP_VARSTATUS_MULTAGGR: 3328 assert(!var->donotmultaggr); 3329 nlocks = 0; 3330 for( i = 0; i < var->data.multaggr.nvars; ++i ) 3331 { 3332 if( var->data.multaggr.scalars[i] > 0.0 ) 3333 nlocks += SCIPvarGetNLocksDownType(var->data.multaggr.vars[i], locktype); 3334 else 3335 nlocks += SCIPvarGetNLocksUpType(var->data.multaggr.vars[i], locktype); 3336 } 3337 return nlocks; 3338 3339 case SCIP_VARSTATUS_NEGATED: 3340 assert(var->negatedvar != NULL); 3341 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 3342 assert(var->negatedvar->negatedvar == var); 3343 return SCIPvarGetNLocksUpType(var->negatedvar, locktype); 3344 3345 default: 3346 SCIPerrorMessage("unknown variable status\n"); 3347 SCIPABORT(); 3348 return INT_MAX; /*lint !e527*/ 3349 } 3350 } 3351 3352 /** gets number of locks for rounding up of a special type */ 3353 int SCIPvarGetNLocksUpType( 3354 SCIP_VAR* var, /**< problem variable */ 3355 SCIP_LOCKTYPE locktype /**< type of variable locks */ 3356 ) 3357 { 3358 int nlocks; 3359 int i; 3360 3361 assert(var != NULL); 3362 assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/ 3363 assert(var->nlocksup[locktype] >= 0); 3364 3365 switch( SCIPvarGetStatus(var) ) 3366 { 3367 case SCIP_VARSTATUS_ORIGINAL: 3368 if( var->data.original.transvar != NULL ) 3369 return SCIPvarGetNLocksUpType(var->data.original.transvar, locktype); 3370 else 3371 return var->nlocksup[locktype]; 3372 3373 case SCIP_VARSTATUS_LOOSE: 3374 case SCIP_VARSTATUS_COLUMN: 3375 case SCIP_VARSTATUS_FIXED: 3376 return var->nlocksup[locktype]; 3377 3378 case SCIP_VARSTATUS_AGGREGATED: 3379 assert(!var->donotaggr); 3380 if( var->data.aggregate.scalar > 0.0 ) 3381 return SCIPvarGetNLocksUpType(var->data.aggregate.var, locktype); 3382 else 3383 return SCIPvarGetNLocksDownType(var->data.aggregate.var, locktype); 3384 3385 case SCIP_VARSTATUS_MULTAGGR: 3386 assert(!var->donotmultaggr); 3387 nlocks = 0; 3388 for( i = 0; i < var->data.multaggr.nvars; ++i ) 3389 { 3390 if( var->data.multaggr.scalars[i] > 0.0 ) 3391 nlocks += SCIPvarGetNLocksUpType(var->data.multaggr.vars[i], locktype); 3392 else 3393 nlocks += SCIPvarGetNLocksDownType(var->data.multaggr.vars[i], locktype); 3394 } 3395 return nlocks; 3396 3397 case SCIP_VARSTATUS_NEGATED: 3398 assert(var->negatedvar != NULL); 3399 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 3400 assert(var->negatedvar->negatedvar == var); 3401 return SCIPvarGetNLocksDownType(var->negatedvar, locktype); 3402 3403 default: 3404 SCIPerrorMessage("unknown variable status\n"); 3405 SCIPABORT(); 3406 return INT_MAX; /*lint !e527*/ 3407 } 3408 } 3409 3410 /** gets number of locks for rounding down 3411 * 3412 * @note This method will always return variable locks of type model 3413 * 3414 * @note It is recommented to use SCIPvarGetNLocksDownType() 3415 */ 3416 int SCIPvarGetNLocksDown( 3417 SCIP_VAR* var /**< problem variable */ 3418 ) 3419 { 3420 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL); 3421 } 3422 3423 /** gets number of locks for rounding up 3424 * 3425 * @note This method will always return variable locks of type model 3426 * 3427 * @note It is recommented to use SCIPvarGetNLocksUpType() 3428 */ 3429 int SCIPvarGetNLocksUp( 3430 SCIP_VAR* var /**< problem variable */ 3431 ) 3432 { 3433 return SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL); 3434 } 3435 3436 /** is it possible, to round variable down and stay feasible? 3437 * 3438 * @note This method will always check w.r.t variable locks of type model 3439 */ 3440 SCIP_Bool SCIPvarMayRoundDown( 3441 SCIP_VAR* var /**< problem variable */ 3442 ) 3443 { 3444 return (SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == 0); 3445 } 3446 3447 /** is it possible, to round variable up and stay feasible? 3448 * 3449 * @note This method will always check w.r.t. variable locks of type model 3450 */ 3451 SCIP_Bool SCIPvarMayRoundUp( 3452 SCIP_VAR* var /**< problem variable */ 3453 ) 3454 { 3455 return (SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == 0); 3456 } 3457 3458 /** gets and captures transformed variable of a given variable; if the variable is not yet transformed, 3459 * a new transformed variable for this variable is created 3460 */ 3461 SCIP_RETCODE SCIPvarTransform( 3462 SCIP_VAR* origvar, /**< original problem variable */ 3463 BMS_BLKMEM* blkmem, /**< block memory of transformed problem */ 3464 SCIP_SET* set, /**< global SCIP settings */ 3465 SCIP_STAT* stat, /**< problem statistics */ 3466 SCIP_OBJSENSE objsense, /**< objective sense of original problem; transformed is always MINIMIZE */ 3467 SCIP_VAR** transvar /**< pointer to store the transformed variable */ 3468 ) 3469 { 3470 char name[SCIP_MAXSTRLEN]; 3471 3472 assert(origvar != NULL); 3473 assert(origvar->scip == set->scip); 3474 assert(SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_ORIGINAL); 3475 assert(SCIPsetIsEQ(set, origvar->glbdom.lb, origvar->locdom.lb)); 3476 assert(SCIPsetIsEQ(set, origvar->glbdom.ub, origvar->locdom.ub)); 3477 assert(origvar->vlbs == NULL); 3478 assert(origvar->vubs == NULL); 3479 assert(transvar != NULL); 3480 3481 /* check if variable is already transformed */ 3482 if( origvar->data.original.transvar != NULL ) 3483 { 3484 *transvar = origvar->data.original.transvar; 3485 SCIPvarCapture(*transvar); 3486 } 3487 else 3488 { 3489 int i; 3490 3491 /* create transformed variable */ 3492 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "t_%s", origvar->name); 3493 SCIP_CALL( SCIPvarCreateTransformed(transvar, blkmem, set, stat, name, 3494 origvar->glbdom.lb, origvar->glbdom.ub, (SCIP_Real)objsense * origvar->obj, 3495 SCIPvarGetType(origvar), origvar->initial, origvar->removable, 3496 origvar->vardelorig, origvar->vartrans, origvar->vardeltrans, origvar->varcopy, NULL) ); 3497 3498 /* copy the branch factor and priority */ 3499 (*transvar)->branchfactor = origvar->branchfactor; 3500 (*transvar)->branchpriority = origvar->branchpriority; 3501 (*transvar)->branchdirection = origvar->branchdirection; /*lint !e732*/ 3502 3503 /* duplicate hole lists */ 3504 SCIP_CALL( holelistDuplicate(&(*transvar)->glbdom.holelist, blkmem, set, origvar->glbdom.holelist) ); 3505 SCIP_CALL( holelistDuplicate(&(*transvar)->locdom.holelist, blkmem, set, origvar->locdom.holelist) ); 3506 3507 /* link original and transformed variable */ 3508 origvar->data.original.transvar = *transvar; 3509 SCIP_CALL( varAddParent(*transvar, blkmem, set, origvar) ); 3510 3511 /* copy rounding locks */ 3512 for( i = 0; i < NLOCKTYPES; i++ ) 3513 { 3514 (*transvar)->nlocksdown[i] = origvar->nlocksdown[i]; 3515 (*transvar)->nlocksup[i] = origvar->nlocksup[i]; 3516 assert((*transvar)->nlocksdown[i] >= 0); 3517 assert((*transvar)->nlocksup[i] >= 0); 3518 } 3519 3520 /* copy donot(mult)aggr status */ 3521 (*transvar)->donotaggr = origvar->donotaggr; 3522 (*transvar)->donotmultaggr = origvar->donotmultaggr; 3523 3524 /* copy lazy bounds */ 3525 (*transvar)->lazylb = origvar->lazylb; 3526 (*transvar)->lazyub = origvar->lazyub; 3527 3528 /* transfer eventual variable statistics; do not update global statistics, because this has been done 3529 * when original variable was created 3530 */ 3531 SCIPhistoryUnite((*transvar)->history, origvar->history, FALSE); 3532 3533 /* transform user data */ 3534 if( origvar->vartrans != NULL ) 3535 { 3536 SCIP_CALL( origvar->vartrans(set->scip, origvar, origvar->vardata, *transvar, &(*transvar)->vardata) ); 3537 } 3538 else 3539 (*transvar)->vardata = origvar->vardata; 3540 } 3541 3542 SCIPsetDebugMsg(set, "transformed variable: <%s>[%p] -> <%s>[%p]\n", origvar->name, (void*)origvar, (*transvar)->name, (void*)*transvar); 3543 3544 return SCIP_OKAY; 3545 } 3546 3547 /** gets corresponding transformed variable of an original or negated original variable */ 3548 SCIP_RETCODE SCIPvarGetTransformed( 3549 SCIP_VAR* origvar, /**< original problem variable */ 3550 BMS_BLKMEM* blkmem, /**< block memory of transformed problem */ 3551 SCIP_SET* set, /**< global SCIP settings */ 3552 SCIP_STAT* stat, /**< problem statistics */ 3553 SCIP_VAR** transvar /**< pointer to store the transformed variable, or NULL if not existing yet */ 3554 ) 3555 { 3556 assert(origvar != NULL); 3557 assert(SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_NEGATED); 3558 assert(origvar->scip == set->scip); 3559 3560 if( SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_NEGATED ) 3561 { 3562 assert(origvar->negatedvar != NULL); 3563 assert(SCIPvarGetStatus(origvar->negatedvar) == SCIP_VARSTATUS_ORIGINAL); 3564 3565 if( origvar->negatedvar->data.original.transvar == NULL ) 3566 *transvar = NULL; 3567 else 3568 { 3569 SCIP_CALL( SCIPvarNegate(origvar->negatedvar->data.original.transvar, blkmem, set, stat, transvar) ); 3570 } 3571 } 3572 else 3573 *transvar = origvar->data.original.transvar; 3574 3575 return SCIP_OKAY; 3576 } 3577 3578 /** converts loose transformed variable into column variable, creates LP column */ 3579 SCIP_RETCODE SCIPvarColumn( 3580 SCIP_VAR* var, /**< problem variable */ 3581 BMS_BLKMEM* blkmem, /**< block memory */ 3582 SCIP_SET* set, /**< global SCIP settings */ 3583 SCIP_STAT* stat, /**< problem statistics */ 3584 SCIP_PROB* prob, /**< problem data */ 3585 SCIP_LP* lp /**< current LP data */ 3586 ) 3587 { 3588 assert(var != NULL); 3589 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); 3590 assert(var->scip == set->scip); 3591 3592 SCIPsetDebugMsg(set, "creating column for variable <%s>\n", var->name); 3593 3594 /* switch variable status */ 3595 var->varstatus = SCIP_VARSTATUS_COLUMN; /*lint !e641*/ 3596 3597 /* create column of variable */ 3598 SCIP_CALL( SCIPcolCreate(&var->data.col, blkmem, set, stat, var, 0, NULL, NULL, var->removable) ); 3599 3600 if( var->probindex != -1 ) 3601 { 3602 /* inform problem about the variable's status change */ 3603 SCIP_CALL( SCIPprobVarChangedStatus(prob, blkmem, set, NULL, NULL, var) ); 3604 3605 /* inform LP, that problem variable is now a column variable and no longer loose */ 3606 SCIP_CALL( SCIPlpUpdateVarColumn(lp, set, var) ); 3607 } 3608 3609 return SCIP_OKAY; 3610 } 3611 3612 /** converts column transformed variable back into loose variable, frees LP column */ 3613 SCIP_RETCODE SCIPvarLoose( 3614 SCIP_VAR* var, /**< problem variable */ 3615 BMS_BLKMEM* blkmem, /**< block memory */ 3616 SCIP_SET* set, /**< global SCIP settings */ 3617 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 3618 SCIP_PROB* prob, /**< problem data */ 3619 SCIP_LP* lp /**< current LP data */ 3620 ) 3621 { 3622 assert(var != NULL); 3623 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 3624 assert(var->scip == set->scip); 3625 assert(var->data.col != NULL); 3626 assert(var->data.col->lppos == -1); 3627 assert(var->data.col->lpipos == -1); 3628 3629 SCIPsetDebugMsg(set, "deleting column for variable <%s>\n", var->name); 3630 3631 /* free column of variable */ 3632 SCIP_CALL( SCIPcolFree(&var->data.col, blkmem, set, eventqueue, lp) ); 3633 3634 /* switch variable status */ 3635 var->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/ 3636 3637 if( var->probindex != -1 ) 3638 { 3639 /* inform problem about the variable's status change */ 3640 SCIP_CALL( SCIPprobVarChangedStatus(prob, blkmem, set, NULL, NULL, var) ); 3641 3642 /* inform LP, that problem variable is now a loose variable and no longer a column */ 3643 SCIP_CALL( SCIPlpUpdateVarLoose(lp, set, var) ); 3644 } 3645 3646 return SCIP_OKAY; 3647 } 3648 3649 /** issues a VARFIXED event on the given variable and all its parents (except ORIGINAL parents); 3650 * the event issuing on the parents is necessary, because unlike with bound changes, the parent variables 3651 * are not informed about a fixing of an active variable they are pointing to 3652 */ 3653 static 3654 SCIP_RETCODE varEventVarFixed( 3655 SCIP_VAR* var, /**< problem variable to change */ 3656 BMS_BLKMEM* blkmem, /**< block memory */ 3657 SCIP_SET* set, /**< global SCIP settings */ 3658 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 3659 int fixeventtype /**< is this event a fixation(0), an aggregation(1), or a 3660 * multi-aggregation(2) 3661 */ 3662 ) 3663 { 3664 SCIP_EVENT* event; 3665 SCIP_VARSTATUS varstatus; 3666 int i; 3667 3668 assert(var != NULL); 3669 assert(var->scip == set->scip); 3670 assert(0 <= fixeventtype && fixeventtype <= 2); 3671 3672 /* issue VARFIXED event on variable */ 3673 SCIP_CALL( SCIPeventCreateVarFixed(&event, blkmem, var) ); 3674 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) ); 3675 3676 #ifndef NDEBUG 3677 for( i = var->nparentvars -1; i >= 0; --i ) 3678 { 3679 assert(SCIPvarGetStatus(var->parentvars[i]) != SCIP_VARSTATUS_MULTAGGR); 3680 } 3681 #endif 3682 3683 switch( fixeventtype ) 3684 { 3685 case 0: 3686 /* process all parents of a fixed variable */ 3687 for( i = var->nparentvars - 1; i >= 0; --i ) 3688 { 3689 varstatus = SCIPvarGetStatus(var->parentvars[i]); 3690 3691 assert(varstatus != SCIP_VARSTATUS_FIXED); 3692 3693 /* issue event on all not yet fixed parent variables, (that should already issued this event) except the original 3694 * one 3695 */ 3696 if( varstatus != SCIP_VARSTATUS_ORIGINAL ) 3697 { 3698 SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) ); 3699 } 3700 } 3701 break; 3702 case 1: 3703 /* process all parents of a aggregated variable */ 3704 for( i = var->nparentvars - 1; i >= 0; --i ) 3705 { 3706 varstatus = SCIPvarGetStatus(var->parentvars[i]); 3707 3708 assert(varstatus != SCIP_VARSTATUS_FIXED); 3709 3710 /* issue event for not aggregated parent variable, because for these and its parents the var event was already 3711 * issued(, except the original one) 3712 * 3713 * @note that even before an aggregated parent variable, there might be variables, for which the vent was not 3714 * yet issued 3715 */ 3716 if( varstatus == SCIP_VARSTATUS_AGGREGATED ) 3717 continue; 3718 3719 if( varstatus != SCIP_VARSTATUS_ORIGINAL ) 3720 { 3721 SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) ); 3722 } 3723 } 3724 break; 3725 case 2: 3726 /* process all parents of a aggregated variable */ 3727 for( i = var->nparentvars - 1; i >= 0; --i ) 3728 { 3729 varstatus = SCIPvarGetStatus(var->parentvars[i]); 3730 3731 assert(varstatus != SCIP_VARSTATUS_FIXED); 3732 3733 /* issue event on all parent variables except the original one */ 3734 if( varstatus != SCIP_VARSTATUS_ORIGINAL ) 3735 { 3736 SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) ); 3737 } 3738 } 3739 break; 3740 default: 3741 SCIPerrorMessage("unknown variable fixation event origin\n"); 3742 return SCIP_INVALIDDATA; 3743 } 3744 3745 return SCIP_OKAY; 3746 } 3747 3748 /** converts variable into fixed variable */ 3749 SCIP_RETCODE SCIPvarFix( 3750 SCIP_VAR* var, /**< problem variable */ 3751 BMS_BLKMEM* blkmem, /**< block memory */ 3752 SCIP_SET* set, /**< global SCIP settings */ 3753 SCIP_STAT* stat, /**< problem statistics */ 3754 SCIP_PROB* transprob, /**< tranformed problem data */ 3755 SCIP_PROB* origprob, /**< original problem data */ 3756 SCIP_PRIMAL* primal, /**< primal data */ 3757 SCIP_TREE* tree, /**< branch and bound tree */ 3758 SCIP_REOPT* reopt, /**< reoptimization data structure */ 3759 SCIP_LP* lp, /**< current LP data */ 3760 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 3761 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 3762 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 3763 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 3764 SCIP_Real fixedval, /**< value to fix variable at */ 3765 SCIP_Bool* infeasible, /**< pointer to store whether the fixing is infeasible */ 3766 SCIP_Bool* fixed /**< pointer to store whether the fixing was performed (variable was unfixed) */ 3767 ) 3768 { 3769 SCIP_Real obj; 3770 SCIP_Real childfixedval; 3771 3772 assert(var != NULL); 3773 assert(var->scip == set->scip); 3774 assert(SCIPsetIsEQ(set, var->glbdom.lb, var->locdom.lb)); 3775 assert(SCIPsetIsEQ(set, var->glbdom.ub, var->locdom.ub)); 3776 assert(infeasible != NULL); 3777 assert(fixed != NULL); 3778 3779 SCIPsetDebugMsg(set, "fix variable <%s>[%g,%g] to %g\n", var->name, var->glbdom.lb, var->glbdom.ub, fixedval); 3780 3781 *infeasible = FALSE; 3782 *fixed = FALSE; 3783 3784 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED ) 3785 { 3786 *infeasible = !SCIPsetIsFeasEQ(set, fixedval, var->locdom.lb); 3787 SCIPsetDebugMsg(set, " -> variable already fixed to %g (fixedval=%g): infeasible=%u\n", var->locdom.lb, fixedval, *infeasible); 3788 return SCIP_OKAY; 3789 } 3790 else if( (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !SCIPsetIsFeasIntegral(set, fixedval)) 3791 || SCIPsetIsFeasLT(set, fixedval, var->locdom.lb) 3792 || SCIPsetIsFeasGT(set, fixedval, var->locdom.ub) ) 3793 { 3794 SCIPsetDebugMsg(set, " -> fixing infeasible: locdom=[%g,%g], fixedval=%g\n", var->locdom.lb, var->locdom.ub, fixedval); 3795 *infeasible = TRUE; 3796 return SCIP_OKAY; 3797 } 3798 3799 switch( SCIPvarGetStatus(var) ) 3800 { 3801 case SCIP_VARSTATUS_ORIGINAL: 3802 if( var->data.original.transvar == NULL ) 3803 { 3804 SCIPerrorMessage("cannot fix an untransformed original variable\n"); 3805 return SCIP_INVALIDDATA; 3806 } 3807 SCIP_CALL( SCIPvarFix(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, 3808 lp, branchcand, eventfilter, eventqueue, cliquetable, fixedval, infeasible, fixed) ); 3809 break; 3810 3811 case SCIP_VARSTATUS_LOOSE: 3812 assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */ 3813 3814 /* set the fixed variable's objective value to 0.0 */ 3815 obj = var->obj; 3816 SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) ); 3817 3818 /* since we change the variable type form loose to fixed, we have to adjust the number of loose 3819 * variables in the LP data structure; the loose objective value (looseobjval) in the LP data structure, however, 3820 * gets adjusted automatically, due to the event SCIP_EVENTTYPE_OBJCHANGED which dropped in the moment where the 3821 * objective of this variable is set to zero 3822 */ 3823 SCIPlpDecNLoosevars(lp); 3824 3825 /* change variable's bounds to fixed value (thereby removing redundant implications and variable bounds) */ 3826 holelistFree(&var->glbdom.holelist, blkmem); 3827 holelistFree(&var->locdom.holelist, blkmem); 3828 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, fixedval) ); 3829 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, fixedval) ); 3830 3831 if( var->glbdom.lb != var->glbdom.ub ) /*lint !e777*/ 3832 { 3833 /* explicitly set variable's bounds if the fixed value was in epsilon range of the old bound (so above call didn't set bound) */ 3834 if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS ) 3835 { 3836 /* if not continuous variable, then make sure variable is fixed to integer value */ 3837 assert(SCIPsetIsIntegral(set, fixedval)); 3838 fixedval = SCIPsetRound(set, fixedval); 3839 } 3840 var->glbdom.lb = fixedval; 3841 var->glbdom.ub = fixedval; 3842 } 3843 3844 /* ensure local domain is fixed to same value as global domain */ 3845 var->locdom.lb = var->glbdom.lb; 3846 var->locdom.ub = var->glbdom.ub; 3847 3848 /* delete implications and variable bounds information */ 3849 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) ); 3850 assert(var->vlbs == NULL); 3851 assert(var->vubs == NULL); 3852 assert(var->implics == NULL); 3853 3854 /* clear the history of the variable */ 3855 SCIPhistoryReset(var->history); 3856 SCIPhistoryReset(var->historycrun); 3857 3858 /* convert variable into fixed variable */ 3859 var->varstatus = SCIP_VARSTATUS_FIXED; /*lint !e641*/ 3860 3861 /* inform problem about the variable's status change */ 3862 if( var->probindex != -1 ) 3863 { 3864 SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) ); 3865 } 3866 3867 /* reset the objective value of the fixed variable, thus adjusting the problem's objective offset */ 3868 SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) ); 3869 3870 /* issue VARFIXED event */ 3871 SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 0) ); 3872 3873 *fixed = TRUE; 3874 break; 3875 3876 case SCIP_VARSTATUS_COLUMN: 3877 SCIPerrorMessage("cannot fix a column variable\n"); 3878 return SCIP_INVALIDDATA; 3879 3880 case SCIP_VARSTATUS_FIXED: 3881 SCIPerrorMessage("cannot fix a fixed variable again\n"); /*lint !e527*/ 3882 SCIPABORT(); /* case is already handled in earlier if condition */ 3883 return SCIP_INVALIDDATA; /*lint !e527*/ 3884 3885 case SCIP_VARSTATUS_AGGREGATED: 3886 /* fix aggregation variable y in x = a*y + c, instead of fixing x directly */ 3887 assert(SCIPsetIsZero(set, var->obj)); 3888 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar)); 3889 if( SCIPsetIsInfinity(set, fixedval) || SCIPsetIsInfinity(set, -fixedval) ) 3890 childfixedval = (var->data.aggregate.scalar < 0.0 ? -fixedval : fixedval); 3891 else 3892 childfixedval = (fixedval - var->data.aggregate.constant)/var->data.aggregate.scalar; 3893 SCIP_CALL( SCIPvarFix(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, 3894 branchcand, eventfilter, eventqueue, cliquetable, childfixedval, infeasible, fixed) ); 3895 break; 3896 3897 case SCIP_VARSTATUS_MULTAGGR: 3898 SCIPerrorMessage("cannot fix a multiple aggregated variable\n"); 3899 SCIPABORT(); 3900 return SCIP_INVALIDDATA; /*lint !e527*/ 3901 3902 case SCIP_VARSTATUS_NEGATED: 3903 /* fix negation variable x in x' = offset - x, instead of fixing x' directly */ 3904 assert(SCIPsetIsZero(set, var->obj)); 3905 assert(var->negatedvar != NULL); 3906 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 3907 assert(var->negatedvar->negatedvar == var); 3908 SCIP_CALL( SCIPvarFix(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, 3909 branchcand, eventfilter, eventqueue, cliquetable, var->data.negate.constant - fixedval, infeasible, fixed) ); 3910 break; 3911 3912 default: 3913 SCIPerrorMessage("unknown variable status\n"); 3914 return SCIP_INVALIDDATA; 3915 } 3916 3917 return SCIP_OKAY; 3918 } 3919 3920 /** transforms given variables, scalars and constant to the corresponding active variables, scalars and constant 3921 * 3922 * If the number of needed active variables is greater than the available slots in the variable array, nothing happens except 3923 * that the required size is stored in the corresponding variable; hence, if afterwards the required size is greater than the 3924 * available slots (varssize), nothing happens; otherwise, the active variable representation is stored in the arrays. 3925 * 3926 * The reason for this approach is that we cannot reallocate memory, since we do not know how the 3927 * memory has been allocated (e.g., by a C++ 'new' or SCIP functions). 3928 */ 3929 SCIP_RETCODE SCIPvarGetActiveRepresentatives( 3930 SCIP_SET* set, /**< global SCIP settings */ 3931 SCIP_VAR** vars, /**< variable array to get active variables */ 3932 SCIP_Real* scalars, /**< scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */ 3933 int* nvars, /**< pointer to number of variables and values in vars and scalars array */ 3934 int varssize, /**< available slots in vars and scalars array */ 3935 SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */ 3936 int* requiredsize, /**< pointer to store the required array size for the active variables */ 3937 SCIP_Bool mergemultiples /**< should multiple occurrences of a var be replaced by a single coeff? */ 3938 ) 3939 { 3940 SCIP_VAR** activevars; 3941 SCIP_Real* activescalars; 3942 int nactivevars; 3943 SCIP_Real activeconstant; 3944 SCIP_Bool activeconstantinf; 3945 int activevarssize; 3946 3947 SCIP_VAR* var; 3948 SCIP_Real scalar; 3949 int v; 3950 int k; 3951 3952 SCIP_VAR** tmpvars; 3953 SCIP_VAR** multvars; 3954 SCIP_Real* tmpscalars; 3955 SCIP_Real* multscalars; 3956 int tmpvarssize; 3957 int ntmpvars; 3958 int nmultvars; 3959 3960 SCIP_VAR* multvar; 3961 SCIP_Real multscalar; 3962 SCIP_Real multconstant; 3963 int pos; 3964 3965 int noldtmpvars; 3966 3967 SCIP_VAR** tmpvars2; 3968 SCIP_Real* tmpscalars2; 3969 int tmpvarssize2; 3970 int ntmpvars2; 3971 3972 SCIP_Bool sortagain = FALSE; 3973 3974 assert(set != NULL); 3975 assert(nvars != NULL); 3976 assert(scalars != NULL || *nvars == 0); 3977 assert(constant != NULL); 3978 assert(requiredsize != NULL); 3979 assert(*nvars <= varssize); 3980 3981 *requiredsize = 0; 3982 3983 if( *nvars == 0 ) 3984 return SCIP_OKAY; 3985 3986 assert(vars != NULL); 3987 3988 /* handle the "easy" case of just one variable and avoid memory allocation if the variable is already active */ 3989 if( *nvars == 1 && (vars[0]->varstatus == ((int) SCIP_VARSTATUS_COLUMN) || vars[0]->varstatus == ((int) SCIP_VARSTATUS_LOOSE)) ) 3990 { 3991 *requiredsize = 1; 3992 3993 return SCIP_OKAY; 3994 } 3995 3996 nactivevars = 0; 3997 activeconstant = 0.0; 3998 activeconstantinf = FALSE; 3999 activevarssize = (*nvars) * 2; 4000 ntmpvars = *nvars; 4001 tmpvarssize = *nvars; 4002 4003 tmpvarssize2 = 1; 4004 4005 /* allocate temporary memory */ 4006 SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpvars2, tmpvarssize2) ); 4007 SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpscalars2, tmpvarssize2) ); 4008 SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) ); 4009 SCIP_CALL( SCIPsetAllocBufferArray(set, &activescalars, activevarssize) ); 4010 SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) ); 4011 SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpscalars, scalars, ntmpvars) ); 4012 4013 /* to avoid unnecessary expanding of variable arrays while disaggregating several variables multiple times combine same variables 4014 * first, first get all corresponding variables with status loose, column, multaggr or fixed 4015 */ 4016 for( v = ntmpvars - 1; v >= 0; --v ) 4017 { 4018 var = tmpvars[v]; 4019 scalar = tmpscalars[v]; 4020 4021 assert(var != NULL); 4022 /* transforms given variable, scalar and constant to the corresponding active, fixed, or 4023 * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed 4024 * variable, "scalar" will be 0.0 and the value of the sum will be stored in "constant". 4025 */ 4026 SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &activeconstant) ); 4027 assert(var != NULL); 4028 4029 assert(SCIPsetIsInfinity(set, activeconstant) == (activeconstant == SCIPsetInfinity(set))); /*lint !e777*/ 4030 assert(SCIPsetIsInfinity(set, -activeconstant) == (activeconstant == -SCIPsetInfinity(set))); /*lint !e777*/ 4031 4032 activeconstantinf = SCIPsetIsInfinity(set, activeconstant) || SCIPsetIsInfinity(set, -activeconstant); 4033 4034 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE 4035 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN 4036 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR 4037 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED); 4038 4039 tmpvars[v] = var; 4040 tmpscalars[v] = scalar; 4041 } 4042 noldtmpvars = ntmpvars; 4043 4044 /* sort all variables to combine equal variables easily */ 4045 SCIPsortPtrReal((void**)tmpvars, tmpscalars, SCIPvarComp, noldtmpvars); 4046 ntmpvars = 0; 4047 for( v = 1; v < noldtmpvars; ++v ) 4048 { 4049 /* combine same variables */ 4050 if( SCIPvarCompare(tmpvars[v], tmpvars[ntmpvars]) == 0 ) 4051 { 4052 tmpscalars[ntmpvars] += tmpscalars[v]; 4053 } 4054 else 4055 { 4056 ++ntmpvars; 4057 if( v > ntmpvars ) 4058 { 4059 tmpscalars[ntmpvars] = tmpscalars[v]; 4060 tmpvars[ntmpvars] = tmpvars[v]; 4061 } 4062 } 4063 } 4064 ++ntmpvars; 4065 4066 #ifdef SCIP_MORE_DEBUG 4067 for( v = 1; v < ntmpvars; ++v ) 4068 assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0); 4069 #endif 4070 4071 /* collect for each variable the representation in active variables */ 4072 while( ntmpvars >= 1 ) 4073 { 4074 --ntmpvars; 4075 ntmpvars2 = 0; 4076 var = tmpvars[ntmpvars]; 4077 scalar = tmpscalars[ntmpvars]; 4078 4079 assert(var != NULL); 4080 4081 /* TODO: maybe we should test here on SCIPsetIsZero() instead of 0.0 */ 4082 if( scalar == 0.0 ) 4083 continue; 4084 4085 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE 4086 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN 4087 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR 4088 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED); 4089 4090 switch( SCIPvarGetStatus(var) ) 4091 { 4092 case SCIP_VARSTATUS_LOOSE: 4093 case SCIP_VARSTATUS_COLUMN: 4094 /* x = a*y + c */ 4095 if( nactivevars >= activevarssize ) 4096 { 4097 activevarssize *= 2; 4098 SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) ); 4099 SCIP_CALL( SCIPsetReallocBufferArray(set, &activescalars, activevarssize) ); 4100 assert(nactivevars < activevarssize); 4101 } 4102 activevars[nactivevars] = var; 4103 activescalars[nactivevars] = scalar; 4104 nactivevars++; 4105 break; 4106 4107 case SCIP_VARSTATUS_MULTAGGR: 4108 /* x = a_1*y_1 + ... + a_n*y_n + c */ 4109 nmultvars = var->data.multaggr.nvars; 4110 multvars = var->data.multaggr.vars; 4111 multscalars = var->data.multaggr.scalars; 4112 sortagain = TRUE; 4113 4114 if( nmultvars + ntmpvars > tmpvarssize ) 4115 { 4116 while( nmultvars + ntmpvars > tmpvarssize ) 4117 tmpvarssize *= 2; 4118 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) ); 4119 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars, tmpvarssize) ); 4120 assert(nmultvars + ntmpvars <= tmpvarssize); 4121 } 4122 4123 if( nmultvars > tmpvarssize2 ) 4124 { 4125 while( nmultvars > tmpvarssize2 ) 4126 tmpvarssize2 *= 2; 4127 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars2, tmpvarssize2) ); 4128 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars2, tmpvarssize2) ); 4129 assert(nmultvars <= tmpvarssize2); 4130 } 4131 4132 --nmultvars; 4133 4134 for( ; nmultvars >= 0; --nmultvars ) 4135 { 4136 multvar = multvars[nmultvars]; 4137 multscalar = multscalars[nmultvars]; 4138 multconstant = 0; 4139 4140 assert(multvar != NULL); 4141 SCIP_CALL( SCIPvarGetProbvarSum(&multvar, set, &multscalar, &multconstant) ); 4142 assert(multvar != NULL); 4143 4144 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE 4145 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN 4146 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR 4147 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED); 4148 4149 if( !activeconstantinf ) 4150 { 4151 assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar)); 4152 4153 if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) ) 4154 { 4155 assert(scalar != 0.0); 4156 if( scalar * multconstant > 0.0 ) 4157 { 4158 activeconstant = SCIPsetInfinity(set); 4159 activeconstantinf = TRUE; 4160 } 4161 else 4162 { 4163 activeconstant = -SCIPsetInfinity(set); 4164 activeconstantinf = TRUE; 4165 } 4166 } 4167 else 4168 activeconstant += scalar * multconstant; 4169 } 4170 #ifndef NDEBUG 4171 else 4172 { 4173 assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 && 4174 (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant)))); 4175 assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 && 4176 (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant)))); 4177 } 4178 #endif 4179 4180 if( SCIPsortedvecFindPtr((void**)tmpvars, SCIPvarComp, multvar, ntmpvars, &pos) ) 4181 { 4182 assert(SCIPvarCompare(tmpvars[pos], multvar) == 0); 4183 tmpscalars[pos] += scalar * multscalar; 4184 } 4185 else 4186 { 4187 tmpvars2[ntmpvars2] = multvar; 4188 tmpscalars2[ntmpvars2] = scalar * multscalar; 4189 ++(ntmpvars2); 4190 assert(ntmpvars2 <= tmpvarssize2); 4191 } 4192 } 4193 4194 if( ntmpvars2 > 0 ) 4195 { 4196 /* sort all variables to combine equal variables easily */ 4197 SCIPsortPtrReal((void**)tmpvars2, tmpscalars2, SCIPvarComp, ntmpvars2); 4198 pos = 0; 4199 for( v = 1; v < ntmpvars2; ++v ) 4200 { 4201 /* combine same variables */ 4202 if( SCIPvarCompare(tmpvars2[v], tmpvars2[pos]) == 0 ) 4203 { 4204 tmpscalars2[pos] += tmpscalars2[v]; 4205 } 4206 else 4207 { 4208 ++pos; 4209 if( v > pos ) 4210 { 4211 tmpscalars2[pos] = tmpscalars2[v]; 4212 tmpvars2[pos] = tmpvars2[v]; 4213 } 4214 } 4215 } 4216 ntmpvars2 = pos + 1; 4217 #ifdef SCIP_MORE_DEBUG 4218 for( v = 1; v < ntmpvars2; ++v ) 4219 { 4220 assert(SCIPvarCompare(tmpvars2[v], tmpvars2[v-1]) > 0); 4221 } 4222 for( v = 1; v < ntmpvars; ++v ) 4223 { 4224 assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0); 4225 } 4226 #endif 4227 v = ntmpvars - 1; 4228 k = ntmpvars2 - 1; 4229 pos = ntmpvars + ntmpvars2 - 1; 4230 ntmpvars += ntmpvars2; 4231 4232 while( v >= 0 && k >= 0 ) 4233 { 4234 assert(pos >= 0); 4235 assert(SCIPvarCompare(tmpvars[v], tmpvars2[k]) != 0); 4236 if( SCIPvarCompare(tmpvars[v], tmpvars2[k]) >= 0 ) 4237 { 4238 tmpvars[pos] = tmpvars[v]; 4239 tmpscalars[pos] = tmpscalars[v]; 4240 --v; 4241 } 4242 else 4243 { 4244 tmpvars[pos] = tmpvars2[k]; 4245 tmpscalars[pos] = tmpscalars2[k]; 4246 --k; 4247 } 4248 --pos; 4249 assert(pos >= 0); 4250 } 4251 while( v >= 0 ) 4252 { 4253 assert(pos >= 0); 4254 tmpvars[pos] = tmpvars[v]; 4255 tmpscalars[pos] = tmpscalars[v]; 4256 --v; 4257 --pos; 4258 } 4259 while( k >= 0 ) 4260 { 4261 assert(pos >= 0); 4262 tmpvars[pos] = tmpvars2[k]; 4263 tmpscalars[pos] = tmpscalars2[k]; 4264 --k; 4265 --pos; 4266 } 4267 } 4268 #ifdef SCIP_MORE_DEBUG 4269 for( v = 1; v < ntmpvars; ++v ) 4270 { 4271 assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0); 4272 } 4273 #endif 4274 4275 if( !activeconstantinf ) 4276 { 4277 assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar)); 4278 4279 multconstant = SCIPvarGetMultaggrConstant(var); 4280 4281 if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) ) 4282 { 4283 assert(scalar != 0.0); 4284 if( scalar * multconstant > 0.0 ) 4285 { 4286 activeconstant = SCIPsetInfinity(set); 4287 activeconstantinf = TRUE; 4288 } 4289 else 4290 { 4291 activeconstant = -SCIPsetInfinity(set); 4292 activeconstantinf = TRUE; 4293 } 4294 } 4295 else 4296 activeconstant += scalar * multconstant; 4297 } 4298 #ifndef NDEBUG 4299 else 4300 { 4301 multconstant = SCIPvarGetMultaggrConstant(var); 4302 assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 && 4303 (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant)))); 4304 assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 && 4305 (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant)))); 4306 } 4307 #endif 4308 break; 4309 4310 case SCIP_VARSTATUS_FIXED: 4311 case SCIP_VARSTATUS_ORIGINAL: 4312 case SCIP_VARSTATUS_AGGREGATED: 4313 case SCIP_VARSTATUS_NEGATED: 4314 default: 4315 /* case x = c, but actually we should not be here, since SCIPvarGetProbvarSum() returns a scalar of 0.0 for 4316 * fixed variables and is handled already 4317 */ 4318 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED); 4319 assert(SCIPsetIsZero(set, var->glbdom.lb) && SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub)); 4320 } 4321 } 4322 4323 if( mergemultiples ) 4324 { 4325 if( sortagain ) 4326 { 4327 /* sort variable and scalar array by variable index */ 4328 SCIPsortPtrReal((void**)activevars, activescalars, SCIPvarComp, nactivevars); 4329 4330 /* eliminate duplicates and count required size */ 4331 v = nactivevars - 1; 4332 while( v > 0 ) 4333 { 4334 /* combine both variable since they are the same */ 4335 if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 ) 4336 { 4337 if( activescalars[v - 1] + activescalars[v] != 0.0 ) 4338 { 4339 activescalars[v - 1] += activescalars[v]; 4340 --nactivevars; 4341 activevars[v] = activevars[nactivevars]; 4342 activescalars[v] = activescalars[nactivevars]; 4343 } 4344 else 4345 { 4346 --nactivevars; 4347 activevars[v] = activevars[nactivevars]; 4348 activescalars[v] = activescalars[nactivevars]; 4349 --nactivevars; 4350 --v; 4351 activevars[v] = activevars[nactivevars]; 4352 activescalars[v] = activescalars[nactivevars]; 4353 } 4354 } 4355 --v; 4356 } 4357 } 4358 /* the variables were added in reverse order, we revert the order now; 4359 * this should not be necessary, but not doing this changes the behavior sometimes 4360 */ 4361 else 4362 { 4363 SCIP_VAR* tmpvar; 4364 SCIP_Real tmpscalar; 4365 4366 for( v = 0; v < nactivevars / 2; ++v ) 4367 { 4368 tmpvar = activevars[v]; 4369 tmpscalar = activescalars[v]; 4370 activevars[v] = activevars[nactivevars - 1 - v]; 4371 activescalars[v] = activescalars[nactivevars - 1 - v]; 4372 activevars[nactivevars - 1 - v] = tmpvar; 4373 activescalars[nactivevars - 1 - v] = tmpscalar; 4374 } 4375 } 4376 } 4377 *requiredsize = nactivevars; 4378 4379 if( varssize >= *requiredsize ) 4380 { 4381 assert(vars != NULL); 4382 4383 *nvars = *requiredsize; 4384 4385 if( !SCIPsetIsInfinity(set, *constant) && !SCIPsetIsInfinity(set, -(*constant)) ) 4386 { 4387 /* if the activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */ 4388 if( activeconstantinf ) 4389 (*constant) = activeconstant; 4390 else 4391 (*constant) += activeconstant; 4392 } 4393 #ifndef NDEBUG 4394 else 4395 { 4396 assert(!SCIPsetIsInfinity(set, (*constant)) || !SCIPsetIsInfinity(set, -activeconstant)); 4397 assert(!SCIPsetIsInfinity(set, -(*constant)) || !SCIPsetIsInfinity(set, activeconstant)); 4398 } 4399 #endif 4400 4401 /* copy active variable and scalar array to the given arrays */ 4402 for( v = 0; v < *nvars; ++v ) 4403 { 4404 vars[v] = activevars[v]; 4405 scalars[v] = activescalars[v]; /*lint !e613*/ 4406 } 4407 } 4408 4409 assert(SCIPsetIsInfinity(set, *constant) == ((*constant) == SCIPsetInfinity(set))); /*lint !e777*/ 4410 assert(SCIPsetIsInfinity(set, -(*constant)) == ((*constant) == -SCIPsetInfinity(set))); /*lint !e777*/ 4411 4412 SCIPsetFreeBufferArray(set, &tmpscalars); 4413 SCIPsetFreeBufferArray(set, &tmpvars); 4414 SCIPsetFreeBufferArray(set, &activescalars); 4415 SCIPsetFreeBufferArray(set, &activevars); 4416 SCIPsetFreeBufferArray(set, &tmpscalars2); 4417 SCIPsetFreeBufferArray(set, &tmpvars2); 4418 4419 return SCIP_OKAY; 4420 } 4421 4422 4423 /** flattens aggregation graph of multi-aggregated variable in order to avoid exponential recursion later on */ 4424 SCIP_RETCODE SCIPvarFlattenAggregationGraph( 4425 SCIP_VAR* var, /**< problem variable */ 4426 BMS_BLKMEM* blkmem, /**< block memory */ 4427 SCIP_SET* set, /**< global SCIP settings */ 4428 SCIP_EVENTQUEUE* eventqueue /**< event queue */ 4429 ) 4430 { 4431 int nlocksup[NLOCKTYPES]; 4432 int nlocksdown[NLOCKTYPES]; 4433 SCIP_Real multconstant; 4434 int multvarssize; 4435 int nmultvars; 4436 int multrequiredsize; 4437 int i; 4438 4439 assert( var != NULL ); 4440 assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR ); 4441 assert(var->scip == set->scip); 4442 4443 /* in order to update the locks on the active representation of the multi-aggregated variable, we remove all locks 4444 * on the current representation now and re-add the locks once the variable graph has been flattened, which 4445 * may lead to duplicate occurences of the same variable being merged 4446 * 4447 * Here is an example. Assume we have the multi-aggregation z = x + y. 4448 * z occures with positive coefficient in a <= constraint c1, so it has an uplock from there. 4449 * When the multi-aggregation is performed, all locks are added to the active representation, 4450 * so x and y both get an uplock from c1. However, z was not yet replaced by x + y in c1. 4451 * Next, a negation y = 1 - x is identified. Again, locks are moved, so that the uplock of y originating 4452 * from c1 is added to x as a downlock. Thus, x has both an up- and downlock from c1. 4453 * The multi-aggregation changes to z = x + 1 - x, which corresponds to the locks. 4454 * However, before z is replaced by that sum, SCIPvarFlattenAggregationGraph() is called 4455 * which changes z = x + y = x + 1 - x = 1, since it merges multiple occurences of the same variable. 4456 * The up- and downlock of x, however, is not removed when replacing z in c1 by its active representation, 4457 * because it is just 1 now. Therefore, we need to update locks when flattening the aggregation graph. 4458 * For this, the multi-aggregated variable knows its locks in addition to adding them to the active 4459 * representation, which corresponds to the locks from constraints where the variable was not replaced yet. 4460 * By removing the locks here, based on the old representation and adding them again after flattening, 4461 * we ensure that the locks are correct afterwards if coefficients were merged. 4462 */ 4463 for( i = 0; i < NLOCKTYPES; ++i ) 4464 { 4465 nlocksup[i] = var->nlocksup[i]; 4466 nlocksdown[i] = var->nlocksdown[i]; 4467 4468 SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, -nlocksdown[i], -nlocksup[i]) ); 4469 } 4470 4471 multconstant = var->data.multaggr.constant; 4472 nmultvars = var->data.multaggr.nvars; 4473 multvarssize = var->data.multaggr.varssize; 4474 4475 SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) ); 4476 4477 if( multrequiredsize > multvarssize ) 4478 { 4479 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.vars), multvarssize, multrequiredsize) ); 4480 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.scalars), multvarssize, multrequiredsize) ); 4481 multvarssize = multrequiredsize; 4482 SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) ); 4483 assert( multrequiredsize <= multvarssize ); 4484 } 4485 /**@note After the flattening the multi aggregation might resolve to be in fact an aggregation (or even a fixing?). 4486 * This issue is not resolved right now, since var->data.multaggr.nvars < 2 should not cause troubles. However, one 4487 * may loose performance hereby, since aggregated variables are easier to handle. 4488 * 4489 * Note, that there are two cases where SCIPvarFlattenAggregationGraph() is called: The easier one is that it is 4490 * called while installing the multi-aggregation. in principle, the described issue could be handled straightforward 4491 * in this case by aggregating or fixing the variable instead. The more complicated case is the one, when the 4492 * multi-aggregation is used, e.g., in linear presolving (and the variable is already declared to be multi-aggregated). 4493 * 4494 * By now, it is not allowed to fix or aggregate multi-aggregated variables which would be necessary in this case. 4495 * 4496 * The same issue appears in the SCIPvarGetProbvar...() methods. 4497 */ 4498 4499 var->data.multaggr.constant = multconstant; 4500 var->data.multaggr.nvars = nmultvars; 4501 var->data.multaggr.varssize = multvarssize; 4502 4503 for( i = 0; i < NLOCKTYPES; ++i ) 4504 { 4505 SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) ); 4506 } 4507 4508 return SCIP_OKAY; 4509 } 4510 4511 /** merge two variable histories together; a typical use case is that \p othervar is an image of the target variable 4512 * in a SCIP copy. Method should be applied with care, especially because no internal checks are performed whether 4513 * the history merge is reasonable 4514 * 4515 * @note Do not use this method if the two variables originate from two SCIP's with different objective functions, since 4516 * this corrupts the variable pseudo costs 4517 * @note Apply with care; no internal checks are performed if the two variables should be merged 4518 */ 4519 void SCIPvarMergeHistories( 4520 SCIP_VAR* targetvar, /**< the variable that should contain both histories afterwards */ 4521 SCIP_VAR* othervar, /**< the variable whose history is to be merged with that of the target variable */ 4522 SCIP_STAT* stat /**< problem statistics */ 4523 ) 4524 { 4525 /* merge only the history of the current run into the target history */ 4526 SCIPhistoryUnite(targetvar->history, othervar->historycrun, FALSE); 4527 4528 /* apply the changes also to the global history */ 4529 SCIPhistoryUnite(stat->glbhistory, othervar->historycrun, FALSE); 4530 } 4531 4532 /** sets the history of a variable; this method is typically used within reoptimization to keep and update the variable 4533 * history over several iterations 4534 */ 4535 void SCIPvarSetHistory( 4536 SCIP_VAR* var, /**< variable */ 4537 SCIP_HISTORY* history, /**< the history which is to set */ 4538 SCIP_STAT* stat /**< problem statistics */ 4539 ) 4540 { 4541 /* merge only the history of the current run into the target history */ 4542 SCIPhistoryUnite(var->history, history, FALSE); 4543 4544 /* apply the changes also to the global history */ 4545 SCIPhistoryUnite(stat->glbhistory, history, FALSE); 4546 } 4547 4548 /** tightens the bounds of both variables in aggregation x = a*y + c */ 4549 static 4550 SCIP_RETCODE varUpdateAggregationBounds( 4551 SCIP_VAR* var, /**< problem variable */ 4552 BMS_BLKMEM* blkmem, /**< block memory */ 4553 SCIP_SET* set, /**< global SCIP settings */ 4554 SCIP_STAT* stat, /**< problem statistics */ 4555 SCIP_PROB* transprob, /**< tranformed problem data */ 4556 SCIP_PROB* origprob, /**< original problem data */ 4557 SCIP_PRIMAL* primal, /**< primal data */ 4558 SCIP_TREE* tree, /**< branch and bound tree */ 4559 SCIP_REOPT* reopt, /**< reoptimization data structure */ 4560 SCIP_LP* lp, /**< current LP data */ 4561 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 4562 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 4563 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 4564 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 4565 SCIP_VAR* aggvar, /**< variable y in aggregation x = a*y + c */ 4566 SCIP_Real scalar, /**< multiplier a in aggregation x = a*y + c */ 4567 SCIP_Real constant, /**< constant shift c in aggregation x = a*y + c */ 4568 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */ 4569 SCIP_Bool* fixed /**< pointer to store whether the variables were fixed */ 4570 ) 4571 { 4572 SCIP_Real varlb; 4573 SCIP_Real varub; 4574 SCIP_Real aggvarlb; 4575 SCIP_Real aggvarub; 4576 SCIP_Bool aggvarbdschanged; 4577 4578 assert(var != NULL); 4579 assert(var->scip == set->scip); 4580 assert(aggvar != NULL); 4581 assert(!SCIPsetIsZero(set, scalar)); 4582 assert(infeasible != NULL); 4583 assert(fixed != NULL); 4584 4585 *infeasible = FALSE; 4586 *fixed = FALSE; 4587 4588 SCIPsetDebugMsg(set, "updating bounds of variables in aggregation <%s> == %g*<%s> %+g\n", var->name, scalar, aggvar->name, constant); 4589 SCIPsetDebugMsg(set, " old bounds: <%s> [%g,%g] <%s> [%g,%g]\n", 4590 var->name, var->glbdom.lb, var->glbdom.ub, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub); 4591 4592 /* loop as long additional changes may be found */ 4593 do 4594 { 4595 aggvarbdschanged = FALSE; 4596 4597 /* update the bounds of the aggregated variable x in x = a*y + c */ 4598 if( scalar > 0.0 ) 4599 { 4600 if( SCIPsetIsInfinity(set, -aggvar->glbdom.lb) ) 4601 varlb = -SCIPsetInfinity(set); 4602 else 4603 varlb = aggvar->glbdom.lb * scalar + constant; 4604 if( SCIPsetIsInfinity(set, aggvar->glbdom.ub) ) 4605 varub = SCIPsetInfinity(set); 4606 else 4607 varub = aggvar->glbdom.ub * scalar + constant; 4608 } 4609 else 4610 { 4611 if( SCIPsetIsInfinity(set, -aggvar->glbdom.lb) ) 4612 varub = SCIPsetInfinity(set); 4613 else 4614 varub = aggvar->glbdom.lb * scalar + constant; 4615 if( SCIPsetIsInfinity(set, aggvar->glbdom.ub) ) 4616 varlb = -SCIPsetInfinity(set); 4617 else 4618 varlb = aggvar->glbdom.ub * scalar + constant; 4619 } 4620 varlb = MAX(varlb, var->glbdom.lb); 4621 varub = MIN(varub, var->glbdom.ub); 4622 SCIPvarAdjustLb(var, set, &varlb); 4623 SCIPvarAdjustUb(var, set, &varub); 4624 4625 /* check the new bounds */ 4626 if( SCIPsetIsGT(set, varlb, varub) ) 4627 { 4628 /* the aggregation is infeasible */ 4629 *infeasible = TRUE; 4630 return SCIP_OKAY; 4631 } 4632 else if( SCIPsetIsEQ(set, varlb, varub) ) 4633 { 4634 /* the aggregated variable is fixed -> fix both variables */ 4635 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, 4636 eventfilter, eventqueue, cliquetable, varlb, infeasible, fixed) ); 4637 if( !(*infeasible) ) 4638 { 4639 SCIP_Bool aggfixed; 4640 4641 SCIP_CALL( SCIPvarFix(aggvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, 4642 eventfilter, eventqueue, cliquetable, (varlb-constant)/scalar, infeasible, &aggfixed) ); 4643 assert(*fixed == aggfixed); 4644 } 4645 return SCIP_OKAY; 4646 } 4647 else 4648 { 4649 if( SCIPsetIsGT(set, varlb, var->glbdom.lb) ) 4650 { 4651 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, varlb) ); 4652 } 4653 if( SCIPsetIsLT(set, varub, var->glbdom.ub) ) 4654 { 4655 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, varub) ); 4656 } 4657 4658 /* update the hole list of the aggregation variable */ 4659 /**@todo update hole list of aggregation variable */ 4660 } 4661 4662 /* update the bounds of the aggregation variable y in x = a*y + c -> y = (x-c)/a */ 4663 if( scalar > 0.0 ) 4664 { 4665 if( SCIPsetIsInfinity(set, -var->glbdom.lb) ) 4666 aggvarlb = -SCIPsetInfinity(set); 4667 else 4668 aggvarlb = (var->glbdom.lb - constant) / scalar; 4669 if( SCIPsetIsInfinity(set, var->glbdom.ub) ) 4670 aggvarub = SCIPsetInfinity(set); 4671 else 4672 aggvarub = (var->glbdom.ub - constant) / scalar; 4673 } 4674 else 4675 { 4676 if( SCIPsetIsInfinity(set, -var->glbdom.lb) ) 4677 aggvarub = SCIPsetInfinity(set); 4678 else 4679 aggvarub = (var->glbdom.lb - constant) / scalar; 4680 if( SCIPsetIsInfinity(set, var->glbdom.ub) ) 4681 aggvarlb = -SCIPsetInfinity(set); 4682 else 4683 aggvarlb = (var->glbdom.ub - constant) / scalar; 4684 } 4685 aggvarlb = MAX(aggvarlb, aggvar->glbdom.lb); 4686 aggvarub = MIN(aggvarub, aggvar->glbdom.ub); 4687 SCIPvarAdjustLb(aggvar, set, &aggvarlb); 4688 SCIPvarAdjustUb(aggvar, set, &aggvarub); 4689 4690 /* check the new bounds */ 4691 if( SCIPsetIsGT(set, aggvarlb, aggvarub) ) 4692 { 4693 /* the aggregation is infeasible */ 4694 *infeasible = TRUE; 4695 return SCIP_OKAY; 4696 } 4697 else if( SCIPsetIsEQ(set, aggvarlb, aggvarub) ) 4698 { 4699 /* the aggregation variable is fixed -> fix both variables */ 4700 SCIP_CALL( SCIPvarFix(aggvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, 4701 eventfilter, eventqueue, cliquetable, aggvarlb, infeasible, fixed) ); 4702 if( !(*infeasible) ) 4703 { 4704 SCIP_Bool varfixed; 4705 4706 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, 4707 eventfilter, eventqueue, cliquetable, aggvarlb * scalar + constant, infeasible, &varfixed) ); 4708 assert(*fixed == varfixed); 4709 } 4710 return SCIP_OKAY; 4711 } 4712 else 4713 { 4714 SCIP_Real oldbd; 4715 if( SCIPsetIsGT(set, aggvarlb, aggvar->glbdom.lb) ) 4716 { 4717 oldbd = aggvar->glbdom.lb; 4718 SCIP_CALL( SCIPvarChgLbGlobal(aggvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, aggvarlb) ); 4719 aggvarbdschanged = !SCIPsetIsEQ(set, oldbd, aggvar->glbdom.lb); 4720 } 4721 if( SCIPsetIsLT(set, aggvarub, aggvar->glbdom.ub) ) 4722 { 4723 oldbd = aggvar->glbdom.ub; 4724 SCIP_CALL( SCIPvarChgUbGlobal(aggvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, aggvarub) ); 4725 aggvarbdschanged = aggvarbdschanged || !SCIPsetIsEQ(set, oldbd, aggvar->glbdom.ub); 4726 } 4727 4728 /* update the hole list of the aggregation variable */ 4729 /**@todo update hole list of aggregation variable */ 4730 } 4731 } 4732 while( aggvarbdschanged ); 4733 4734 SCIPsetDebugMsg(set, " new bounds: <%s> [%g,%g] <%s> [%g,%g]\n", 4735 var->name, var->glbdom.lb, var->glbdom.ub, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub); 4736 4737 return SCIP_OKAY; 4738 } 4739 4740 /** converts loose variable into aggregated variable */ 4741 SCIP_RETCODE SCIPvarAggregate( 4742 SCIP_VAR* var, /**< loose problem variable */ 4743 BMS_BLKMEM* blkmem, /**< block memory */ 4744 SCIP_SET* set, /**< global SCIP settings */ 4745 SCIP_STAT* stat, /**< problem statistics */ 4746 SCIP_PROB* transprob, /**< tranformed problem data */ 4747 SCIP_PROB* origprob, /**< original problem data */ 4748 SCIP_PRIMAL* primal, /**< primal data */ 4749 SCIP_TREE* tree, /**< branch and bound tree */ 4750 SCIP_REOPT* reopt, /**< reoptimization data structure */ 4751 SCIP_LP* lp, /**< current LP data */ 4752 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 4753 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 4754 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 4755 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 4756 SCIP_VAR* aggvar, /**< loose variable y in aggregation x = a*y + c */ 4757 SCIP_Real scalar, /**< multiplier a in aggregation x = a*y + c */ 4758 SCIP_Real constant, /**< constant shift c in aggregation x = a*y + c */ 4759 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */ 4760 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */ 4761 ) 4762 { 4763 SCIP_VAR** vars; 4764 SCIP_Real* coefs; 4765 SCIP_Real* constants; 4766 SCIP_Real obj; 4767 SCIP_Real branchfactor; 4768 SCIP_Bool fixed; 4769 int branchpriority; 4770 int nlocksdown[NLOCKTYPES]; 4771 int nlocksup[NLOCKTYPES]; 4772 int nvbds; 4773 int i; 4774 int j; 4775 4776 assert(var != NULL); 4777 assert(aggvar != NULL); 4778 assert(var->scip == set->scip); 4779 assert(var->glbdom.lb == var->locdom.lb); /*lint !e777*/ 4780 assert(var->glbdom.ub == var->locdom.ub); /*lint !e777*/ 4781 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); 4782 assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */ 4783 assert(infeasible != NULL); 4784 assert(aggregated != NULL); 4785 4786 *infeasible = FALSE; 4787 *aggregated = FALSE; 4788 4789 /* get active problem variable of aggregation variable */ 4790 SCIP_CALL( SCIPvarGetProbvarSum(&aggvar, set, &scalar, &constant) ); 4791 4792 /* aggregation is a fixing, if the scalar is zero */ 4793 if( SCIPsetIsZero(set, scalar) ) 4794 { 4795 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventfilter, 4796 eventqueue, cliquetable, constant, infeasible, aggregated) ); 4797 goto TERMINATE; 4798 } 4799 4800 /* don't perform the aggregation if the aggregation variable is multi-aggregated itself */ 4801 if( SCIPvarGetStatus(aggvar) == SCIP_VARSTATUS_MULTAGGR ) 4802 return SCIP_OKAY; 4803 4804 /**@todo currently we don't perform the aggregation if the aggregation variable has a non-empty hole list; this 4805 * should be changed in the future 4806 */ 4807 if( SCIPvarGetHolelistGlobal(var) != NULL ) 4808 return SCIP_OKAY; 4809 4810 /* if the variable is not allowed to be aggregated */ 4811 if( SCIPvarDoNotAggr(var) ) 4812 { 4813 SCIPsetDebugMsg(set, "variable is not allowed to be aggregated.\n"); 4814 return SCIP_OKAY; 4815 } 4816 4817 assert(aggvar->glbdom.lb == aggvar->locdom.lb); /*lint !e777*/ 4818 assert(aggvar->glbdom.ub == aggvar->locdom.ub); /*lint !e777*/ 4819 assert(SCIPvarGetStatus(aggvar) == SCIP_VARSTATUS_LOOSE); 4820 4821 SCIPsetDebugMsg(set, "aggregate variable <%s>[%g,%g] == %g*<%s>[%g,%g] %+g\n", var->name, var->glbdom.lb, var->glbdom.ub, 4822 scalar, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub, constant); 4823 4824 /* if variable and aggregation variable are equal, the variable can be fixed: x == a*x + c => x == c/(1-a) */ 4825 if( var == aggvar ) 4826 { 4827 if( SCIPsetIsEQ(set, scalar, 1.0) ) 4828 *infeasible = !SCIPsetIsZero(set, constant); 4829 else 4830 { 4831 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, 4832 eventfilter, eventqueue, cliquetable, constant/(1.0-scalar), infeasible, aggregated) ); 4833 } 4834 goto TERMINATE; 4835 } 4836 4837 /* tighten the bounds of aggregated and aggregation variable */ 4838 SCIP_CALL( varUpdateAggregationBounds(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, 4839 branchcand, eventfilter, eventqueue, cliquetable, aggvar, scalar, constant, infeasible, &fixed) ); 4840 if( *infeasible || fixed ) 4841 { 4842 *aggregated = fixed; 4843 goto TERMINATE; 4844 } 4845 4846 /* delete implications and variable bounds of the aggregated variable from other variables, but keep them in the 4847 * aggregated variable 4848 */ 4849 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, FALSE) ); 4850 4851 /* set the aggregated variable's objective value to 0.0 */ 4852 obj = var->obj; 4853 SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) ); 4854 4855 /* unlock all locks */ 4856 for( i = 0; i < NLOCKTYPES; i++ ) 4857 { 4858 nlocksdown[i] = var->nlocksdown[i]; 4859 nlocksup[i] = var->nlocksup[i]; 4860 4861 var->nlocksdown[i] = 0; 4862 var->nlocksup[i] = 0; 4863 } 4864 4865 /* check, if variable should be used as NEGATED variable of the aggregation variable */ 4866 if( SCIPvarIsBinary(var) && SCIPvarIsBinary(aggvar) 4867 && var->negatedvar == NULL && aggvar->negatedvar == NULL 4868 && SCIPsetIsEQ(set, scalar, -1.0) && SCIPsetIsEQ(set, constant, 1.0) ) 4869 { 4870 /* link both variables as negation pair */ 4871 var->varstatus = SCIP_VARSTATUS_NEGATED; /*lint !e641*/ 4872 var->data.negate.constant = 1.0; 4873 var->negatedvar = aggvar; 4874 aggvar->negatedvar = var; 4875 4876 /* copy donot(mult)aggr status */ 4877 aggvar->donotaggr |= var->donotaggr; 4878 aggvar->donotmultaggr |= var->donotmultaggr; 4879 4880 /* mark both variables to be non-deletable */ 4881 SCIPvarMarkNotDeletable(var); 4882 SCIPvarMarkNotDeletable(aggvar); 4883 } 4884 else 4885 { 4886 /* convert variable into aggregated variable */ 4887 var->varstatus = SCIP_VARSTATUS_AGGREGATED; /*lint !e641*/ 4888 var->data.aggregate.var = aggvar; 4889 var->data.aggregate.scalar = scalar; 4890 var->data.aggregate.constant = constant; 4891 4892 /* copy donot(mult)aggr status */ 4893 aggvar->donotaggr |= var->donotaggr; 4894 aggvar->donotmultaggr |= var->donotmultaggr; 4895 4896 /* mark both variables to be non-deletable */ 4897 SCIPvarMarkNotDeletable(var); 4898 SCIPvarMarkNotDeletable(aggvar); 4899 } 4900 4901 /* make aggregated variable a parent of the aggregation variable */ 4902 SCIP_CALL( varAddParent(aggvar, blkmem, set, var) ); 4903 4904 /* relock the variable, thus increasing the locks of the aggregation variable */ 4905 for( i = 0; i < NLOCKTYPES; i++ ) 4906 { 4907 SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) ); 4908 } 4909 4910 /* move the variable bounds to the aggregation variable: 4911 * - add all variable bounds again to the variable, thus adding it to the aggregation variable 4912 * - free the variable bounds data structures 4913 */ 4914 if( var->vlbs != NULL ) 4915 { 4916 nvbds = SCIPvboundsGetNVbds(var->vlbs); 4917 vars = SCIPvboundsGetVars(var->vlbs); 4918 coefs = SCIPvboundsGetCoefs(var->vlbs); 4919 constants = SCIPvboundsGetConstants(var->vlbs); 4920 for( i = 0; i < nvbds && !(*infeasible); ++i ) 4921 { 4922 SCIP_CALL( SCIPvarAddVlb(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand, 4923 eventqueue, vars[i], coefs[i], constants[i], FALSE, infeasible, NULL) ); 4924 } 4925 } 4926 if( var->vubs != NULL ) 4927 { 4928 nvbds = SCIPvboundsGetNVbds(var->vubs); 4929 vars = SCIPvboundsGetVars(var->vubs); 4930 coefs = SCIPvboundsGetCoefs(var->vubs); 4931 constants = SCIPvboundsGetConstants(var->vubs); 4932 for( i = 0; i < nvbds && !(*infeasible); ++i ) 4933 { 4934 SCIP_CALL( SCIPvarAddVub(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand, 4935 eventqueue, vars[i], coefs[i], constants[i], FALSE, infeasible, NULL) ); 4936 } 4937 } 4938 SCIPvboundsFree(&var->vlbs, blkmem); 4939 SCIPvboundsFree(&var->vubs, blkmem); 4940 4941 /* move the implications to the aggregation variable: 4942 * - add all implications again to the variable, thus adding it to the aggregation variable 4943 * - free the implications data structures 4944 */ 4945 if( var->implics != NULL && SCIPvarGetType(aggvar) == SCIP_VARTYPE_BINARY ) 4946 { 4947 assert(SCIPvarIsBinary(var)); 4948 for( i = 0; i < 2; ++i ) 4949 { 4950 SCIP_VAR** implvars; 4951 SCIP_BOUNDTYPE* impltypes; 4952 SCIP_Real* implbounds; 4953 int nimpls; 4954 4955 nimpls = SCIPimplicsGetNImpls(var->implics, (SCIP_Bool)i); 4956 implvars = SCIPimplicsGetVars(var->implics, (SCIP_Bool)i); 4957 impltypes = SCIPimplicsGetTypes(var->implics, (SCIP_Bool)i); 4958 implbounds = SCIPimplicsGetBounds(var->implics, (SCIP_Bool)i); 4959 4960 for( j = 0; j < nimpls && !(*infeasible); ++j ) 4961 { 4962 /* @todo can't we omit transitive closure, because it should already have been done when adding the 4963 * implication to the aggregated variable? 4964 */ 4965 SCIP_CALL( SCIPvarAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 4966 branchcand, eventqueue, (SCIP_Bool)i, implvars[j], impltypes[j], implbounds[j], FALSE, infeasible, 4967 NULL) ); 4968 assert(nimpls == SCIPimplicsGetNImpls(var->implics, (SCIP_Bool)i)); 4969 } 4970 } 4971 } 4972 SCIPimplicsFree(&var->implics, blkmem); 4973 4974 /* add the history entries to the aggregation variable and clear the history of the aggregated variable */ 4975 SCIPhistoryUnite(aggvar->history, var->history, scalar < 0.0); 4976 SCIPhistoryUnite(aggvar->historycrun, var->historycrun, scalar < 0.0); 4977 SCIPhistoryReset(var->history); 4978 SCIPhistoryReset(var->historycrun); 4979 4980 /* update flags of aggregation variable */ 4981 aggvar->removable &= var->removable; 4982 4983 /* update branching factors and priorities of both variables to be the maximum of both variables */ 4984 branchfactor = MAX(aggvar->branchfactor, var->branchfactor); 4985 branchpriority = MAX(aggvar->branchpriority, var->branchpriority); 4986 SCIP_CALL( SCIPvarChgBranchFactor(aggvar, set, branchfactor) ); 4987 SCIP_CALL( SCIPvarChgBranchPriority(aggvar, branchpriority) ); 4988 SCIP_CALL( SCIPvarChgBranchFactor(var, set, branchfactor) ); 4989 SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) ); 4990 4991 /* update branching direction of both variables to agree to a single direction */ 4992 if( scalar >= 0.0 ) 4993 { 4994 if( (SCIP_BRANCHDIR)var->branchdirection == SCIP_BRANCHDIR_AUTO ) 4995 { 4996 SCIP_CALL( SCIPvarChgBranchDirection(var, (SCIP_BRANCHDIR)aggvar->branchdirection) ); 4997 } 4998 else if( (SCIP_BRANCHDIR)aggvar->branchdirection == SCIP_BRANCHDIR_AUTO ) 4999 { 5000 SCIP_CALL( SCIPvarChgBranchDirection(aggvar, (SCIP_BRANCHDIR)var->branchdirection) ); 5001 } 5002 else if( var->branchdirection != aggvar->branchdirection ) 5003 { 5004 SCIP_CALL( SCIPvarChgBranchDirection(var, SCIP_BRANCHDIR_AUTO) ); 5005 } 5006 } 5007 else 5008 { 5009 if( (SCIP_BRANCHDIR)var->branchdirection == SCIP_BRANCHDIR_AUTO ) 5010 { 5011 SCIP_CALL( SCIPvarChgBranchDirection(var, SCIPbranchdirOpposite((SCIP_BRANCHDIR)aggvar->branchdirection)) ); 5012 } 5013 else if( (SCIP_BRANCHDIR)aggvar->branchdirection == SCIP_BRANCHDIR_AUTO ) 5014 { 5015 SCIP_CALL( SCIPvarChgBranchDirection(aggvar, SCIPbranchdirOpposite((SCIP_BRANCHDIR)var->branchdirection)) ); 5016 } 5017 else if( var->branchdirection != aggvar->branchdirection ) 5018 { 5019 SCIP_CALL( SCIPvarChgBranchDirection(var, SCIP_BRANCHDIR_AUTO) ); 5020 } 5021 } 5022 5023 if( var->probindex != -1 ) 5024 { 5025 /* inform problem about the variable's status change */ 5026 SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) ); 5027 } 5028 5029 /* reset the objective value of the aggregated variable, thus adjusting the objective value of the aggregation 5030 * variable and the problem's objective offset 5031 */ 5032 SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) ); 5033 5034 /* issue VARFIXED event */ 5035 SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 1) ); 5036 5037 *aggregated = TRUE; 5038 5039 TERMINATE: 5040 /* check aggregation on debugging solution */ 5041 if( *infeasible || *aggregated ) 5042 SCIP_CALL( SCIPdebugCheckAggregation(set, var, &aggvar, &scalar, constant, 1) ); /*lint !e506 !e774*/ 5043 5044 return SCIP_OKAY; 5045 } 5046 5047 /** Tries to aggregate an equality a*x + b*y == c consisting of two (implicit) integral active problem variables x and 5048 * y. An integer aggregation (i.e. integral coefficients a' and b', such that a'*x + b'*y == c') is searched. 5049 * 5050 * This can lead to the detection of infeasibility (e.g. if c' is fractional), or to a rejection of the aggregation 5051 * (denoted by aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable. 5052 */ 5053 static 5054 SCIP_RETCODE tryAggregateIntVars( 5055 SCIP_SET* set, /**< global SCIP settings */ 5056 BMS_BLKMEM* blkmem, /**< block memory */ 5057 SCIP_STAT* stat, /**< problem statistics */ 5058 SCIP_PROB* transprob, /**< tranformed problem data */ 5059 SCIP_PROB* origprob, /**< original problem data */ 5060 SCIP_PRIMAL* primal, /**< primal data */ 5061 SCIP_TREE* tree, /**< branch and bound tree */ 5062 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5063 SCIP_LP* lp, /**< current LP data */ 5064 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 5065 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 5066 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 5067 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 5068 SCIP_VAR* varx, /**< integral variable x in equality a*x + b*y == c */ 5069 SCIP_VAR* vary, /**< integral variable y in equality a*x + b*y == c */ 5070 SCIP_Real scalarx, /**< multiplier a in equality a*x + b*y == c */ 5071 SCIP_Real scalary, /**< multiplier b in equality a*x + b*y == c */ 5072 SCIP_Real rhs, /**< right hand side c in equality a*x + b*y == c */ 5073 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */ 5074 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */ 5075 ) 5076 { 5077 SCIP_VAR* aggvar; 5078 char aggvarname[SCIP_MAXSTRLEN]; 5079 SCIP_Longint scalarxn = 0; 5080 SCIP_Longint scalarxd = 0; 5081 SCIP_Longint scalaryn = 0; 5082 SCIP_Longint scalaryd = 0; 5083 SCIP_Longint a; 5084 SCIP_Longint b; 5085 SCIP_Longint c; 5086 SCIP_Longint scm; 5087 SCIP_Longint gcd; 5088 SCIP_Longint currentclass; 5089 SCIP_Longint classstep; 5090 SCIP_Longint xsol; 5091 SCIP_Longint ysol; 5092 SCIP_Bool success; 5093 SCIP_VARTYPE vartype; 5094 5095 #define MAXDNOM 1000000LL 5096 5097 assert(set != NULL); 5098 assert(blkmem != NULL); 5099 assert(stat != NULL); 5100 assert(transprob != NULL); 5101 assert(origprob != NULL); 5102 assert(tree != NULL); 5103 assert(lp != NULL); 5104 assert(cliquetable != NULL); 5105 assert(branchcand != NULL); 5106 assert(eventqueue != NULL); 5107 assert(varx != NULL); 5108 assert(vary != NULL); 5109 assert(varx != vary); 5110 assert(infeasible != NULL); 5111 assert(aggregated != NULL); 5112 assert(SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING); 5113 assert(SCIPvarGetStatus(varx) == SCIP_VARSTATUS_LOOSE); 5114 assert(SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(varx) == SCIP_VARTYPE_IMPLINT); 5115 assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE); 5116 assert(SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vary) == SCIP_VARTYPE_IMPLINT); 5117 assert(!SCIPsetIsZero(set, scalarx)); 5118 assert(!SCIPsetIsZero(set, scalary)); 5119 5120 *infeasible = FALSE; 5121 *aggregated = FALSE; 5122 5123 /* if the variable is not allowed to be aggregated */ 5124 if( SCIPvarDoNotAggr(varx) ) 5125 { 5126 SCIPsetDebugMsg(set, "variable is not allowed to be aggregated.\n"); 5127 return SCIP_OKAY; 5128 } 5129 5130 /* get rational representation of coefficients */ 5131 success = SCIPrealToRational(scalarx, -SCIPsetEpsilon(set), SCIPsetEpsilon(set), MAXDNOM, &scalarxn, &scalarxd); 5132 if( success ) 5133 success = SCIPrealToRational(scalary, -SCIPsetEpsilon(set), SCIPsetEpsilon(set), MAXDNOM, &scalaryn, &scalaryd); 5134 if( !success ) 5135 return SCIP_OKAY; 5136 assert(scalarxd >= 1); 5137 assert(scalaryd >= 1); 5138 5139 /* multiply equality with smallest common denominator */ 5140 scm = SCIPcalcSmaComMul(scalarxd, scalaryd); 5141 a = (scm/scalarxd)*scalarxn; 5142 b = (scm/scalaryd)*scalaryn; 5143 rhs *= scm; 5144 5145 /* divide equality by the greatest common divisor of a and b */ 5146 gcd = SCIPcalcGreComDiv(ABS(a), ABS(b)); 5147 a /= gcd; 5148 b /= gcd; 5149 rhs /= gcd; 5150 assert(a != 0); 5151 assert(b != 0); 5152 5153 /* check, if right hand side is integral */ 5154 if( !SCIPsetIsFeasIntegral(set, rhs) ) 5155 { 5156 *infeasible = TRUE; 5157 return SCIP_OKAY; 5158 } 5159 c = (SCIP_Longint)(SCIPsetFeasFloor(set, rhs)); 5160 5161 /* check that the scalar and constant in the aggregation are not too large to avoid numerical problems */ 5162 if( REALABS((SCIP_Real)(c/a)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) /*lint !e653*/ 5163 || REALABS((SCIP_Real)(b)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) /*lint !e653*/ 5164 || REALABS((SCIP_Real)(a)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) ) /*lint !e653*/ 5165 { 5166 return SCIP_OKAY; 5167 } 5168 5169 /* check, if we are in an easy case with either |a| = 1 or |b| = 1 */ 5170 if( (a == 1 || a == -1) && SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER ) 5171 { 5172 /* aggregate x = - b/a*y + c/a */ 5173 /*lint --e{653}*/ 5174 SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable, 5175 branchcand, eventfilter, eventqueue, vary, (SCIP_Real)(-b/a), (SCIP_Real)(c/a), infeasible, aggregated) ); 5176 assert(*aggregated); 5177 return SCIP_OKAY; 5178 } 5179 if( (b == 1 || b == -1) && SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER ) 5180 { 5181 /* aggregate y = - a/b*x + c/b */ 5182 /*lint --e{653}*/ 5183 SCIP_CALL( SCIPvarAggregate(vary, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable, 5184 branchcand, eventfilter, eventqueue, varx, (SCIP_Real)(-a/b), (SCIP_Real)(c/b), infeasible, aggregated) ); 5185 assert(*aggregated); 5186 return SCIP_OKAY; 5187 } 5188 5189 /* Both variables are integers, their coefficients are not multiples of each other, and they don't have any 5190 * common divisor. Let (x',y') be a solution of the equality 5191 * a*x + b*y == c -> a*x == c - b*y 5192 * Then x = -b*z + x', y = a*z + y' with z integral gives all solutions to the equality. 5193 */ 5194 5195 /* find initial solution (x',y'): 5196 * - find y' such that c - b*y' is a multiple of a 5197 * - start in equivalence class c%a 5198 * - step through classes, where each step increases class number by (-b)%a, until class 0 is visited 5199 * - if equivalence class 0 is visited, we are done: y' equals the number of steps taken 5200 * - because a and b don't have a common divisor, each class is visited at most once, and at most a-1 steps are needed 5201 * - calculate x' with x' = (c - b*y')/a (which must be integral) 5202 * 5203 * Algorithm works for a > 0 only. 5204 */ 5205 if( a < 0 ) 5206 { 5207 a = -a; 5208 b = -b; 5209 c = -c; 5210 } 5211 assert(a > 0); 5212 5213 /* search upwards from ysol = 0 */ 5214 ysol = 0; 5215 currentclass = c % a; 5216 if( currentclass < 0 ) 5217 currentclass += a; 5218 assert(0 <= currentclass && currentclass < a); 5219 5220 classstep = (-b) % a; 5221 5222 if( classstep < 0 ) 5223 classstep += a; 5224 assert(0 <= classstep && classstep < a); 5225 5226 while( currentclass != 0 ) 5227 { 5228 assert(0 <= currentclass && currentclass < a); 5229 currentclass += classstep; 5230 if( currentclass >= a ) 5231 currentclass -= a; 5232 ysol++; 5233 } 5234 assert(ysol < a); 5235 assert(((c - b*ysol) % a) == 0); 5236 5237 xsol = (c - b*ysol)/a; 5238 5239 /* determine variable type for new artificial variable: 5240 * 5241 * if both variables are implicit integer the new variable can be implicit too, because the integer implication on 5242 * these both variables should be enforced by some other variables, otherwise the new variable needs to be of 5243 * integral type 5244 */ 5245 vartype = ((SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER) 5246 ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_IMPLINT); 5247 5248 /* feasible solutions are (x,y) = (x',y') + z*(-b,a) 5249 * - create new integer variable z with infinite bounds 5250 * - aggregate variable x = -b*z + x' 5251 * - aggregate variable y = a*z + y' 5252 * - the bounds of z are calculated automatically during aggregation 5253 */ 5254 (void) SCIPsnprintf(aggvarname, SCIP_MAXSTRLEN, "agg%d", stat->nvaridx); 5255 SCIP_CALL( SCIPvarCreateTransformed(&aggvar, blkmem, set, stat, 5256 aggvarname, -SCIPsetInfinity(set), SCIPsetInfinity(set), 0.0, vartype, 5257 SCIPvarIsInitial(varx) || SCIPvarIsInitial(vary), SCIPvarIsRemovable(varx) && SCIPvarIsRemovable(vary), 5258 NULL, NULL, NULL, NULL, NULL) ); 5259 5260 SCIP_CALL( SCIPprobAddVar(transprob, blkmem, set, lp, branchcand, eventfilter, eventqueue, aggvar) ); 5261 5262 SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable, 5263 branchcand, eventfilter, eventqueue, aggvar, (SCIP_Real)(-b), (SCIP_Real)xsol, infeasible, aggregated) ); 5264 assert(*aggregated || *infeasible); 5265 5266 if( !(*infeasible) ) 5267 { 5268 SCIP_CALL( SCIPvarAggregate(vary, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable, 5269 branchcand, eventfilter, eventqueue, aggvar, (SCIP_Real)a, (SCIP_Real)ysol, infeasible, aggregated) ); 5270 assert(*aggregated || *infeasible); 5271 } 5272 5273 /* release z */ 5274 SCIP_CALL( SCIPvarRelease(&aggvar, blkmem, set, eventqueue, lp) ); 5275 5276 return SCIP_OKAY; /*lint !e438*/ 5277 } 5278 5279 /** performs second step of SCIPaggregateVars(): 5280 * the variable to be aggregated is chosen among active problem variables x' and y', preferring a less strict variable 5281 * type as aggregation variable (i.e. continuous variables are preferred over implicit integers, implicit integers 5282 * or integers over binaries). If none of the variables is continuous, it is tried to find an integer 5283 * aggregation (i.e. integral coefficients a'' and b'', such that a''*x' + b''*y' == c''). This can lead to 5284 * the detection of infeasibility (e.g. if c'' is fractional), or to a rejection of the aggregation (denoted by 5285 * aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable. 5286 * 5287 * @todo check for fixings, infeasibility, bound changes, or domain holes: 5288 * a) if there is no easy aggregation and we have one binary variable and another integer/implicit/binary variable 5289 * b) for implicit integer variables with fractional aggregation scalar (we cannot (for technical reasons) and do 5290 * not want to aggregate implicit integer variables, since we loose the corresponding divisibility property) 5291 */ 5292 SCIP_RETCODE SCIPvarTryAggregateVars( 5293 SCIP_SET* set, /**< global SCIP settings */ 5294 BMS_BLKMEM* blkmem, /**< block memory */ 5295 SCIP_STAT* stat, /**< problem statistics */ 5296 SCIP_PROB* transprob, /**< tranformed problem data */ 5297 SCIP_PROB* origprob, /**< original problem data */ 5298 SCIP_PRIMAL* primal, /**< primal data */ 5299 SCIP_TREE* tree, /**< branch and bound tree */ 5300 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5301 SCIP_LP* lp, /**< current LP data */ 5302 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 5303 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 5304 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 5305 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 5306 SCIP_VAR* varx, /**< variable x in equality a*x + b*y == c */ 5307 SCIP_VAR* vary, /**< variable y in equality a*x + b*y == c */ 5308 SCIP_Real scalarx, /**< multiplier a in equality a*x + b*y == c */ 5309 SCIP_Real scalary, /**< multiplier b in equality a*x + b*y == c */ 5310 SCIP_Real rhs, /**< right hand side c in equality a*x + b*y == c */ 5311 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */ 5312 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */ 5313 ) 5314 { 5315 SCIP_Bool easyaggr; 5316 5317 assert(set != NULL); 5318 assert(blkmem != NULL); 5319 assert(stat != NULL); 5320 assert(transprob != NULL); 5321 assert(origprob != NULL); 5322 assert(tree != NULL); 5323 assert(lp != NULL); 5324 assert(cliquetable != NULL); 5325 assert(branchcand != NULL); 5326 assert(eventqueue != NULL); 5327 assert(varx != NULL); 5328 assert(vary != NULL); 5329 assert(varx != vary); 5330 assert(infeasible != NULL); 5331 assert(aggregated != NULL); 5332 assert(SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING); 5333 assert(SCIPvarGetStatus(varx) == SCIP_VARSTATUS_LOOSE); 5334 assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE); 5335 assert(!SCIPsetIsZero(set, scalarx)); 5336 assert(!SCIPsetIsZero(set, scalary)); 5337 5338 *infeasible = FALSE; 5339 *aggregated = FALSE; 5340 5341 if( SCIPsetIsZero(set, scalarx / scalary) || SCIPsetIsZero(set, scalary / scalarx) ) 5342 return SCIP_OKAY; 5343 5344 /* prefer aggregating the variable of more general type (preferred aggregation variable is varx) */ 5345 if( SCIPvarGetType(vary) > SCIPvarGetType(varx) || 5346 (SCIPvarGetType(vary) == SCIPvarGetType(varx) && !SCIPvarIsBinary(vary) && SCIPvarIsBinary(varx)) ) 5347 { 5348 SCIP_VAR* var; 5349 SCIP_Real scalar; 5350 5351 /* switch the variables, such that varx is the variable of more general type (cont > implint > int > bin) */ 5352 var = vary; 5353 vary = varx; 5354 varx = var; 5355 scalar = scalary; 5356 scalary = scalarx; 5357 scalarx = scalar; 5358 } 5359 5360 /* don't aggregate if the aggregation would lead to a binary variable aggregated to a non-binary variable */ 5361 if( SCIPvarIsBinary(varx) && !SCIPvarIsBinary(vary) ) 5362 return SCIP_OKAY; 5363 5364 assert(SCIPvarGetType(varx) >= SCIPvarGetType(vary)); 5365 5366 /* figure out, which variable should be aggregated */ 5367 easyaggr = FALSE; 5368 5369 /* check if it is an easy aggregation */ 5370 if( SCIPvarGetType(varx) == SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(vary) < SCIP_VARTYPE_CONTINUOUS ) 5371 { 5372 easyaggr = TRUE; 5373 } 5374 else if( SCIPsetIsFeasIntegral(set, scalary/scalarx) ) 5375 { 5376 easyaggr = TRUE; 5377 } 5378 else if( SCIPsetIsFeasIntegral(set, scalarx/scalary) && SCIPvarGetType(vary) == SCIPvarGetType(varx) ) 5379 { 5380 /* we have an easy aggregation if we flip the variables x and y */ 5381 SCIP_VAR* var; 5382 SCIP_Real scalar; 5383 5384 /* switch the variables, such that varx is the aggregated variable */ 5385 var = vary; 5386 vary = varx; 5387 varx = var; 5388 scalar = scalary; 5389 scalary = scalarx; 5390 scalarx = scalar; 5391 easyaggr = TRUE; 5392 } 5393 else if( SCIPvarGetType(varx) == SCIP_VARTYPE_CONTINUOUS ) 5394 { 5395 /* the aggregation is still easy if both variables are continuous */ 5396 assert(SCIPvarGetType(vary) == SCIP_VARTYPE_CONTINUOUS); /* otherwise we are in the first case */ 5397 easyaggr = TRUE; 5398 } 5399 5400 /* did we find an "easy" aggregation? */ 5401 if( easyaggr ) 5402 { 5403 SCIP_Real scalar; 5404 SCIP_Real constant; 5405 5406 assert(SCIPvarGetType(varx) >= SCIPvarGetType(vary)); 5407 5408 /* calculate aggregation scalar and constant: a*x + b*y == c => x == -b/a * y + c/a */ 5409 scalar = -scalary/scalarx; 5410 constant = rhs/scalarx; 5411 5412 if( REALABS(constant) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) ) /*lint !e653*/ 5413 return SCIP_OKAY; 5414 5415 /* check aggregation for integer feasibility */ 5416 if( SCIPvarGetType(varx) != SCIP_VARTYPE_CONTINUOUS 5417 && SCIPvarGetType(vary) != SCIP_VARTYPE_CONTINUOUS 5418 && SCIPsetIsFeasIntegral(set, scalar) && !SCIPsetIsFeasIntegral(set, constant) ) 5419 { 5420 *infeasible = TRUE; 5421 return SCIP_OKAY; 5422 } 5423 5424 /* if the aggregation scalar is fractional, we cannot (for technical reasons) and do not want to aggregate implicit integer variables, 5425 * since then we would loose the corresponding divisibility property 5426 */ 5427 assert(SCIPvarGetType(varx) != SCIP_VARTYPE_IMPLINT || SCIPsetIsFeasIntegral(set, scalar)); 5428 5429 /* aggregate the variable */ 5430 SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable, 5431 branchcand, eventfilter, eventqueue, vary, scalar, constant, infeasible, aggregated) ); 5432 assert(*aggregated || *infeasible || SCIPvarDoNotAggr(varx)); 5433 } 5434 else if( (SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(varx) == SCIP_VARTYPE_IMPLINT) 5435 && (SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vary) == SCIP_VARTYPE_IMPLINT) ) 5436 { 5437 /* the variables are both integral: we have to try to find an integer aggregation */ 5438 SCIP_CALL( tryAggregateIntVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable, 5439 branchcand, eventfilter, eventqueue, varx, vary, scalarx, scalary, rhs, infeasible, aggregated) ); 5440 } 5441 5442 return SCIP_OKAY; 5443 } 5444 5445 /** converts variable into multi-aggregated variable */ 5446 SCIP_RETCODE SCIPvarMultiaggregate( 5447 SCIP_VAR* var, /**< problem variable */ 5448 BMS_BLKMEM* blkmem, /**< block memory */ 5449 SCIP_SET* set, /**< global SCIP settings */ 5450 SCIP_STAT* stat, /**< problem statistics */ 5451 SCIP_PROB* transprob, /**< tranformed problem data */ 5452 SCIP_PROB* origprob, /**< original problem data */ 5453 SCIP_PRIMAL* primal, /**< primal data */ 5454 SCIP_TREE* tree, /**< branch and bound tree */ 5455 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5456 SCIP_LP* lp, /**< current LP data */ 5457 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 5458 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 5459 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 5460 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 5461 int naggvars, /**< number n of variables in aggregation x = a_1*y_1 + ... + a_n*y_n + c */ 5462 SCIP_VAR** aggvars, /**< variables y_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */ 5463 SCIP_Real* scalars, /**< multipliers a_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */ 5464 SCIP_Real constant, /**< constant shift c in aggregation x = a_1*y_1 + ... + a_n*y_n + c */ 5465 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */ 5466 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */ 5467 ) 5468 { 5469 SCIP_VAR** tmpvars; 5470 SCIP_Real* tmpscalars; 5471 SCIP_Real obj; 5472 SCIP_Real branchfactor; 5473 int branchpriority; 5474 SCIP_BRANCHDIR branchdirection; 5475 int nlocksdown[NLOCKTYPES]; 5476 int nlocksup[NLOCKTYPES]; 5477 int v; 5478 SCIP_Real tmpconstant; 5479 SCIP_Real tmpscalar; 5480 int ntmpvars; 5481 int tmpvarssize; 5482 int tmprequiredsize; 5483 int i; 5484 5485 assert(var != NULL); 5486 assert(var->scip == set->scip); 5487 assert(var->glbdom.lb == var->locdom.lb); /*lint !e777*/ 5488 assert(var->glbdom.ub == var->locdom.ub); /*lint !e777*/ 5489 assert(naggvars == 0 || aggvars != NULL); 5490 assert(naggvars == 0 || scalars != NULL); 5491 assert(infeasible != NULL); 5492 assert(aggregated != NULL); 5493 5494 SCIPsetDebugMsg(set, "trying multi-aggregating variable <%s> == ...%d vars... %+g\n", var->name, naggvars, constant); 5495 5496 *infeasible = FALSE; 5497 *aggregated = FALSE; 5498 5499 switch( SCIPvarGetStatus(var) ) 5500 { 5501 case SCIP_VARSTATUS_ORIGINAL: 5502 if( var->data.original.transvar == NULL ) 5503 { 5504 SCIPerrorMessage("cannot multi-aggregate an untransformed original variable\n"); 5505 return SCIP_INVALIDDATA; 5506 } 5507 SCIP_CALL( SCIPvarMultiaggregate(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree, 5508 reopt, lp, cliquetable, branchcand, eventfilter, eventqueue, naggvars, aggvars, scalars, constant, infeasible, aggregated) ); 5509 break; 5510 5511 case SCIP_VARSTATUS_LOOSE: 5512 assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */ 5513 5514 /* check if we would create a self-reference */ 5515 ntmpvars = naggvars; 5516 tmpvarssize = naggvars; 5517 tmpconstant = constant; 5518 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpvars, aggvars, ntmpvars) ); 5519 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpscalars, scalars, ntmpvars) ); 5520 5521 /* get all active variables for multi-aggregation */ 5522 SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) ); 5523 if( tmprequiredsize > tmpvarssize ) 5524 { 5525 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpvars, tmpvarssize, tmprequiredsize) ); 5526 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize, tmprequiredsize) ); 5527 tmpvarssize = tmprequiredsize; 5528 SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) ); 5529 assert( tmprequiredsize <= tmpvarssize ); 5530 } 5531 5532 tmpscalar = 0.0; 5533 5534 /* iterate over all active variables of the multi-aggregation and filter all variables which are equal to the 5535 * possible multi-aggregated variable 5536 */ 5537 for( v = ntmpvars - 1; v >= 0; --v ) 5538 { 5539 assert(tmpvars[v] != NULL); 5540 assert(SCIPvarGetStatus(tmpvars[v]) == SCIP_VARSTATUS_LOOSE); 5541 5542 if( tmpvars[v]->index == var->index ) 5543 { 5544 tmpscalar += tmpscalars[v]; 5545 tmpvars[v] = tmpvars[ntmpvars - 1]; 5546 tmpscalars[v] = tmpscalars[ntmpvars - 1]; 5547 --ntmpvars; 5548 } 5549 } 5550 5551 /* this means that x = x + a_1*y_1 + ... + a_n*y_n + c */ 5552 if( SCIPsetIsEQ(set, tmpscalar, 1.0) ) 5553 { 5554 if( ntmpvars == 0 ) 5555 { 5556 if( SCIPsetIsZero(set, tmpconstant) ) /* x = x */ 5557 { 5558 SCIPsetDebugMsg(set, "Possible multi-aggregation was completely resolved and detected to be redundant.\n"); 5559 goto TERMINATE; 5560 } 5561 else /* 0 = c and c != 0 */ 5562 { 5563 SCIPsetDebugMsg(set, "Multi-aggregation was completely resolved and led to infeasibility.\n"); 5564 *infeasible = TRUE; 5565 goto TERMINATE; 5566 } 5567 } 5568 else if( ntmpvars == 1 ) /* 0 = a*y + c => y = -c/a */ 5569 { 5570 assert(tmpscalars[0] != 0.0); 5571 assert(tmpvars[0] != NULL); 5572 5573 SCIPsetDebugMsg(set, "Possible multi-aggregation led to fixing of variable <%s> to %g.\n", SCIPvarGetName(tmpvars[0]), -constant/tmpscalars[0]); 5574 SCIP_CALL( SCIPvarFix(tmpvars[0], blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, 5575 branchcand, eventfilter, eventqueue, cliquetable, -constant/tmpscalars[0], infeasible, aggregated) ); 5576 goto TERMINATE; 5577 } 5578 else if( ntmpvars == 2 ) /* 0 = a_1*y_1 + a_2*y_2 + c => y_1 = -a_2/a_1 * y_2 - c/a_1 */ 5579 { 5580 /* both variables are different active problem variables, and both scalars are non-zero: try to aggregate them */ 5581 SCIPsetDebugMsg(set, "Possible multi-aggregation led to aggregation of variables <%s> and <%s> with scalars %g and %g and constant %g.\n", 5582 SCIPvarGetName(tmpvars[0]), SCIPvarGetName(tmpvars[1]), tmpscalars[0], tmpscalars[1], -tmpconstant); 5583 5584 SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp, 5585 cliquetable, branchcand, eventfilter, eventqueue, tmpvars[0], tmpvars[1], tmpscalars[0], 5586 tmpscalars[1], -tmpconstant, infeasible, aggregated) ); 5587 5588 goto TERMINATE; 5589 } 5590 else 5591 /* @todo: it is possible to multi-aggregate another variable, does it make sense?, 5592 * rest looks like 0 = a_1*y_1 + ... + a_n*y_n + c and has at least three variables 5593 */ 5594 goto TERMINATE; 5595 } 5596 /* this means that x = b*x + a_1*y_1 + ... + a_n*y_n + c */ 5597 else if( !SCIPsetIsZero(set, tmpscalar) ) 5598 { 5599 tmpscalar = 1 - tmpscalar; 5600 tmpconstant /= tmpscalar; 5601 for( v = ntmpvars - 1; v >= 0; --v ) 5602 tmpscalars[v] /= tmpscalar; 5603 } 5604 5605 /* check, if we are in one of the simple cases */ 5606 if( ntmpvars == 0 ) 5607 { 5608 SCIPsetDebugMsg(set, "Possible multi-aggregation led to fixing of variable <%s> to %g.\n", SCIPvarGetName(var), tmpconstant); 5609 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, 5610 eventfilter, eventqueue, cliquetable, tmpconstant, infeasible, aggregated) ); 5611 goto TERMINATE; 5612 } 5613 5614 /* if only one aggregation variable is left, we perform a normal aggregation instead of a multi-aggregation */ 5615 if( ntmpvars == 1 ) 5616 { 5617 SCIPsetDebugMsg(set, "Possible multi-aggregation led to aggregation of variables <%s> and <%s> with scalars %g and %g and constant %g.\n", 5618 SCIPvarGetName(var), SCIPvarGetName(tmpvars[0]), 1.0, -tmpscalars[0], tmpconstant); 5619 5620 SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp, 5621 cliquetable, branchcand, eventfilter, eventqueue, var, tmpvars[0], 1.0, -tmpscalars[0], tmpconstant, 5622 infeasible, aggregated) ); 5623 5624 goto TERMINATE; 5625 } 5626 5627 /**@todo currently we don't perform the multi aggregation if the multi aggregation variable has a non 5628 * empty hole list; this should be changed in the future */ 5629 if( SCIPvarGetHolelistGlobal(var) != NULL ) 5630 goto TERMINATE; 5631 5632 /* if the variable is not allowed to be multi-aggregated */ 5633 if( SCIPvarDoNotMultaggr(var) ) 5634 { 5635 SCIPsetDebugMsg(set, "variable is not allowed to be multi-aggregated.\n"); 5636 goto TERMINATE; 5637 } 5638 5639 /* if the variable to be multi-aggregated has implications or variable bounds (i.e. is the implied variable or 5640 * variable bound variable of another variable), we have to remove it from the other variables implications or 5641 * variable bounds 5642 */ 5643 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) ); 5644 assert(var->vlbs == NULL); 5645 assert(var->vubs == NULL); 5646 assert(var->implics == NULL); 5647 5648 /* set the aggregated variable's objective value to 0.0 */ 5649 obj = var->obj; 5650 SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) ); 5651 5652 /* since we change the variable type form loose to multi aggregated, we have to adjust the number of loose 5653 * variables in the LP data structure; the loose objective value (looseobjval) in the LP data structure, however, 5654 * gets adjusted automatically, due to the event SCIP_EVENTTYPE_OBJCHANGED which dropped in the moment where the 5655 * objective of this variable is set to zero 5656 */ 5657 SCIPlpDecNLoosevars(lp); 5658 5659 /* unlock all rounding locks */ 5660 for( i = 0; i < NLOCKTYPES; i++ ) 5661 { 5662 nlocksdown[i] = var->nlocksdown[i]; 5663 nlocksup[i] = var->nlocksup[i]; 5664 5665 var->nlocksdown[i] = 0; 5666 var->nlocksup[i] = 0; 5667 } 5668 5669 /* convert variable into multi-aggregated variable */ 5670 var->varstatus = SCIP_VARSTATUS_MULTAGGR; /*lint !e641*/ 5671 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->data.multaggr.vars, tmpvars, ntmpvars) ); 5672 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->data.multaggr.scalars, tmpscalars, ntmpvars) ); 5673 var->data.multaggr.constant = tmpconstant; 5674 var->data.multaggr.nvars = ntmpvars; 5675 var->data.multaggr.varssize = ntmpvars; 5676 5677 /* mark variable to be non-deletable */ 5678 SCIPvarMarkNotDeletable(var); 5679 5680 /* relock the variable, thus increasing the locks of the aggregation variables */ 5681 for( i = 0; i < NLOCKTYPES; i++ ) 5682 { 5683 SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) ); 5684 } 5685 5686 /* update flags and branching factors and priorities of aggregation variables; 5687 * update preferred branching direction of all aggregation variables that don't have a preferred direction yet 5688 */ 5689 branchfactor = var->branchfactor; 5690 branchpriority = var->branchpriority; 5691 branchdirection = (SCIP_BRANCHDIR)var->branchdirection; 5692 5693 for( v = 0; v < ntmpvars; ++v ) 5694 { 5695 assert(tmpvars[v] != NULL); 5696 tmpvars[v]->removable &= var->removable; 5697 branchfactor = MAX(tmpvars[v]->branchfactor, branchfactor); 5698 branchpriority = MAX(tmpvars[v]->branchpriority, branchpriority); 5699 5700 /* mark variable to be non-deletable */ 5701 SCIPvarMarkNotDeletable(tmpvars[v]); 5702 } 5703 for( v = 0; v < ntmpvars; ++v ) 5704 { 5705 SCIP_CALL( SCIPvarChgBranchFactor(tmpvars[v], set, branchfactor) ); 5706 SCIP_CALL( SCIPvarChgBranchPriority(tmpvars[v], branchpriority) ); 5707 if( (SCIP_BRANCHDIR)tmpvars[v]->branchdirection == SCIP_BRANCHDIR_AUTO ) 5708 { 5709 if( tmpscalars[v] >= 0.0 ) 5710 { 5711 SCIP_CALL( SCIPvarChgBranchDirection(tmpvars[v], branchdirection) ); 5712 } 5713 else 5714 { 5715 SCIP_CALL( SCIPvarChgBranchDirection(tmpvars[v], SCIPbranchdirOpposite(branchdirection)) ); 5716 } 5717 } 5718 } 5719 SCIP_CALL( SCIPvarChgBranchFactor(var, set, branchfactor) ); 5720 SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) ); 5721 5722 if( var->probindex != -1 ) 5723 { 5724 /* inform problem about the variable's status change */ 5725 SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) ); 5726 } 5727 5728 /* issue VARFIXED event */ 5729 SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 2) ); 5730 5731 /* reset the objective value of the aggregated variable, thus adjusting the objective value of the aggregation 5732 * variables and the problem's objective offset 5733 */ 5734 SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) ); 5735 5736 *aggregated = TRUE; 5737 5738 TERMINATE: 5739 BMSfreeBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize); 5740 BMSfreeBlockMemoryArray(blkmem, &tmpvars, tmpvarssize); 5741 5742 break; 5743 5744 case SCIP_VARSTATUS_COLUMN: 5745 SCIPerrorMessage("cannot multi-aggregate a column variable\n"); 5746 return SCIP_INVALIDDATA; 5747 5748 case SCIP_VARSTATUS_FIXED: 5749 SCIPerrorMessage("cannot multi-aggregate a fixed variable\n"); 5750 return SCIP_INVALIDDATA; 5751 5752 case SCIP_VARSTATUS_AGGREGATED: 5753 SCIPerrorMessage("cannot multi-aggregate an aggregated variable\n"); 5754 return SCIP_INVALIDDATA; 5755 5756 case SCIP_VARSTATUS_MULTAGGR: 5757 SCIPerrorMessage("cannot multi-aggregate a multiple aggregated variable again\n"); 5758 return SCIP_INVALIDDATA; 5759 5760 case SCIP_VARSTATUS_NEGATED: 5761 /* aggregate negation variable x in x' = offset - x, instead of aggregating x' directly: 5762 * x' = a_1*y_1 + ... + a_n*y_n + c -> x = offset - x' = offset - a_1*y_1 - ... - a_n*y_n - c 5763 */ 5764 assert(SCIPsetIsZero(set, var->obj)); 5765 assert(var->negatedvar != NULL); 5766 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 5767 assert(var->negatedvar->negatedvar == var); 5768 5769 /* switch the signs of the aggregation scalars */ 5770 for( v = 0; v < naggvars; ++v ) 5771 scalars[v] *= -1.0; 5772 5773 /* perform the multi aggregation on the negation variable */ 5774 SCIP_CALL( SCIPvarMultiaggregate(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, 5775 cliquetable, branchcand, eventfilter, eventqueue, naggvars, aggvars, scalars, 5776 var->data.negate.constant - constant, infeasible, aggregated) ); 5777 5778 /* switch the signs of the aggregation scalars again, to reset them to their original values */ 5779 for( v = 0; v < naggvars; ++v ) 5780 scalars[v] *= -1.0; 5781 break; 5782 5783 default: 5784 SCIPerrorMessage("unknown variable status\n"); 5785 return SCIP_INVALIDDATA; 5786 } 5787 5788 /* check multi-aggregation on debugging solution */ 5789 if( *infeasible || *aggregated ) 5790 SCIP_CALL( SCIPdebugCheckAggregation(set, var, aggvars, scalars, constant, naggvars) ); /*lint !e506 !e774*/ 5791 5792 return SCIP_OKAY; 5793 } 5794 5795 /** transformed variables are resolved to their active, fixed, or multi-aggregated problem variable of a variable, 5796 * or for original variables the same variable is returned 5797 */ 5798 static 5799 SCIP_VAR* varGetActiveVar( 5800 SCIP_VAR* var /**< problem variable */ 5801 ) 5802 { 5803 SCIP_VAR* retvar; 5804 5805 assert(var != NULL); 5806 5807 retvar = var; 5808 5809 SCIPdebugMessage("get active variable of <%s>\n", var->name); 5810 5811 while( TRUE ) /*lint !e716 */ 5812 { 5813 assert(retvar != NULL); 5814 5815 switch( SCIPvarGetStatus(retvar) ) 5816 { 5817 case SCIP_VARSTATUS_ORIGINAL: 5818 case SCIP_VARSTATUS_LOOSE: 5819 case SCIP_VARSTATUS_COLUMN: 5820 case SCIP_VARSTATUS_FIXED: 5821 return retvar; 5822 5823 case SCIP_VARSTATUS_MULTAGGR: 5824 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */ 5825 if ( retvar->data.multaggr.nvars == 1 ) 5826 retvar = retvar->data.multaggr.vars[0]; 5827 else 5828 return retvar; 5829 break; 5830 5831 case SCIP_VARSTATUS_AGGREGATED: 5832 retvar = retvar->data.aggregate.var; 5833 break; 5834 5835 case SCIP_VARSTATUS_NEGATED: 5836 retvar = retvar->negatedvar; 5837 break; 5838 5839 default: 5840 SCIPerrorMessage("unknown variable status\n"); 5841 SCIPABORT(); 5842 return NULL; /*lint !e527*/ 5843 } 5844 } 5845 } 5846 5847 /** returns whether variable is not allowed to be aggregated */ 5848 SCIP_Bool SCIPvarDoNotAggr( 5849 SCIP_VAR* var /**< problem variable */ 5850 ) 5851 { 5852 SCIP_VAR* retvar; 5853 5854 assert(var != NULL); 5855 5856 retvar = varGetActiveVar(var); 5857 assert(retvar != NULL); 5858 5859 switch( SCIPvarGetStatus(retvar) ) 5860 { 5861 case SCIP_VARSTATUS_ORIGINAL: 5862 case SCIP_VARSTATUS_LOOSE: 5863 case SCIP_VARSTATUS_COLUMN: 5864 case SCIP_VARSTATUS_FIXED: 5865 return retvar->donotaggr; 5866 5867 case SCIP_VARSTATUS_MULTAGGR: 5868 return FALSE; 5869 5870 case SCIP_VARSTATUS_AGGREGATED: 5871 case SCIP_VARSTATUS_NEGATED: 5872 default: 5873 /* aggregated and negated variables should be resolved by varGetActiveVar() */ 5874 SCIPerrorMessage("wrong variable status\n"); 5875 SCIPABORT(); 5876 return FALSE; /*lint !e527 */ 5877 } 5878 } 5879 5880 /** returns whether variable is not allowed to be multi-aggregated */ 5881 SCIP_Bool SCIPvarDoNotMultaggr( 5882 SCIP_VAR* var /**< problem variable */ 5883 ) 5884 { 5885 SCIP_VAR* retvar; 5886 5887 assert(var != NULL); 5888 5889 retvar = varGetActiveVar(var); 5890 assert(retvar != NULL); 5891 5892 switch( SCIPvarGetStatus(retvar) ) 5893 { 5894 case SCIP_VARSTATUS_ORIGINAL: 5895 case SCIP_VARSTATUS_LOOSE: 5896 case SCIP_VARSTATUS_COLUMN: 5897 case SCIP_VARSTATUS_FIXED: 5898 return retvar->donotmultaggr; 5899 5900 case SCIP_VARSTATUS_MULTAGGR: 5901 return FALSE; 5902 5903 case SCIP_VARSTATUS_AGGREGATED: 5904 case SCIP_VARSTATUS_NEGATED: 5905 default: 5906 /* aggregated and negated variables should be resolved by varGetActiveVar() */ 5907 SCIPerrorMessage("wrong variable status\n"); 5908 SCIPABORT(); 5909 return FALSE; /*lint !e527 */ 5910 } 5911 } 5912 5913 /** gets negated variable x' = offset - x of problem variable x; the negated variable is created if not yet existing; 5914 * the negation offset of binary variables is always 1, the offset of other variables is fixed to lb + ub when the 5915 * negated variable is created 5916 */ 5917 SCIP_RETCODE SCIPvarNegate( 5918 SCIP_VAR* var, /**< problem variable to negate */ 5919 BMS_BLKMEM* blkmem, /**< block memory of transformed problem */ 5920 SCIP_SET* set, /**< global SCIP settings */ 5921 SCIP_STAT* stat, /**< problem statistics */ 5922 SCIP_VAR** negvar /**< pointer to store the negated variable */ 5923 ) 5924 { 5925 assert(var != NULL); 5926 assert(var->scip == set->scip); 5927 assert(negvar != NULL); 5928 5929 /* check, if we already created the negated variable */ 5930 if( var->negatedvar == NULL ) 5931 { 5932 char negvarname[SCIP_MAXSTRLEN]; 5933 5934 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED); 5935 5936 SCIPsetDebugMsg(set, "creating negated variable of <%s>\n", var->name); 5937 5938 /* negation is only possible for bounded variables */ 5939 if( SCIPsetIsInfinity(set, -var->glbdom.lb) || SCIPsetIsInfinity(set, var->glbdom.ub) ) 5940 { 5941 SCIPerrorMessage("cannot negate unbounded variable\n"); 5942 return SCIP_INVALIDDATA; 5943 } 5944 5945 (void) SCIPsnprintf(negvarname, SCIP_MAXSTRLEN, "%s_neg", var->name); 5946 5947 /* create negated variable */ 5948 SCIP_CALL( varCreate(negvar, blkmem, set, stat, negvarname, var->glbdom.lb, var->glbdom.ub, 0.0, 5949 SCIPvarGetType(var), var->initial, var->removable, NULL, NULL, NULL, NULL, NULL) ); 5950 (*negvar)->varstatus = SCIP_VARSTATUS_NEGATED; /*lint !e641*/ 5951 if( SCIPvarIsBinary(var) ) 5952 (*negvar)->data.negate.constant = 1.0; 5953 else 5954 (*negvar)->data.negate.constant = var->glbdom.lb + var->glbdom.ub; 5955 5956 /* create event filter for transformed variable */ 5957 if( SCIPvarIsTransformed(var) ) 5958 { 5959 SCIP_CALL( SCIPeventfilterCreate(&(*negvar)->eventfilter, blkmem) ); 5960 } 5961 5962 /* set the bounds corresponding to the negation variable */ 5963 (*negvar)->glbdom.lb = (*negvar)->data.negate.constant - var->glbdom.ub; 5964 (*negvar)->glbdom.ub = (*negvar)->data.negate.constant - var->glbdom.lb; 5965 (*negvar)->locdom.lb = (*negvar)->data.negate.constant - var->locdom.ub; 5966 (*negvar)->locdom.ub = (*negvar)->data.negate.constant - var->locdom.lb; 5967 /**@todo create holes in the negated variable corresponding to the holes of the negation variable */ 5968 5969 /* link the variables together */ 5970 var->negatedvar = *negvar; 5971 (*negvar)->negatedvar = var; 5972 5973 /* mark both variables to be non-deletable */ 5974 SCIPvarMarkNotDeletable(var); 5975 SCIPvarMarkNotDeletable(*negvar); 5976 5977 /* copy the branch factor and priority, and use the negative preferred branching direction */ 5978 (*negvar)->branchfactor = var->branchfactor; 5979 (*negvar)->branchpriority = var->branchpriority; 5980 (*negvar)->branchdirection = SCIPbranchdirOpposite((SCIP_BRANCHDIR)var->branchdirection); /*lint !e641*/ 5981 5982 /* copy donot(mult)aggr status */ 5983 (*negvar)->donotaggr = var->donotaggr; 5984 (*negvar)->donotmultaggr = var->donotmultaggr; 5985 5986 /* copy lazy bounds (they have to be flipped) */ 5987 (*negvar)->lazylb = (*negvar)->data.negate.constant - var->lazyub; 5988 (*negvar)->lazyub = (*negvar)->data.negate.constant - var->lazylb; 5989 5990 /* make negated variable a parent of the negation variable (negated variable is captured as a parent) */ 5991 SCIP_CALL( varAddParent(var, blkmem, set, *negvar) ); 5992 assert((*negvar)->nuses == 1); 5993 } 5994 assert(var->negatedvar != NULL); 5995 5996 /* return the negated variable */ 5997 *negvar = var->negatedvar; 5998 5999 /* exactly one variable of the negation pair has to be marked as negated variable */ 6000 assert((SCIPvarGetStatus(*negvar) == SCIP_VARSTATUS_NEGATED) != (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED)); 6001 6002 return SCIP_OKAY; 6003 } 6004 6005 /** informs variable that its position in problem's vars array changed */ 6006 static 6007 void varSetProbindex( 6008 SCIP_VAR* var, /**< problem variable */ 6009 int probindex /**< new problem index of variable (-1 for removal) */ 6010 ) 6011 { 6012 assert(var != NULL); 6013 assert(probindex >= 0 || var->vlbs == NULL); 6014 assert(probindex >= 0 || var->vubs == NULL); 6015 assert(probindex >= 0 || var->implics == NULL); 6016 6017 var->probindex = probindex; 6018 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 6019 { 6020 assert(var->data.col != NULL); 6021 var->data.col->var_probindex = probindex; 6022 } 6023 } 6024 6025 /** informs variable that its position in problem's vars array changed */ 6026 void SCIPvarSetProbindex( 6027 SCIP_VAR* var, /**< problem variable */ 6028 int probindex /**< new problem index of variable */ 6029 ) 6030 { 6031 assert(var != NULL); 6032 assert(probindex >= 0); 6033 6034 varSetProbindex(var, probindex); 6035 } 6036 6037 /** gives the variable a new name 6038 * 6039 * @note the old pointer is overwritten, which might result in a memory leakage 6040 */ 6041 void SCIPvarSetNamePointer( 6042 SCIP_VAR* var, /**< problem variable */ 6043 const char* name /**< new name of variable */ 6044 ) 6045 { 6046 assert(var != NULL); 6047 assert(name != NULL); 6048 6049 var->name = (char*)name; 6050 } 6051 6052 /** informs variable that it will be removed from the problem; adjusts probindex and removes variable from the 6053 * implication graph; 6054 * If 'final' is TRUE, the thorough implication graph removal is not performed. Instead, only the 6055 * variable bounds and implication data structures of the variable are freed. Since in the final removal 6056 * of all variables from the transformed problem, this deletes the implication graph completely and is faster 6057 * than removing the variables one by one, each time updating all lists of the other variables. 6058 */ 6059 SCIP_RETCODE SCIPvarRemove( 6060 SCIP_VAR* var, /**< problem variable */ 6061 BMS_BLKMEM* blkmem, /**< block memory buffer */ 6062 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 6063 SCIP_SET* set, /**< global SCIP settings */ 6064 SCIP_Bool final /**< is this the final removal of all problem variables? */ 6065 ) 6066 { 6067 assert(SCIPvarGetProbindex(var) >= 0); 6068 assert(var->scip == set->scip); 6069 6070 /* if the variable is active in the transformed problem, remove it from the implication graph */ 6071 if( SCIPvarIsTransformed(var) 6072 && (SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN) ) 6073 { 6074 if( final ) 6075 { 6076 /* just destroy the data structures */ 6077 SCIPvboundsFree(&var->vlbs, blkmem); 6078 SCIPvboundsFree(&var->vubs, blkmem); 6079 SCIPimplicsFree(&var->implics, blkmem); 6080 } 6081 else 6082 { 6083 /* unlink the variable from all other variables' lists and free the data structures */ 6084 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) ); 6085 } 6086 } 6087 6088 /* mark the variable to be no longer a member of the problem */ 6089 varSetProbindex(var, -1); 6090 6091 return SCIP_OKAY; 6092 } 6093 6094 /** marks the variable to be deleted from the problem */ 6095 void SCIPvarMarkDeleted( 6096 SCIP_VAR* var /**< problem variable */ 6097 ) 6098 { 6099 assert(var != NULL); 6100 assert(var->probindex != -1); 6101 6102 var->deleted = TRUE; 6103 } 6104 6105 /** marks the variable to not to be aggregated */ 6106 SCIP_RETCODE SCIPvarMarkDoNotAggr( 6107 SCIP_VAR* var /**< problem variable */ 6108 ) 6109 { 6110 SCIP_VAR* retvar; 6111 6112 assert(var != NULL); 6113 6114 retvar = varGetActiveVar(var); 6115 assert(retvar != NULL); 6116 6117 switch( SCIPvarGetStatus(retvar) ) 6118 { 6119 case SCIP_VARSTATUS_ORIGINAL: 6120 case SCIP_VARSTATUS_LOOSE: 6121 case SCIP_VARSTATUS_COLUMN: 6122 case SCIP_VARSTATUS_FIXED: 6123 retvar->donotaggr = TRUE; 6124 break; 6125 6126 case SCIP_VARSTATUS_MULTAGGR: 6127 SCIPerrorMessage("cannot mark a multi-aggregated variable to not be aggregated.\n"); 6128 return SCIP_INVALIDDATA; 6129 6130 case SCIP_VARSTATUS_AGGREGATED: 6131 case SCIP_VARSTATUS_NEGATED: 6132 default: 6133 /* aggregated and negated variables should be resolved by varGetActiveVar() */ 6134 SCIPerrorMessage("wrong variable status\n"); 6135 return SCIP_INVALIDDATA; 6136 } 6137 6138 return SCIP_OKAY; 6139 } 6140 6141 /** marks the variable to not to be multi-aggregated */ 6142 SCIP_RETCODE SCIPvarMarkDoNotMultaggr( 6143 SCIP_VAR* var /**< problem variable */ 6144 ) 6145 { 6146 SCIP_VAR* retvar; 6147 6148 assert(var != NULL); 6149 6150 retvar = varGetActiveVar(var); 6151 assert(retvar != NULL); 6152 6153 switch( SCIPvarGetStatus(retvar) ) 6154 { 6155 case SCIP_VARSTATUS_ORIGINAL: 6156 case SCIP_VARSTATUS_LOOSE: 6157 case SCIP_VARSTATUS_COLUMN: 6158 case SCIP_VARSTATUS_FIXED: 6159 retvar->donotmultaggr = TRUE; 6160 break; 6161 6162 case SCIP_VARSTATUS_MULTAGGR: 6163 SCIPerrorMessage("cannot mark a multi-aggregated variable to not be multi-aggregated.\n"); 6164 return SCIP_INVALIDDATA; 6165 6166 case SCIP_VARSTATUS_AGGREGATED: 6167 case SCIP_VARSTATUS_NEGATED: 6168 default: 6169 /* aggregated and negated variables should be resolved by varGetActiveVar() */ 6170 SCIPerrorMessage("wrong variable status\n"); 6171 return SCIP_INVALIDDATA; 6172 } 6173 6174 return SCIP_OKAY; 6175 } 6176 6177 /** changes type of variable; cannot be called, if var belongs to a problem */ 6178 SCIP_RETCODE SCIPvarChgType( 6179 SCIP_VAR* var, /**< problem variable to change */ 6180 BMS_BLKMEM* blkmem, /**< block memory */ 6181 SCIP_SET* set, /**< global SCIP settings */ 6182 SCIP_PRIMAL* primal, /**< primal data */ 6183 SCIP_LP* lp, /**< current LP data */ 6184 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 6185 SCIP_VARTYPE vartype /**< new type of variable */ 6186 ) 6187 { 6188 SCIP_EVENT* event; 6189 SCIP_VARTYPE oldtype; 6190 6191 assert(var != NULL); 6192 6193 SCIPdebugMessage("change type of <%s> from %d to %d\n", var->name, SCIPvarGetType(var), vartype); 6194 6195 if( var->probindex >= 0 ) 6196 { 6197 SCIPerrorMessage("cannot change type of variable already in the problem\n"); 6198 return SCIP_INVALIDDATA; 6199 } 6200 6201 oldtype = (SCIP_VARTYPE)var->vartype; 6202 var->vartype = vartype; /*lint !e641*/ 6203 6204 if( SCIPsetGetStage(set) > SCIP_STAGE_TRANSFORMING ) 6205 { 6206 SCIP_CALL( SCIPeventCreateTypeChanged(&event, blkmem, var, oldtype, vartype) ); 6207 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) ); 6208 } 6209 6210 if( var->negatedvar != NULL ) 6211 { 6212 assert(oldtype == (SCIP_VARTYPE)var->negatedvar->vartype 6213 || SCIPvarIsBinary(var) == SCIPvarIsBinary(var->negatedvar)); 6214 6215 var->negatedvar->vartype = vartype; /*lint !e641*/ 6216 6217 if( SCIPsetGetStage(set) > SCIP_STAGE_TRANSFORMING ) 6218 { 6219 SCIP_CALL( SCIPeventCreateTypeChanged(&event, blkmem, var->negatedvar, oldtype, vartype) ); 6220 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) ); 6221 } 6222 } 6223 6224 return SCIP_OKAY; 6225 } 6226 6227 /** appends OBJCHANGED event to the event queue */ 6228 static 6229 SCIP_RETCODE varEventObjChanged( 6230 SCIP_VAR* var, /**< problem variable to change */ 6231 BMS_BLKMEM* blkmem, /**< block memory */ 6232 SCIP_SET* set, /**< global SCIP settings */ 6233 SCIP_PRIMAL* primal, /**< primal data */ 6234 SCIP_LP* lp, /**< current LP data */ 6235 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 6236 SCIP_Real oldobj, /**< old objective value for variable */ 6237 SCIP_Real newobj /**< new objective value for variable */ 6238 ) 6239 { 6240 SCIP_EVENT* event; 6241 6242 assert(var != NULL); 6243 assert(var->scip == set->scip); 6244 assert(var->eventfilter != NULL); 6245 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); 6246 assert(SCIPvarIsTransformed(var)); 6247 6248 /* In the case where the objcetive value of a variable is very close to epsilon, and it is aggregated 6249 * into a variable with a big objective value, round-off errors might make the assert oldobj != newobj fail. 6250 * Hence, we relax it by letting it pass if the variables are percieved the same and we use very large values 6251 * that make comparison with values close to epsilon inaccurate. 6252 */ 6253 assert(!SCIPsetIsEQ(set, oldobj, newobj) || 6254 (SCIPsetIsEQ(set, oldobj, newobj) && REALABS(newobj) > 1e+15 * SCIPsetEpsilon(set)) 6255 ); 6256 6257 SCIP_CALL( SCIPeventCreateObjChanged(&event, blkmem, var, oldobj, newobj) ); 6258 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) ); 6259 6260 return SCIP_OKAY; 6261 } 6262 6263 /** changes objective value of variable */ 6264 SCIP_RETCODE SCIPvarChgObj( 6265 SCIP_VAR* var, /**< variable to change */ 6266 BMS_BLKMEM* blkmem, /**< block memory */ 6267 SCIP_SET* set, /**< global SCIP settings */ 6268 SCIP_PROB* prob, /**< problem data */ 6269 SCIP_PRIMAL* primal, /**< primal data */ 6270 SCIP_LP* lp, /**< current LP data */ 6271 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 6272 SCIP_Real newobj /**< new objective value for variable */ 6273 ) 6274 { 6275 SCIP_Real oldobj; 6276 6277 assert(var != NULL); 6278 assert(set != NULL); 6279 assert(var->scip == set->scip); 6280 6281 SCIPsetDebugMsg(set, "changing objective value of <%s> from %g to %g\n", var->name, var->obj, newobj); 6282 6283 if( !SCIPsetIsEQ(set, var->obj, newobj) ) 6284 { 6285 switch( SCIPvarGetStatus(var) ) 6286 { 6287 case SCIP_VARSTATUS_ORIGINAL: 6288 if( var->data.original.transvar != NULL ) 6289 { 6290 assert(SCIPprobIsTransformed(prob)); 6291 6292 SCIP_CALL( SCIPvarChgObj(var->data.original.transvar, blkmem, set, prob, primal, lp, eventqueue, 6293 (SCIP_Real) prob->objsense * newobj/prob->objscale) ); 6294 } 6295 else 6296 assert(set->stage == SCIP_STAGE_PROBLEM); 6297 6298 var->obj = newobj; 6299 var->unchangedobj = newobj; 6300 6301 break; 6302 6303 case SCIP_VARSTATUS_LOOSE: 6304 case SCIP_VARSTATUS_COLUMN: 6305 oldobj = var->obj; 6306 var->obj = newobj; 6307 6308 /* update unchanged objective value of variable */ 6309 if( !lp->divingobjchg ) 6310 var->unchangedobj = newobj; 6311 6312 /* update the number of variables with non-zero objective coefficient; 6313 * we only want to do the update, if the variable is added to the problem; 6314 * since the objective of inactive variables cannot be changed, this corresponds to probindex != -1 6315 */ 6316 if( SCIPvarIsActive(var) ) 6317 SCIPprobUpdateNObjVars(prob, set, oldobj, var->obj); 6318 6319 SCIP_CALL( varEventObjChanged(var, blkmem, set, primal, lp, eventqueue, oldobj, var->obj) ); 6320 break; 6321 6322 case SCIP_VARSTATUS_FIXED: 6323 case SCIP_VARSTATUS_AGGREGATED: 6324 case SCIP_VARSTATUS_MULTAGGR: 6325 case SCIP_VARSTATUS_NEGATED: 6326 SCIPerrorMessage("cannot change objective value of a fixed, aggregated, multi-aggregated, or negated variable\n"); 6327 return SCIP_INVALIDDATA; 6328 6329 default: 6330 SCIPerrorMessage("unknown variable status\n"); 6331 return SCIP_INVALIDDATA; 6332 } 6333 } 6334 6335 return SCIP_OKAY; 6336 } 6337 6338 /** adds value to objective value of variable */ 6339 SCIP_RETCODE SCIPvarAddObj( 6340 SCIP_VAR* var, /**< variable to change */ 6341 BMS_BLKMEM* blkmem, /**< block memory */ 6342 SCIP_SET* set, /**< global SCIP settings */ 6343 SCIP_STAT* stat, /**< problem statistics */ 6344 SCIP_PROB* transprob, /**< transformed problem data */ 6345 SCIP_PROB* origprob, /**< original problem data */ 6346 SCIP_PRIMAL* primal, /**< primal data */ 6347 SCIP_TREE* tree, /**< branch and bound tree */ 6348 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6349 SCIP_LP* lp, /**< current LP data */ 6350 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 6351 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 6352 SCIP_Real addobj /**< additional objective value for variable */ 6353 ) 6354 { 6355 assert(var != NULL); 6356 assert(set != NULL); 6357 assert(var->scip == set->scip); 6358 assert(set->stage < SCIP_STAGE_INITSOLVE); 6359 6360 SCIPsetDebugMsg(set, "adding %g to objective value %g of <%s>\n", addobj, var->obj, var->name); 6361 6362 if( !SCIPsetIsZero(set, addobj) ) 6363 { 6364 SCIP_Real oldobj; 6365 int i; 6366 6367 switch( SCIPvarGetStatus(var) ) 6368 { 6369 case SCIP_VARSTATUS_ORIGINAL: 6370 if( var->data.original.transvar != NULL ) 6371 { 6372 SCIP_CALL( SCIPvarAddObj(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree, 6373 reopt, lp, eventfilter, eventqueue, (SCIP_Real) transprob->objsense * addobj/transprob->objscale) ); 6374 } 6375 else 6376 assert(set->stage == SCIP_STAGE_PROBLEM); 6377 6378 var->obj += addobj; 6379 var->unchangedobj += addobj; 6380 assert(SCIPsetIsEQ(set, var->obj, var->unchangedobj)); 6381 6382 break; 6383 6384 case SCIP_VARSTATUS_LOOSE: 6385 case SCIP_VARSTATUS_COLUMN: 6386 oldobj = var->obj; 6387 var->obj += addobj; 6388 6389 /* update unchanged objective value of variable */ 6390 if( !lp->divingobjchg ) 6391 { 6392 var->unchangedobj += addobj; 6393 assert(SCIPsetIsEQ(set, var->obj, var->unchangedobj)); 6394 } 6395 6396 /* update the number of variables with non-zero objective coefficient; 6397 * we only want to do the update, if the variable is added to the problem; 6398 * since the objective of inactive variables cannot be changed, this corresponds to probindex != -1 6399 */ 6400 if( SCIPvarIsActive(var) ) 6401 SCIPprobUpdateNObjVars(transprob, set, oldobj, var->obj); 6402 6403 SCIP_CALL( varEventObjChanged(var, blkmem, set, primal, lp, eventqueue, oldobj, var->obj) ); 6404 break; 6405 6406 case SCIP_VARSTATUS_FIXED: 6407 assert(SCIPsetIsEQ(set, var->locdom.lb, var->locdom.ub)); 6408 SCIPprobAddObjoffset(transprob, var->locdom.lb * addobj); 6409 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) ); 6410 break; 6411 6412 case SCIP_VARSTATUS_AGGREGATED: 6413 assert(!var->donotaggr); 6414 /* x = a*y + c -> add a*addobj to obj. val. of y, and c*addobj to obj. offset of problem */ 6415 SCIPprobAddObjoffset(transprob, var->data.aggregate.constant * addobj); 6416 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) ); 6417 SCIP_CALL( SCIPvarAddObj(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, 6418 lp, eventfilter, eventqueue, var->data.aggregate.scalar * addobj) ); 6419 break; 6420 6421 case SCIP_VARSTATUS_MULTAGGR: 6422 assert(!var->donotmultaggr); 6423 /* x = a_1*y_1 + ... + a_n*y_n + c -> add a_i*addobj to obj. val. of y_i, and c*addobj to obj. offset */ 6424 SCIPprobAddObjoffset(transprob, var->data.multaggr.constant * addobj); 6425 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) ); 6426 for( i = 0; i < var->data.multaggr.nvars; ++i ) 6427 { 6428 SCIP_CALL( SCIPvarAddObj(var->data.multaggr.vars[i], blkmem, set, stat, transprob, origprob, primal, tree, 6429 reopt, lp, eventfilter, eventqueue, var->data.multaggr.scalars[i] * addobj) ); 6430 } 6431 break; 6432 6433 case SCIP_VARSTATUS_NEGATED: 6434 /* x' = offset - x -> add -addobj to obj. val. of x and offset*addobj to obj. offset of problem */ 6435 assert(var->negatedvar != NULL); 6436 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 6437 assert(var->negatedvar->negatedvar == var); 6438 SCIPprobAddObjoffset(transprob, var->data.negate.constant * addobj); 6439 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) ); 6440 SCIP_CALL( SCIPvarAddObj(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, 6441 eventfilter, eventqueue, -addobj) ); 6442 break; 6443 6444 default: 6445 SCIPerrorMessage("unknown variable status\n"); 6446 return SCIP_INVALIDDATA; 6447 } 6448 } 6449 6450 return SCIP_OKAY; 6451 } 6452 6453 /** changes objective value of variable in current dive */ 6454 SCIP_RETCODE SCIPvarChgObjDive( 6455 SCIP_VAR* var, /**< problem variable to change */ 6456 SCIP_SET* set, /**< global SCIP settings */ 6457 SCIP_LP* lp, /**< current LP data */ 6458 SCIP_Real newobj /**< new objective value for variable */ 6459 ) 6460 { 6461 assert(var != NULL); 6462 assert(set != NULL); 6463 assert(var->scip == set->scip); 6464 assert(lp != NULL); 6465 6466 SCIPsetDebugMsg(set, "changing objective of <%s> to %g in current dive\n", var->name, newobj); 6467 6468 if( SCIPsetIsZero(set, newobj) ) 6469 newobj = 0.0; 6470 6471 /* change objective value of attached variables */ 6472 switch( SCIPvarGetStatus(var) ) 6473 { 6474 case SCIP_VARSTATUS_ORIGINAL: 6475 assert(var->data.original.transvar != NULL); 6476 SCIP_CALL( SCIPvarChgObjDive(var->data.original.transvar, set, lp, newobj) ); 6477 break; 6478 6479 case SCIP_VARSTATUS_COLUMN: 6480 assert(var->data.col != NULL); 6481 SCIP_CALL( SCIPcolChgObj(var->data.col, set, lp, newobj) ); 6482 break; 6483 6484 case SCIP_VARSTATUS_LOOSE: 6485 case SCIP_VARSTATUS_FIXED: 6486 /* nothing to do here: only the constant shift in objective function would change */ 6487 break; 6488 6489 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 6490 assert(var->data.aggregate.var != NULL); 6491 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar)); 6492 SCIP_CALL( SCIPvarChgObjDive(var->data.aggregate.var, set, lp, newobj / var->data.aggregate.scalar) ); 6493 /* the constant can be ignored, because it would only affect the objective shift */ 6494 break; 6495 6496 case SCIP_VARSTATUS_MULTAGGR: 6497 SCIPerrorMessage("cannot change diving objective value of a multi-aggregated variable\n"); 6498 return SCIP_INVALIDDATA; 6499 6500 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 6501 assert(var->negatedvar != NULL); 6502 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 6503 assert(var->negatedvar->negatedvar == var); 6504 SCIP_CALL( SCIPvarChgObjDive(var->negatedvar, set, lp, -newobj) ); 6505 /* the offset can be ignored, because it would only affect the objective shift */ 6506 break; 6507 6508 default: 6509 SCIPerrorMessage("unknown variable status\n"); 6510 return SCIP_INVALIDDATA; 6511 } 6512 6513 return SCIP_OKAY; 6514 } 6515 6516 /** adjust lower bound to integral value, if variable is integral */ 6517 void SCIPvarAdjustLb( 6518 SCIP_VAR* var, /**< problem variable */ 6519 SCIP_SET* set, /**< global SCIP settings */ 6520 SCIP_Real* lb /**< pointer to lower bound to adjust */ 6521 ) 6522 { 6523 assert(var != NULL); 6524 assert(set != NULL); 6525 assert(var->scip == set->scip); 6526 assert(lb != NULL); 6527 6528 SCIPsetDebugMsg(set, "adjust lower bound %g of <%s>\n", *lb, var->name); 6529 6530 *lb = adjustedLb(set, SCIPvarGetType(var), *lb); 6531 } 6532 6533 /** adjust upper bound to integral value, if variable is integral */ 6534 void SCIPvarAdjustUb( 6535 SCIP_VAR* var, /**< problem variable */ 6536 SCIP_SET* set, /**< global SCIP settings */ 6537 SCIP_Real* ub /**< pointer to upper bound to adjust */ 6538 ) 6539 { 6540 assert(var != NULL); 6541 assert(set != NULL); 6542 assert(var->scip == set->scip); 6543 assert(ub != NULL); 6544 6545 SCIPsetDebugMsg(set, "adjust upper bound %g of <%s>\n", *ub, var->name); 6546 6547 *ub = adjustedUb(set, SCIPvarGetType(var), *ub); 6548 } 6549 6550 /** adjust lower or upper bound to integral value, if variable is integral */ 6551 void SCIPvarAdjustBd( 6552 SCIP_VAR* var, /**< problem variable */ 6553 SCIP_SET* set, /**< global SCIP settings */ 6554 SCIP_BOUNDTYPE boundtype, /**< type of bound to adjust */ 6555 SCIP_Real* bd /**< pointer to bound to adjust */ 6556 ) 6557 { 6558 assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER); 6559 6560 if( boundtype == SCIP_BOUNDTYPE_LOWER ) 6561 SCIPvarAdjustLb(var, set, bd); 6562 else 6563 SCIPvarAdjustUb(var, set, bd); 6564 } 6565 6566 /** changes lower bound of original variable in original problem */ 6567 SCIP_RETCODE SCIPvarChgLbOriginal( 6568 SCIP_VAR* var, /**< problem variable to change */ 6569 SCIP_SET* set, /**< global SCIP settings */ 6570 SCIP_Real newbound /**< new bound for variable */ 6571 ) 6572 { 6573 int i; 6574 6575 assert(var != NULL); 6576 assert(!SCIPvarIsTransformed(var)); 6577 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED); 6578 assert(set != NULL); 6579 assert(var->scip == set->scip); 6580 assert(set->stage == SCIP_STAGE_PROBLEM); 6581 6582 /* check that the bound is feasible */ 6583 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsLE(set, newbound, SCIPvarGetUbOriginal(var))); 6584 /* adjust bound to integral value if variable is of integral type */ 6585 newbound = adjustedLb(set, SCIPvarGetType(var), newbound); 6586 6587 if( SCIPsetIsZero(set, newbound) ) 6588 newbound = 0.0; 6589 6590 /* original domains are only stored for ORIGINAL variables, not for NEGATED */ 6591 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL ) 6592 { 6593 SCIPsetDebugMsg(set, "changing original lower bound of <%s> from %g to %g\n", 6594 var->name, var->data.original.origdom.lb, newbound); 6595 6596 if( SCIPsetIsEQ(set, var->data.original.origdom.lb, newbound) ) 6597 return SCIP_OKAY; 6598 6599 /* change the bound */ 6600 var->data.original.origdom.lb = newbound; 6601 } 6602 else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED ) 6603 { 6604 assert( var->negatedvar != NULL ); 6605 SCIP_CALL( SCIPvarChgUbOriginal(var->negatedvar, set, var->data.negate.constant - newbound) ); 6606 } 6607 6608 /* process parent variables */ 6609 for( i = 0; i < var->nparentvars; ++i ) 6610 { 6611 SCIP_VAR* parentvar; 6612 6613 parentvar = var->parentvars[i]; 6614 assert(parentvar != NULL); 6615 assert(SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_NEGATED); 6616 assert(parentvar->negatedvar == var); 6617 assert(var->negatedvar == parentvar); 6618 6619 SCIP_CALL( SCIPvarChgUbOriginal(parentvar, set, parentvar->data.negate.constant - newbound) ); 6620 } 6621 6622 return SCIP_OKAY; 6623 } 6624 6625 /** changes upper bound of original variable in original problem */ 6626 SCIP_RETCODE SCIPvarChgUbOriginal( 6627 SCIP_VAR* var, /**< problem variable to change */ 6628 SCIP_SET* set, /**< global SCIP settings */ 6629 SCIP_Real newbound /**< new bound for variable */ 6630 ) 6631 { 6632 int i; 6633 6634 assert(var != NULL); 6635 assert(!SCIPvarIsTransformed(var)); 6636 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED); 6637 assert(set != NULL); 6638 assert(var->scip == set->scip); 6639 assert(set->stage == SCIP_STAGE_PROBLEM); 6640 6641 /* check that the bound is feasible */ 6642 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsGE(set, newbound, SCIPvarGetLbOriginal(var))); 6643 /* adjust bound to integral value if variable is of integral type */ 6644 newbound = adjustedUb(set, SCIPvarGetType(var), newbound); 6645 6646 if( SCIPsetIsZero(set, newbound) ) 6647 newbound = 0.0; 6648 6649 /* original domains are only stored for ORIGINAL variables, not for NEGATED */ 6650 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL ) 6651 { 6652 SCIPsetDebugMsg(set, "changing original upper bound of <%s> from %g to %g\n", 6653 var->name, var->data.original.origdom.ub, newbound); 6654 6655 if( SCIPsetIsEQ(set, var->data.original.origdom.ub, newbound) ) 6656 return SCIP_OKAY; 6657 6658 /* change the bound */ 6659 var->data.original.origdom.ub = newbound; 6660 } 6661 else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED ) 6662 { 6663 assert( var->negatedvar != NULL ); 6664 SCIP_CALL( SCIPvarChgLbOriginal(var->negatedvar, set, var->data.negate.constant - newbound) ); 6665 } 6666 6667 /* process parent variables */ 6668 for( i = 0; i < var->nparentvars; ++i ) 6669 { 6670 SCIP_VAR* parentvar; 6671 6672 parentvar = var->parentvars[i]; 6673 assert(parentvar != NULL); 6674 assert(SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_NEGATED); 6675 assert(parentvar->negatedvar == var); 6676 assert(var->negatedvar == parentvar); 6677 6678 SCIP_CALL( SCIPvarChgLbOriginal(parentvar, set, parentvar->data.negate.constant - newbound) ); 6679 } 6680 6681 return SCIP_OKAY; 6682 } 6683 6684 /** appends GLBCHANGED event to the event queue */ 6685 static 6686 SCIP_RETCODE varEventGlbChanged( 6687 SCIP_VAR* var, /**< problem variable to change */ 6688 BMS_BLKMEM* blkmem, /**< block memory */ 6689 SCIP_SET* set, /**< global SCIP settings */ 6690 SCIP_LP* lp, /**< current LP data */ 6691 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 6692 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 6693 SCIP_Real oldbound, /**< old lower bound for variable */ 6694 SCIP_Real newbound /**< new lower bound for variable */ 6695 ) 6696 { 6697 assert(var != NULL); 6698 assert(var->eventfilter != NULL); 6699 assert(SCIPvarIsTransformed(var)); 6700 assert(!SCIPsetIsEQ(set, oldbound, newbound) || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/ 6701 assert(set != NULL); 6702 assert(var->scip == set->scip); 6703 6704 /* check, if the variable is being tracked for bound changes 6705 * COLUMN and LOOSE variables are tracked always, because global/root pseudo objective value has to be updated 6706 */ 6707 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GLBCHANGED) != 0) 6708 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN 6709 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE ) 6710 { 6711 SCIP_EVENT* event; 6712 6713 SCIPsetDebugMsg(set, "issue GLBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound); 6714 6715 SCIP_CALL( SCIPeventCreateGlbChanged(&event, blkmem, var, oldbound, newbound) ); 6716 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) ); 6717 } 6718 6719 return SCIP_OKAY; 6720 } 6721 6722 /** appends GUBCHANGED event to the event queue */ 6723 static 6724 SCIP_RETCODE varEventGubChanged( 6725 SCIP_VAR* var, /**< problem variable to change */ 6726 BMS_BLKMEM* blkmem, /**< block memory */ 6727 SCIP_SET* set, /**< global SCIP settings */ 6728 SCIP_LP* lp, /**< current LP data */ 6729 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 6730 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 6731 SCIP_Real oldbound, /**< old lower bound for variable */ 6732 SCIP_Real newbound /**< new lower bound for variable */ 6733 ) 6734 { 6735 assert(var != NULL); 6736 assert(var->eventfilter != NULL); 6737 assert(SCIPvarIsTransformed(var)); 6738 assert(!SCIPsetIsEQ(set, oldbound, newbound) || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/ 6739 assert(set != NULL); 6740 assert(var->scip == set->scip); 6741 6742 /* check, if the variable is being tracked for bound changes 6743 * COLUMN and LOOSE variables are tracked always, because global/root pseudo objective value has to be updated 6744 */ 6745 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GUBCHANGED) != 0) 6746 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN 6747 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE ) 6748 { 6749 SCIP_EVENT* event; 6750 6751 SCIPsetDebugMsg(set, "issue GUBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound); 6752 6753 SCIP_CALL( SCIPeventCreateGubChanged(&event, blkmem, var, oldbound, newbound) ); 6754 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) ); 6755 } 6756 6757 return SCIP_OKAY; 6758 } 6759 6760 /** appends GHOLEADDED event to the event queue */ 6761 static 6762 SCIP_RETCODE varEventGholeAdded( 6763 SCIP_VAR* var, /**< problem variable to change */ 6764 BMS_BLKMEM* blkmem, /**< block memory */ 6765 SCIP_SET* set, /**< global SCIP settings */ 6766 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 6767 SCIP_Real left, /**< left bound of open interval in new hole */ 6768 SCIP_Real right /**< right bound of open interval in new hole */ 6769 ) 6770 { 6771 assert(var != NULL); 6772 assert(var->eventfilter != NULL); 6773 assert(SCIPvarIsTransformed(var)); 6774 assert(set != NULL); 6775 assert(var->scip == set->scip); 6776 assert(SCIPsetIsLT(set, left, right)); 6777 6778 /* check, if the variable is being tracked for bound changes */ 6779 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GHOLEADDED) != 0) ) 6780 { 6781 SCIP_EVENT* event; 6782 6783 SCIPsetDebugMsg(set, "issue GHOLEADDED event for variable <%s>: (%.15g,%.15g)\n", var->name, left, right); 6784 6785 SCIP_CALL( SCIPeventCreateGholeAdded(&event, blkmem, var, left, right) ); 6786 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) ); 6787 } 6788 6789 return SCIP_OKAY; 6790 } 6791 6792 /** increases root bound change statistics after a global bound change */ 6793 static 6794 void varIncRootboundchgs( 6795 SCIP_VAR* var, /**< problem variable to change */ 6796 SCIP_SET* set, /**< global SCIP settings */ 6797 SCIP_STAT* stat /**< problem statistics */ 6798 ) 6799 { 6800 assert(var != NULL); 6801 assert(set != NULL); 6802 assert(var->scip == set->scip); 6803 assert(stat != NULL); 6804 6805 if( SCIPvarIsActive(var) && SCIPvarIsTransformed(var) && set->stage == SCIP_STAGE_SOLVING ) 6806 { 6807 stat->nrootboundchgs++; 6808 stat->nrootboundchgsrun++; 6809 if( SCIPvarIsIntegral(var) && SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) ) 6810 { 6811 stat->nrootintfixings++; 6812 stat->nrootintfixingsrun++; 6813 } 6814 } 6815 } 6816 6817 /* forward declaration, because both methods call each other recursively */ 6818 6819 /* performs the current change in upper bound, changes all parents accordingly */ 6820 static 6821 SCIP_RETCODE varProcessChgUbGlobal( 6822 SCIP_VAR* var, /**< problem variable to change */ 6823 BMS_BLKMEM* blkmem, /**< block memory */ 6824 SCIP_SET* set, /**< global SCIP settings */ 6825 SCIP_STAT* stat, /**< problem statistics */ 6826 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 6827 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 6828 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 6829 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 6830 SCIP_Real newbound /**< new bound for variable */ 6831 ); 6832 6833 /** performs the current change in lower bound, changes all parents accordingly */ 6834 static 6835 SCIP_RETCODE varProcessChgLbGlobal( 6836 SCIP_VAR* var, /**< problem variable to change */ 6837 BMS_BLKMEM* blkmem, /**< block memory */ 6838 SCIP_SET* set, /**< global SCIP settings */ 6839 SCIP_STAT* stat, /**< problem statistics */ 6840 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 6841 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 6842 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 6843 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 6844 SCIP_Real newbound /**< new bound for variable */ 6845 ) 6846 { 6847 SCIP_VAR* parentvar; 6848 SCIP_Real oldbound; 6849 int i; 6850 6851 assert(var != NULL); 6852 /* local domains can violate global bounds but not more than feasibility epsilon */ 6853 assert(SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb)); 6854 assert(SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub)); 6855 assert(blkmem != NULL); 6856 assert(set != NULL); 6857 assert(var->scip == set->scip); 6858 assert(stat != NULL); 6859 6860 /* adjust bound to integral value if variable is of integral type */ 6861 newbound = adjustedLb(set, SCIPvarGetType(var), newbound); 6862 6863 /* check that the bound is feasible */ 6864 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM && newbound > var->glbdom.ub ) 6865 { 6866 /* due to numerics we only want to be feasible in feasibility tolerance */ 6867 assert(SCIPsetIsFeasLE(set, newbound, var->glbdom.ub)); 6868 newbound = var->glbdom.ub; 6869 } 6870 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 6871 6872 assert(var->vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, newbound, 0.0) || SCIPsetIsEQ(set, newbound, 1.0)); /*lint !e641*/ 6873 6874 SCIPsetDebugMsg(set, "process changing global lower bound of <%s> from %f to %f\n", var->name, var->glbdom.lb, newbound); 6875 6876 if( SCIPsetIsEQ(set, newbound, var->glbdom.lb) && !(newbound != var->glbdom.lb && newbound * var->glbdom.lb <= 0.0) ) /*lint !e777*/ 6877 return SCIP_OKAY; 6878 6879 /* check bound on debugging solution */ 6880 SCIP_CALL( SCIPdebugCheckLbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/ 6881 6882 /* change the bound */ 6883 oldbound = var->glbdom.lb; 6884 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasLE(set, newbound, var->glbdom.ub)); 6885 var->glbdom.lb = newbound; 6886 assert( SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb) ); 6887 assert( SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub) ); 6888 6889 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM ) 6890 { 6891 /* merges overlapping holes into single holes, moves bounds respectively */ 6892 domMerge(&var->glbdom, blkmem, set, &newbound, NULL); 6893 } 6894 6895 /* update the root bound changes counters */ 6896 varIncRootboundchgs(var, set, stat); 6897 6898 /* update the lbchginfos array by replacing worse local bounds with the new global bound and changing the 6899 * redundant bound changes to be branching decisions 6900 */ 6901 for( i = 0; i < var->nlbchginfos; ++i ) 6902 { 6903 assert(var->lbchginfos[i].var == var); 6904 6905 if( var->lbchginfos[i].oldbound < var->glbdom.lb ) 6906 { 6907 SCIPsetDebugMsg(set, " -> adjust lower bound change <%s>: %g -> %g due to new global lower bound %g\n", 6908 SCIPvarGetName(var), var->lbchginfos[i].oldbound, var->lbchginfos[i].newbound, var->glbdom.lb); 6909 var->lbchginfos[i].oldbound = var->glbdom.lb; 6910 if( SCIPsetIsLE(set, var->lbchginfos[i].newbound, var->glbdom.lb) ) 6911 { 6912 /* this bound change is redundant due to the new global bound */ 6913 var->lbchginfos[i].newbound = var->glbdom.lb; 6914 var->lbchginfos[i].boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/ 6915 var->lbchginfos[i].redundant = TRUE; 6916 } 6917 else 6918 break; /* from now on, the remaining local bound changes are not redundant */ 6919 } 6920 else 6921 break; /* from now on, the remaining local bound changes are not redundant */ 6922 } 6923 6924 /* remove redundant implications and variable bounds */ 6925 if( (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE) 6926 && (!set->reopt_enable || set->stage == SCIP_STAGE_PRESOLVING) ) 6927 { 6928 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, TRUE, TRUE) ); 6929 } 6930 6931 /* issue bound change event */ 6932 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL)); 6933 if( var->eventfilter != NULL ) 6934 { 6935 SCIP_CALL( varEventGlbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) ); 6936 } 6937 6938 /* process parent variables */ 6939 for( i = 0; i < var->nparentvars; ++i ) 6940 { 6941 parentvar = var->parentvars[i]; 6942 assert(parentvar != NULL); 6943 6944 switch( SCIPvarGetStatus(parentvar) ) 6945 { 6946 case SCIP_VARSTATUS_ORIGINAL: 6947 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) ); 6948 break; 6949 6950 case SCIP_VARSTATUS_COLUMN: 6951 case SCIP_VARSTATUS_LOOSE: 6952 case SCIP_VARSTATUS_FIXED: 6953 case SCIP_VARSTATUS_MULTAGGR: 6954 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n"); 6955 return SCIP_INVALIDDATA; 6956 6957 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 6958 assert(parentvar->data.aggregate.var == var); 6959 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) ) 6960 { 6961 SCIP_Real parentnewbound; 6962 6963 /* a > 0 -> change lower bound of y */ 6964 assert(SCIPsetIsInfinity(set, -parentvar->glbdom.lb) || SCIPsetIsInfinity(set, -oldbound) 6965 || SCIPsetIsFeasEQ(set, parentvar->glbdom.lb, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant) 6966 || (SCIPsetIsZero(set, parentvar->glbdom.lb / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound))); 6967 6968 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 6969 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant; 6970 else 6971 parentnewbound = newbound; 6972 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) ); 6973 } 6974 else 6975 { 6976 SCIP_Real parentnewbound; 6977 6978 /* a < 0 -> change upper bound of y */ 6979 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar)); 6980 assert(SCIPsetIsInfinity(set, parentvar->glbdom.ub) || SCIPsetIsInfinity(set, -oldbound) 6981 || SCIPsetIsFeasEQ(set, parentvar->glbdom.ub, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant) 6982 || (SCIPsetIsZero(set, parentvar->glbdom.ub / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound))); 6983 6984 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 6985 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant; 6986 else 6987 parentnewbound = -newbound; 6988 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) ); 6989 } 6990 break; 6991 6992 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 6993 assert(parentvar->negatedvar != NULL); 6994 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED); 6995 assert(parentvar->negatedvar->negatedvar == parentvar); 6996 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 6997 parentvar->data.negate.constant - newbound) ); 6998 break; 6999 7000 default: 7001 SCIPerrorMessage("unknown variable status\n"); 7002 return SCIP_INVALIDDATA; 7003 } 7004 } 7005 7006 return SCIP_OKAY; 7007 } 7008 7009 /** performs the current change in upper bound, changes all parents accordingly */ 7010 static 7011 SCIP_RETCODE varProcessChgUbGlobal( 7012 SCIP_VAR* var, /**< problem variable to change */ 7013 BMS_BLKMEM* blkmem, /**< block memory */ 7014 SCIP_SET* set, /**< global SCIP settings */ 7015 SCIP_STAT* stat, /**< problem statistics */ 7016 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 7017 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 7018 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 7019 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 7020 SCIP_Real newbound /**< new bound for variable */ 7021 ) 7022 { 7023 SCIP_VAR* parentvar; 7024 SCIP_Real oldbound; 7025 int i; 7026 7027 assert(var != NULL); 7028 /* local domains can violate global bounds but not more than feasibility epsilon */ 7029 assert(SCIPsetIsFeasLE(set, var->glbdom.lb , var->locdom.lb)); 7030 assert(SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub)); 7031 assert(blkmem != NULL); 7032 assert(set != NULL); 7033 assert(var->scip == set->scip); 7034 assert(stat != NULL); 7035 7036 /* adjust bound to integral value if variable is of integral type */ 7037 newbound = adjustedUb(set, SCIPvarGetType(var), newbound); 7038 7039 /* check that the bound is feasible */ 7040 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM && newbound < var->glbdom.lb ) 7041 { 7042 /* due to numerics we only want to be feasible in feasibility tolerance */ 7043 assert(SCIPsetIsFeasGE(set, newbound, var->glbdom.lb)); 7044 newbound = var->glbdom.lb; 7045 } 7046 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 7047 7048 assert(var->vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, newbound, 0.0) || SCIPsetIsEQ(set, newbound, 1.0)); /*lint !e641*/ 7049 7050 SCIPsetDebugMsg(set, "process changing global upper bound of <%s> from %f to %f\n", var->name, var->glbdom.ub, newbound); 7051 7052 if( SCIPsetIsEQ(set, newbound, var->glbdom.ub) && !(newbound != var->glbdom.ub && newbound * var->glbdom.ub <= 0.0) ) /*lint !e777*/ 7053 return SCIP_OKAY; 7054 7055 /* check bound on debugging solution */ 7056 SCIP_CALL( SCIPdebugCheckUbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/ 7057 7058 /* change the bound */ 7059 oldbound = var->glbdom.ub; 7060 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasGE(set, newbound, var->glbdom.lb)); 7061 var->glbdom.ub = newbound; 7062 assert( SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb) ); 7063 assert( SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub) ); 7064 7065 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM ) 7066 { 7067 /* merges overlapping holes into single holes, moves bounds respectively */ 7068 domMerge(&var->glbdom, blkmem, set, NULL, &newbound); 7069 } 7070 7071 /* update the root bound changes counters */ 7072 varIncRootboundchgs(var, set, stat); 7073 7074 /* update the ubchginfos array by replacing worse local bounds with the new global bound and changing the 7075 * redundant bound changes to be branching decisions 7076 */ 7077 for( i = 0; i < var->nubchginfos; ++i ) 7078 { 7079 assert(var->ubchginfos[i].var == var); 7080 if( var->ubchginfos[i].oldbound > var->glbdom.ub ) 7081 { 7082 SCIPsetDebugMsg(set, " -> adjust upper bound change <%s>: %g -> %g due to new global upper bound %g\n", 7083 SCIPvarGetName(var), var->ubchginfos[i].oldbound, var->ubchginfos[i].newbound, var->glbdom.ub); 7084 var->ubchginfos[i].oldbound = var->glbdom.ub; 7085 if( SCIPsetIsGE(set, var->ubchginfos[i].newbound, var->glbdom.ub) ) 7086 { 7087 /* this bound change is redundant due to the new global bound */ 7088 var->ubchginfos[i].newbound = var->glbdom.ub; 7089 var->ubchginfos[i].boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/ 7090 var->ubchginfos[i].redundant = TRUE; 7091 } 7092 else 7093 break; /* from now on, the remaining local bound changes are not redundant */ 7094 } 7095 else 7096 break; /* from now on, the remaining local bound changes are not redundant */ 7097 } 7098 7099 /* remove redundant implications and variable bounds */ 7100 if( (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE) 7101 && (!set->reopt_enable || set->stage == SCIP_STAGE_PRESOLVING) ) 7102 { 7103 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, TRUE, TRUE) ); 7104 } 7105 7106 /* issue bound change event */ 7107 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL)); 7108 if( var->eventfilter != NULL ) 7109 { 7110 SCIP_CALL( varEventGubChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) ); 7111 } 7112 7113 /* process parent variables */ 7114 for( i = 0; i < var->nparentvars; ++i ) 7115 { 7116 parentvar = var->parentvars[i]; 7117 assert(parentvar != NULL); 7118 7119 switch( SCIPvarGetStatus(parentvar) ) 7120 { 7121 case SCIP_VARSTATUS_ORIGINAL: 7122 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) ); 7123 break; 7124 7125 case SCIP_VARSTATUS_COLUMN: 7126 case SCIP_VARSTATUS_LOOSE: 7127 case SCIP_VARSTATUS_FIXED: 7128 case SCIP_VARSTATUS_MULTAGGR: 7129 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n"); 7130 return SCIP_INVALIDDATA; 7131 7132 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 7133 assert(parentvar->data.aggregate.var == var); 7134 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) ) 7135 { 7136 SCIP_Real parentnewbound; 7137 7138 /* a > 0 -> change upper bound of y */ 7139 assert(SCIPsetIsInfinity(set, parentvar->glbdom.ub) || SCIPsetIsInfinity(set, oldbound) 7140 || SCIPsetIsFeasEQ(set, parentvar->glbdom.ub, 7141 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)); 7142 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 7143 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant; 7144 else 7145 parentnewbound = newbound; 7146 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) ); 7147 } 7148 else 7149 { 7150 SCIP_Real parentnewbound; 7151 7152 /* a < 0 -> change lower bound of y */ 7153 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar)); 7154 assert(SCIPsetIsInfinity(set, -parentvar->glbdom.lb) || SCIPsetIsInfinity(set, oldbound) 7155 || SCIPsetIsFeasEQ(set, parentvar->glbdom.lb, 7156 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)); 7157 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 7158 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant; 7159 else 7160 parentnewbound = -newbound; 7161 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) ); 7162 } 7163 break; 7164 7165 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 7166 assert(parentvar->negatedvar != NULL); 7167 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED); 7168 assert(parentvar->negatedvar->negatedvar == parentvar); 7169 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 7170 parentvar->data.negate.constant - newbound) ); 7171 break; 7172 7173 default: 7174 SCIPerrorMessage("unknown variable status\n"); 7175 return SCIP_INVALIDDATA; 7176 } 7177 } 7178 7179 return SCIP_OKAY; 7180 } 7181 7182 /** changes global lower bound of variable; if possible, adjusts bound to integral value; 7183 * updates local lower bound if the global bound is tighter 7184 */ 7185 SCIP_RETCODE SCIPvarChgLbGlobal( 7186 SCIP_VAR* var, /**< problem variable to change */ 7187 BMS_BLKMEM* blkmem, /**< block memory */ 7188 SCIP_SET* set, /**< global SCIP settings */ 7189 SCIP_STAT* stat, /**< problem statistics */ 7190 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 7191 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 7192 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 7193 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 7194 SCIP_Real newbound /**< new bound for variable */ 7195 ) 7196 { 7197 assert(var != NULL); 7198 assert(blkmem != NULL); 7199 assert(set != NULL); 7200 assert(var->scip == set->scip); 7201 7202 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside 7203 * of the domain within feastol 7204 */ 7205 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->glbdom.ub)); 7206 7207 /* adjust bound to integral value if variable is of integral type */ 7208 newbound = adjustedLb(set, SCIPvarGetType(var), newbound); 7209 7210 /* check that the adjusted bound is feasible 7211 * @todo this does not have to be the case if the original problem was infeasible due to bounds and we are called 7212 * here because we reset bounds to their original value! 7213 */ 7214 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->glbdom.ub)); 7215 7216 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM ) 7217 { 7218 /* we do not want to exceed the upperbound, which could have happened due to numerics */ 7219 newbound = MIN(newbound, var->glbdom.ub); 7220 } 7221 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 7222 7223 /* the new global bound has to be tighter except we are in the original problem; this must be w.r.t. feastol because 7224 * SCIPvarFix() allows fixings that are outside of the domain within feastol 7225 */ 7226 assert(lp == NULL || SCIPsetIsFeasLE(set, var->glbdom.lb, newbound) || (set->reopt_enable && set->stage == SCIP_STAGE_PRESOLVED)); 7227 7228 SCIPsetDebugMsg(set, "changing global lower bound of <%s> from %g to %g\n", var->name, var->glbdom.lb, newbound); 7229 7230 if( SCIPsetIsEQ(set, var->glbdom.lb, newbound) && !(newbound != var->glbdom.lb && newbound * var->glbdom.lb <= 0.0) ) /*lint !e777*/ 7231 return SCIP_OKAY; 7232 7233 /* change bounds of attached variables */ 7234 switch( SCIPvarGetStatus(var) ) 7235 { 7236 case SCIP_VARSTATUS_ORIGINAL: 7237 if( var->data.original.transvar != NULL ) 7238 { 7239 SCIP_CALL( SCIPvarChgLbGlobal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, 7240 cliquetable, newbound) ); 7241 } 7242 else 7243 { 7244 assert(set->stage == SCIP_STAGE_PROBLEM); 7245 if( newbound > SCIPvarGetLbLocal(var) ) 7246 { 7247 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) ); 7248 } 7249 SCIP_CALL( varProcessChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) ); 7250 } 7251 break; 7252 7253 case SCIP_VARSTATUS_COLUMN: 7254 case SCIP_VARSTATUS_LOOSE: 7255 if( newbound > SCIPvarGetLbLocal(var) ) 7256 { 7257 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) ); 7258 } 7259 SCIP_CALL( varProcessChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) ); 7260 break; 7261 7262 case SCIP_VARSTATUS_FIXED: 7263 SCIPerrorMessage("cannot change the bounds of a fixed variable\n"); 7264 return SCIP_INVALIDDATA; 7265 7266 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 7267 assert(var->data.aggregate.var != NULL); 7268 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) ) 7269 { 7270 SCIP_Real childnewbound; 7271 7272 /* a > 0 -> change lower bound of y */ 7273 assert((SCIPsetIsInfinity(set, -var->glbdom.lb) && SCIPsetIsInfinity(set, -var->data.aggregate.var->glbdom.lb)) 7274 || SCIPsetIsFeasEQ(set, var->glbdom.lb, 7275 var->data.aggregate.var->glbdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant)); 7276 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 7277 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 7278 else 7279 childnewbound = newbound; 7280 SCIP_CALL( SCIPvarChgLbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 7281 childnewbound) ); 7282 } 7283 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) ) 7284 { 7285 SCIP_Real childnewbound; 7286 7287 /* a < 0 -> change upper bound of y */ 7288 assert((SCIPsetIsInfinity(set, -var->glbdom.lb) && SCIPsetIsInfinity(set, var->data.aggregate.var->glbdom.ub)) 7289 || SCIPsetIsFeasEQ(set, var->glbdom.lb, 7290 var->data.aggregate.var->glbdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant)); 7291 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 7292 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 7293 else 7294 childnewbound = -newbound; 7295 SCIP_CALL( SCIPvarChgUbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 7296 childnewbound) ); 7297 } 7298 else 7299 { 7300 SCIPerrorMessage("scalar is zero in aggregation\n"); 7301 return SCIP_INVALIDDATA; 7302 } 7303 break; 7304 7305 case SCIP_VARSTATUS_MULTAGGR: 7306 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n"); 7307 return SCIP_INVALIDDATA; 7308 7309 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 7310 assert(var->negatedvar != NULL); 7311 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 7312 assert(var->negatedvar->negatedvar == var); 7313 SCIP_CALL( SCIPvarChgUbGlobal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 7314 var->data.negate.constant - newbound) ); 7315 break; 7316 7317 default: 7318 SCIPerrorMessage("unknown variable status\n"); 7319 return SCIP_INVALIDDATA; 7320 } 7321 7322 return SCIP_OKAY; 7323 } 7324 7325 /** changes global upper bound of variable; if possible, adjusts bound to integral value; 7326 * updates local upper bound if the global bound is tighter 7327 */ 7328 SCIP_RETCODE SCIPvarChgUbGlobal( 7329 SCIP_VAR* var, /**< problem variable to change */ 7330 BMS_BLKMEM* blkmem, /**< block memory */ 7331 SCIP_SET* set, /**< global SCIP settings */ 7332 SCIP_STAT* stat, /**< problem statistics */ 7333 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 7334 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 7335 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 7336 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 7337 SCIP_Real newbound /**< new bound for variable */ 7338 ) 7339 { 7340 assert(var != NULL); 7341 assert(blkmem != NULL); 7342 assert(set != NULL); 7343 assert(var->scip == set->scip); 7344 7345 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside 7346 * of the domain within feastol 7347 */ 7348 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->glbdom.lb)); 7349 7350 /* adjust bound to integral value if variable is of integral type */ 7351 newbound = adjustedUb(set, SCIPvarGetType(var), newbound); 7352 7353 /* check that the adjusted bound is feasible 7354 * @todo this does not have to be the case if the original problem was infeasible due to bounds and we are called 7355 * here because we reset bounds to their original value! 7356 */ 7357 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->glbdom.lb)); 7358 7359 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM ) 7360 { 7361 /* we do not want to undercut the lowerbound, which could have happened due to numerics */ 7362 newbound = MAX(newbound, var->glbdom.lb); 7363 } 7364 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 7365 7366 /* the new global bound has to be tighter except we are in the original problem; this must be w.r.t. feastol because 7367 * SCIPvarFix() allows fixings that are outside of the domain within feastol 7368 */ 7369 assert(lp == NULL || SCIPsetIsFeasGE(set, var->glbdom.ub, newbound) || (set->reopt_enable && set->stage == SCIP_STAGE_PRESOLVED)); 7370 7371 SCIPsetDebugMsg(set, "changing global upper bound of <%s> from %g to %g\n", var->name, var->glbdom.ub, newbound); 7372 7373 if( SCIPsetIsEQ(set, var->glbdom.ub, newbound) && !(newbound != var->glbdom.ub && newbound * var->glbdom.ub <= 0.0) ) /*lint !e777*/ 7374 return SCIP_OKAY; 7375 7376 /* change bounds of attached variables */ 7377 switch( SCIPvarGetStatus(var) ) 7378 { 7379 case SCIP_VARSTATUS_ORIGINAL: 7380 if( var->data.original.transvar != NULL ) 7381 { 7382 SCIP_CALL( SCIPvarChgUbGlobal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 7383 newbound) ); 7384 } 7385 else 7386 { 7387 assert(set->stage == SCIP_STAGE_PROBLEM); 7388 if( newbound < SCIPvarGetUbLocal(var) ) 7389 { 7390 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) ); 7391 } 7392 SCIP_CALL( varProcessChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) ); 7393 } 7394 break; 7395 7396 case SCIP_VARSTATUS_COLUMN: 7397 case SCIP_VARSTATUS_LOOSE: 7398 if( newbound < SCIPvarGetUbLocal(var) ) 7399 { 7400 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) ); 7401 } 7402 SCIP_CALL( varProcessChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) ); 7403 break; 7404 7405 case SCIP_VARSTATUS_FIXED: 7406 SCIPerrorMessage("cannot change the bounds of a fixed variable\n"); 7407 return SCIP_INVALIDDATA; 7408 7409 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 7410 assert(var->data.aggregate.var != NULL); 7411 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) ) 7412 { 7413 SCIP_Real childnewbound; 7414 7415 /* a > 0 -> change lower bound of y */ 7416 assert((SCIPsetIsInfinity(set, var->glbdom.ub) && SCIPsetIsInfinity(set, var->data.aggregate.var->glbdom.ub)) 7417 || SCIPsetIsFeasEQ(set, var->glbdom.ub, 7418 var->data.aggregate.var->glbdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant)); 7419 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 7420 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 7421 else 7422 childnewbound = newbound; 7423 SCIP_CALL( SCIPvarChgUbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 7424 childnewbound) ); 7425 } 7426 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) ) 7427 { 7428 SCIP_Real childnewbound; 7429 7430 /* a < 0 -> change upper bound of y */ 7431 assert((SCIPsetIsInfinity(set, var->glbdom.ub) && SCIPsetIsInfinity(set, -var->data.aggregate.var->glbdom.lb)) 7432 || SCIPsetIsFeasEQ(set, var->glbdom.ub, 7433 var->data.aggregate.var->glbdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant)); 7434 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 7435 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 7436 else 7437 childnewbound = -newbound; 7438 SCIP_CALL( SCIPvarChgLbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 7439 childnewbound) ); 7440 } 7441 else 7442 { 7443 SCIPerrorMessage("scalar is zero in aggregation\n"); 7444 return SCIP_INVALIDDATA; 7445 } 7446 break; 7447 7448 case SCIP_VARSTATUS_MULTAGGR: 7449 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n"); 7450 return SCIP_INVALIDDATA; 7451 7452 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 7453 assert(var->negatedvar != NULL); 7454 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 7455 assert(var->negatedvar->negatedvar == var); 7456 SCIP_CALL( SCIPvarChgLbGlobal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 7457 var->data.negate.constant - newbound) ); 7458 break; 7459 7460 default: 7461 SCIPerrorMessage("unknown variable status\n"); 7462 return SCIP_INVALIDDATA; 7463 } 7464 7465 return SCIP_OKAY; 7466 } 7467 7468 /** changes lazy lower bound of the variable, this is only possible if the variable is not in the LP yet */ 7469 SCIP_RETCODE SCIPvarChgLbLazy( 7470 SCIP_VAR* var, /**< problem variable */ 7471 SCIP_SET* set, /**< global SCIP settings */ 7472 SCIP_Real lazylb /**< the lazy lower bound to be set */ 7473 ) 7474 { 7475 assert(var != NULL); 7476 assert(var->probindex != -1); 7477 assert(SCIPsetIsFeasGE(set, var->glbdom.ub, lazylb)); 7478 assert(SCIPsetIsFeasGE(set, var->lazyub, lazylb)); 7479 assert(set != NULL); 7480 assert(var->scip == set->scip); 7481 7482 /* variable should not be in the LP */ 7483 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 7484 return SCIP_INVALIDCALL; 7485 7486 var->lazylb = lazylb; 7487 7488 return SCIP_OKAY; 7489 } 7490 7491 /** changes lazy upper bound of the variable, this is only possible if the variable is not in the LP yet */ 7492 SCIP_RETCODE SCIPvarChgUbLazy( 7493 SCIP_VAR* var, /**< problem variable */ 7494 SCIP_SET* set, /**< global SCIP settings */ 7495 SCIP_Real lazyub /**< the lazy lower bound to be set */ 7496 ) 7497 { 7498 assert(var != NULL); 7499 assert(var->probindex != -1); 7500 assert(SCIPsetIsFeasGE(set, lazyub, var->glbdom.lb)); 7501 assert(SCIPsetIsFeasGE(set, lazyub, var->lazylb)); 7502 assert(set != NULL); 7503 assert(var->scip == set->scip); 7504 7505 /* variable should not be in the LP */ 7506 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 7507 return SCIP_INVALIDCALL; 7508 7509 var->lazyub = lazyub; 7510 7511 return SCIP_OKAY; 7512 } 7513 7514 7515 /** changes global bound of variable; if possible, adjusts bound to integral value; 7516 * updates local bound if the global bound is tighter 7517 */ 7518 SCIP_RETCODE SCIPvarChgBdGlobal( 7519 SCIP_VAR* var, /**< problem variable to change */ 7520 BMS_BLKMEM* blkmem, /**< block memory */ 7521 SCIP_SET* set, /**< global SCIP settings */ 7522 SCIP_STAT* stat, /**< problem statistics */ 7523 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 7524 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 7525 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 7526 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 7527 SCIP_Real newbound, /**< new bound for variable */ 7528 SCIP_BOUNDTYPE boundtype /**< type of bound: lower or upper bound */ 7529 ) 7530 { 7531 /* apply bound change to the LP data */ 7532 switch( boundtype ) 7533 { 7534 case SCIP_BOUNDTYPE_LOWER: 7535 return SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound); 7536 case SCIP_BOUNDTYPE_UPPER: 7537 return SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound); 7538 default: 7539 SCIPerrorMessage("unknown bound type\n"); 7540 return SCIP_INVALIDDATA; 7541 } 7542 } 7543 7544 /** appends LBTIGHTENED or LBRELAXED event to the event queue */ 7545 static 7546 SCIP_RETCODE varEventLbChanged( 7547 SCIP_VAR* var, /**< problem variable to change */ 7548 BMS_BLKMEM* blkmem, /**< block memory */ 7549 SCIP_SET* set, /**< global SCIP settings */ 7550 SCIP_LP* lp, /**< current LP data */ 7551 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 7552 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 7553 SCIP_Real oldbound, /**< old lower bound for variable */ 7554 SCIP_Real newbound /**< new lower bound for variable */ 7555 ) 7556 { 7557 assert(var != NULL); 7558 assert(var->eventfilter != NULL); 7559 assert(SCIPvarIsTransformed(var)); 7560 assert(!SCIPsetIsEQ(set, oldbound, newbound) || newbound == var->glbdom.lb || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/ 7561 assert(set != NULL); 7562 assert(var->scip == set->scip); 7563 7564 /* check, if the variable is being tracked for bound changes 7565 * COLUMN and LOOSE variables are tracked always, because row activities and LP changes have to be updated 7566 */ 7567 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_LBCHANGED) != 0) 7568 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN 7569 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE ) 7570 { 7571 SCIP_EVENT* event; 7572 7573 SCIPsetDebugMsg(set, "issue LBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound); 7574 7575 SCIP_CALL( SCIPeventCreateLbChanged(&event, blkmem, var, oldbound, newbound) ); 7576 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) ); 7577 } 7578 7579 return SCIP_OKAY; 7580 } 7581 7582 /** appends UBTIGHTENED or UBRELAXED event to the event queue */ 7583 static 7584 SCIP_RETCODE varEventUbChanged( 7585 SCIP_VAR* var, /**< problem variable to change */ 7586 BMS_BLKMEM* blkmem, /**< block memory */ 7587 SCIP_SET* set, /**< global SCIP settings */ 7588 SCIP_LP* lp, /**< current LP data */ 7589 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 7590 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 7591 SCIP_Real oldbound, /**< old upper bound for variable */ 7592 SCIP_Real newbound /**< new upper bound for variable */ 7593 ) 7594 { 7595 assert(var != NULL); 7596 assert(var->eventfilter != NULL); 7597 assert(SCIPvarIsTransformed(var)); 7598 assert(!SCIPsetIsEQ(set, oldbound, newbound) || newbound == var->glbdom.ub || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/ 7599 assert(set != NULL); 7600 assert(var->scip == set->scip); 7601 7602 /* check, if the variable is being tracked for bound changes 7603 * COLUMN and LOOSE variables are tracked always, because row activities and LP changes have to be updated 7604 */ 7605 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_UBCHANGED) != 0) 7606 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN 7607 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE ) 7608 { 7609 SCIP_EVENT* event; 7610 7611 SCIPsetDebugMsg(set, "issue UBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound); 7612 7613 SCIP_CALL( SCIPeventCreateUbChanged(&event, blkmem, var, oldbound, newbound) ); 7614 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) ); 7615 } 7616 7617 return SCIP_OKAY; 7618 } 7619 7620 /* forward declaration, because both methods call each other recursively */ 7621 7622 /* performs the current change in upper bound, changes all parents accordingly */ 7623 static 7624 SCIP_RETCODE varProcessChgUbLocal( 7625 SCIP_VAR* var, /**< problem variable to change */ 7626 BMS_BLKMEM* blkmem, /**< block memory */ 7627 SCIP_SET* set, /**< global SCIP settings */ 7628 SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */ 7629 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 7630 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 7631 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 7632 SCIP_Real newbound /**< new bound for variable */ 7633 ); 7634 7635 /** performs the current change in lower bound, changes all parents accordingly */ 7636 static 7637 SCIP_RETCODE varProcessChgLbLocal( 7638 SCIP_VAR* var, /**< problem variable to change */ 7639 BMS_BLKMEM* blkmem, /**< block memory */ 7640 SCIP_SET* set, /**< global SCIP settings */ 7641 SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */ 7642 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 7643 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 7644 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 7645 SCIP_Real newbound /**< new bound for variable */ 7646 ) 7647 { 7648 SCIP_VAR* parentvar; 7649 SCIP_Real oldbound; 7650 int i; 7651 7652 assert(var != NULL); 7653 assert(set != NULL); 7654 assert(var->scip == set->scip); 7655 assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && (SCIPsetIsZero(set, newbound) || SCIPsetIsEQ(set, newbound, 1.0) 7656 || SCIPsetIsEQ(set, newbound, var->locdom.ub))) 7657 || (SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS && (SCIPsetIsIntegral(set, newbound) 7658 || SCIPsetIsEQ(set, newbound, var->locdom.ub))) 7659 || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS); 7660 7661 /* check that the bound is feasible */ 7662 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsLE(set, newbound, var->glbdom.ub)); 7663 /* adjust bound to integral value if variable is of integral type */ 7664 newbound = adjustedLb(set, SCIPvarGetType(var), newbound); 7665 7666 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM ) 7667 { 7668 /* we do not want to exceed the upper bound, which could have happened due to numerics */ 7669 newbound = MIN(newbound, var->locdom.ub); 7670 7671 /* we do not want to undercut the global lower bound, which could have happened due to numerics */ 7672 newbound = MAX(newbound, var->glbdom.lb); 7673 } 7674 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 7675 7676 SCIPsetDebugMsg(set, "process changing lower bound of <%s> from %g to %g\n", var->name, var->locdom.lb, newbound); 7677 7678 if( SCIPsetIsEQ(set, newbound, var->glbdom.lb) && var->glbdom.lb != var->locdom.lb ) /*lint !e777*/ 7679 newbound = var->glbdom.lb; 7680 else if( SCIPsetIsEQ(set, newbound, var->locdom.lb) && !(newbound != var->locdom.lb && newbound * var->locdom.lb <= 0.0) ) /*lint !e777*/ 7681 return SCIP_OKAY; 7682 7683 /* change the bound */ 7684 oldbound = var->locdom.lb; 7685 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasLE(set, newbound, var->locdom.ub)); 7686 var->locdom.lb = newbound; 7687 7688 /* update statistic; during the update steps of the parent variable we pass a NULL pointer to ensure that we only 7689 * once update the statistic 7690 */ 7691 if( stat != NULL ) 7692 SCIPstatIncrement(stat, set, domchgcount); 7693 7694 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM ) 7695 { 7696 /* merges overlapping holes into single holes, moves bounds respectively */ 7697 domMerge(&var->locdom, blkmem, set, &newbound, NULL); 7698 } 7699 7700 /* issue bound change event */ 7701 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL)); 7702 if( var->eventfilter != NULL ) 7703 { 7704 SCIP_CALL( varEventLbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) ); 7705 } 7706 7707 /* process parent variables */ 7708 for( i = 0; i < var->nparentvars; ++i ) 7709 { 7710 parentvar = var->parentvars[i]; 7711 assert(parentvar != NULL); 7712 7713 switch( SCIPvarGetStatus(parentvar) ) 7714 { 7715 case SCIP_VARSTATUS_ORIGINAL: 7716 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, newbound) ); 7717 break; 7718 7719 case SCIP_VARSTATUS_COLUMN: 7720 case SCIP_VARSTATUS_LOOSE: 7721 case SCIP_VARSTATUS_FIXED: 7722 case SCIP_VARSTATUS_MULTAGGR: 7723 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n"); 7724 return SCIP_INVALIDDATA; 7725 7726 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 7727 assert(parentvar->data.aggregate.var == var); 7728 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) ) 7729 { 7730 SCIP_Real parentnewbound; 7731 7732 /* a > 0 -> change lower bound of y */ 7733 assert(SCIPsetIsInfinity(set, -parentvar->locdom.lb) || SCIPsetIsInfinity(set, -oldbound) 7734 || SCIPsetIsFeasEQ(set, parentvar->locdom.lb, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant) 7735 || (SCIPsetIsZero(set, parentvar->locdom.lb / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound))); 7736 7737 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 7738 { 7739 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant; 7740 /* if parent's new lower bound exceeds its upper bound, then this could be due to numerical difficulties, e.g., if numbers are large 7741 * thus, at least a relative comparision of the new lower bound and the current upper bound should proof consistency 7742 * as a result, the parent's lower bound is set to it's upper bound, and not above 7743 */ 7744 if( parentnewbound > parentvar->glbdom.ub ) 7745 { 7746 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */ 7747 assert(SCIPsetIsFeasLE(set, parentnewbound, parentvar->glbdom.ub)); 7748 parentnewbound = parentvar->glbdom.ub; 7749 } 7750 } 7751 else 7752 parentnewbound = newbound; 7753 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) ); 7754 } 7755 else 7756 { 7757 SCIP_Real parentnewbound; 7758 7759 /* a < 0 -> change upper bound of y */ 7760 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar)); 7761 assert(SCIPsetIsInfinity(set, parentvar->locdom.ub) || SCIPsetIsInfinity(set, -oldbound) 7762 || SCIPsetIsFeasEQ(set, parentvar->locdom.ub, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant) 7763 || (SCIPsetIsZero(set, parentvar->locdom.ub / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound))); 7764 7765 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 7766 { 7767 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant; 7768 /* if parent's new upper bound is below its lower bound, then this could be due to numerical difficulties, e.g., if numbers are large 7769 * thus, at least a relative comparision of the new upper bound and the current lower bound should proof consistency 7770 * as a result, the parent's upper bound is set to it's lower bound, and not below 7771 */ 7772 if( parentnewbound < parentvar->glbdom.lb ) 7773 { 7774 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */ 7775 assert(SCIPsetIsFeasGE(set, parentnewbound, parentvar->glbdom.lb)); 7776 parentnewbound = parentvar->glbdom.lb; 7777 } 7778 } 7779 else 7780 parentnewbound = -newbound; 7781 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) ); 7782 } 7783 break; 7784 7785 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */ 7786 assert(parentvar->negatedvar != NULL); 7787 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED); 7788 assert(parentvar->negatedvar->negatedvar == parentvar); 7789 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, 7790 parentvar->data.negate.constant - newbound) ); 7791 break; 7792 7793 default: 7794 SCIPerrorMessage("unknown variable status\n"); 7795 return SCIP_INVALIDDATA; 7796 } 7797 } 7798 7799 return SCIP_OKAY; 7800 } 7801 7802 /** performs the current change in upper bound, changes all parents accordingly */ 7803 static 7804 SCIP_RETCODE varProcessChgUbLocal( 7805 SCIP_VAR* var, /**< problem variable to change */ 7806 BMS_BLKMEM* blkmem, /**< block memory */ 7807 SCIP_SET* set, /**< global SCIP settings */ 7808 SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */ 7809 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 7810 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 7811 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 7812 SCIP_Real newbound /**< new bound for variable */ 7813 ) 7814 { 7815 SCIP_VAR* parentvar; 7816 SCIP_Real oldbound; 7817 int i; 7818 7819 assert(var != NULL); 7820 assert(set != NULL); 7821 assert(var->scip == set->scip); 7822 assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && (SCIPsetIsZero(set, newbound) || SCIPsetIsEQ(set, newbound, 1.0) 7823 || SCIPsetIsEQ(set, newbound, var->locdom.lb))) 7824 || (SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS && (SCIPsetIsIntegral(set, newbound) 7825 || SCIPsetIsEQ(set, newbound, var->locdom.lb))) 7826 || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS); 7827 7828 /* check that the bound is feasible */ 7829 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsGE(set, newbound, var->glbdom.lb)); 7830 /* adjust bound to integral value if variable is of integral type */ 7831 newbound = adjustedUb(set, SCIPvarGetType(var), newbound); 7832 7833 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM ) 7834 { 7835 /* we do not want to undercut the lower bound, which could have happened due to numerics */ 7836 newbound = MAX(newbound, var->locdom.lb); 7837 7838 /* we do not want to exceed the global upper bound, which could have happened due to numerics */ 7839 newbound = MIN(newbound, var->glbdom.ub); 7840 } 7841 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 7842 7843 SCIPsetDebugMsg(set, "process changing upper bound of <%s> from %g to %g\n", var->name, var->locdom.ub, newbound); 7844 7845 if( SCIPsetIsEQ(set, newbound, var->glbdom.ub) && var->glbdom.ub != var->locdom.ub ) /*lint !e777*/ 7846 newbound = var->glbdom.ub; 7847 else if( SCIPsetIsEQ(set, newbound, var->locdom.ub) && !(newbound != var->locdom.ub && newbound * var->locdom.ub <= 0.0) ) /*lint !e777*/ 7848 return SCIP_OKAY; 7849 7850 /* change the bound */ 7851 oldbound = var->locdom.ub; 7852 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasGE(set, newbound, var->locdom.lb)); 7853 var->locdom.ub = newbound; 7854 7855 /* update statistic; during the update steps of the parent variable we pass a NULL pointer to ensure that we only 7856 * once update the statistic 7857 */ 7858 if( stat != NULL ) 7859 SCIPstatIncrement(stat, set, domchgcount); 7860 7861 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM ) 7862 { 7863 /* merges overlapping holes into single holes, moves bounds respectively */ 7864 domMerge(&var->locdom, blkmem, set, NULL, &newbound); 7865 } 7866 7867 /* issue bound change event */ 7868 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL)); 7869 if( var->eventfilter != NULL ) 7870 { 7871 SCIP_CALL( varEventUbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) ); 7872 } 7873 7874 /* process parent variables */ 7875 for( i = 0; i < var->nparentvars; ++i ) 7876 { 7877 parentvar = var->parentvars[i]; 7878 assert(parentvar != NULL); 7879 7880 switch( SCIPvarGetStatus(parentvar) ) 7881 { 7882 case SCIP_VARSTATUS_ORIGINAL: 7883 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, newbound) ); 7884 break; 7885 7886 case SCIP_VARSTATUS_COLUMN: 7887 case SCIP_VARSTATUS_LOOSE: 7888 case SCIP_VARSTATUS_FIXED: 7889 case SCIP_VARSTATUS_MULTAGGR: 7890 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n"); 7891 return SCIP_INVALIDDATA; 7892 7893 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 7894 assert(parentvar->data.aggregate.var == var); 7895 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) ) 7896 { 7897 SCIP_Real parentnewbound; 7898 7899 /* a > 0 -> change upper bound of x */ 7900 assert(SCIPsetIsInfinity(set, parentvar->locdom.ub) || SCIPsetIsInfinity(set, oldbound) 7901 || SCIPsetIsFeasEQ(set, parentvar->locdom.ub, 7902 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)); 7903 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 7904 { 7905 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant; 7906 /* if parent's new upper bound is below its lower bound, then this could be due to numerical difficulties, e.g., if numbers are large 7907 * thus, at least a relative comparision of the new upper bound and the current lower bound should proof consistency 7908 * as a result, the parent's upper bound is set to it's lower bound, and not below 7909 */ 7910 if( parentnewbound < parentvar->glbdom.lb ) 7911 { 7912 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */ 7913 assert(SCIPsetIsFeasGE(set, parentnewbound, parentvar->glbdom.lb)); 7914 parentnewbound = parentvar->glbdom.lb; 7915 } 7916 } 7917 else 7918 parentnewbound = newbound; 7919 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) ); 7920 } 7921 else 7922 { 7923 SCIP_Real parentnewbound; 7924 7925 /* a < 0 -> change lower bound of x */ 7926 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar)); 7927 assert(SCIPsetIsInfinity(set, -parentvar->locdom.lb) || SCIPsetIsInfinity(set, oldbound) 7928 || SCIPsetIsFeasEQ(set, parentvar->locdom.lb, 7929 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)); 7930 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 7931 { 7932 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant; 7933 /* if parent's new lower bound exceeds its upper bound, then this could be due to numerical difficulties, e.g., if numbers are large 7934 * thus, at least a relative comparision of the new lower bound and the current upper bound should proof consistency 7935 * as a result, the parent's lower bound is set to it's upper bound, and not above 7936 */ 7937 if( parentnewbound > parentvar->glbdom.ub ) 7938 { 7939 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */ 7940 assert(SCIPsetIsFeasLE(set, parentnewbound, parentvar->glbdom.ub)); 7941 parentnewbound = parentvar->glbdom.ub; 7942 } 7943 } 7944 else 7945 parentnewbound = -newbound; 7946 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) ); 7947 } 7948 break; 7949 7950 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */ 7951 assert(parentvar->negatedvar != NULL); 7952 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED); 7953 assert(parentvar->negatedvar->negatedvar == parentvar); 7954 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, 7955 parentvar->data.negate.constant - newbound) ); 7956 break; 7957 7958 default: 7959 SCIPerrorMessage("unknown variable status\n"); 7960 return SCIP_INVALIDDATA; 7961 } 7962 } 7963 7964 return SCIP_OKAY; 7965 } 7966 7967 /** changes current local lower bound of variable; if possible, adjusts bound to integral value; stores inference 7968 * information in variable 7969 */ 7970 SCIP_RETCODE SCIPvarChgLbLocal( 7971 SCIP_VAR* var, /**< problem variable to change */ 7972 BMS_BLKMEM* blkmem, /**< block memory */ 7973 SCIP_SET* set, /**< global SCIP settings */ 7974 SCIP_STAT* stat, /**< problem statistics */ 7975 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 7976 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 7977 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 7978 SCIP_Real newbound /**< new bound for variable */ 7979 ) 7980 { 7981 assert(var != NULL); 7982 assert(blkmem != NULL); 7983 assert(set != NULL); 7984 assert(var->scip == set->scip); 7985 7986 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside 7987 * of the domain within feastol 7988 */ 7989 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->locdom.ub)); 7990 7991 /* adjust bound to integral value if variable is of integral type */ 7992 newbound = adjustedLb(set, SCIPvarGetType(var), newbound); 7993 7994 /* check that the adjusted bound is feasible */ 7995 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->locdom.ub)); 7996 7997 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM ) 7998 { 7999 /* we do not want to exceed the upperbound, which could have happened due to numerics */ 8000 newbound = MIN(newbound, var->locdom.ub); 8001 } 8002 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 8003 8004 SCIPsetDebugMsg(set, "changing lower bound of <%s>[%g,%g] to %g\n", var->name, var->locdom.lb, var->locdom.ub, newbound); 8005 8006 if( SCIPsetIsEQ(set, var->locdom.lb, newbound) && (!SCIPsetIsEQ(set, var->glbdom.lb, newbound) || var->locdom.lb == newbound) /*lint !e777*/ 8007 && !(newbound != var->locdom.lb && newbound * var->locdom.lb <= 0.0) ) /*lint !e777*/ 8008 return SCIP_OKAY; 8009 8010 /* change bounds of attached variables */ 8011 switch( SCIPvarGetStatus(var) ) 8012 { 8013 case SCIP_VARSTATUS_ORIGINAL: 8014 if( var->data.original.transvar != NULL ) 8015 { 8016 SCIP_CALL( SCIPvarChgLbLocal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, 8017 newbound) ); 8018 } 8019 else 8020 { 8021 assert(set->stage == SCIP_STAGE_PROBLEM); 8022 SCIP_CALL( varProcessChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) ); 8023 } 8024 break; 8025 8026 case SCIP_VARSTATUS_COLUMN: 8027 case SCIP_VARSTATUS_LOOSE: 8028 SCIP_CALL( varProcessChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) ); 8029 break; 8030 8031 case SCIP_VARSTATUS_FIXED: 8032 SCIPerrorMessage("cannot change the bounds of a fixed variable\n"); 8033 return SCIP_INVALIDDATA; 8034 8035 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 8036 assert(var->data.aggregate.var != NULL); 8037 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) ) 8038 { 8039 SCIP_Real childnewbound; 8040 8041 /* a > 0 -> change lower bound of y */ 8042 assert((SCIPsetIsInfinity(set, -var->locdom.lb) && SCIPsetIsInfinity(set, -var->data.aggregate.var->locdom.lb)) 8043 || SCIPsetIsFeasEQ(set, var->locdom.lb, 8044 var->data.aggregate.var->locdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant)); 8045 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 8046 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 8047 else 8048 childnewbound = newbound; 8049 SCIP_CALL( SCIPvarChgLbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, 8050 childnewbound) ); 8051 } 8052 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) ) 8053 { 8054 SCIP_Real childnewbound; 8055 8056 /* a < 0 -> change upper bound of y */ 8057 assert((SCIPsetIsInfinity(set, -var->locdom.lb) && SCIPsetIsInfinity(set, var->data.aggregate.var->locdom.ub)) 8058 || SCIPsetIsFeasEQ(set, var->locdom.lb, 8059 var->data.aggregate.var->locdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant)); 8060 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 8061 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 8062 else 8063 childnewbound = -newbound; 8064 SCIP_CALL( SCIPvarChgUbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, 8065 childnewbound) ); 8066 } 8067 else 8068 { 8069 SCIPerrorMessage("scalar is zero in aggregation\n"); 8070 return SCIP_INVALIDDATA; 8071 } 8072 break; 8073 8074 case SCIP_VARSTATUS_MULTAGGR: 8075 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n"); 8076 return SCIP_INVALIDDATA; 8077 8078 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 8079 assert(var->negatedvar != NULL); 8080 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 8081 assert(var->negatedvar->negatedvar == var); 8082 SCIP_CALL( SCIPvarChgUbLocal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue, 8083 var->data.negate.constant - newbound) ); 8084 break; 8085 8086 default: 8087 SCIPerrorMessage("unknown variable status\n"); 8088 return SCIP_INVALIDDATA; 8089 } 8090 8091 return SCIP_OKAY; 8092 } 8093 8094 /** changes current local upper bound of variable; if possible, adjusts bound to integral value; stores inference 8095 * information in variable 8096 */ 8097 SCIP_RETCODE SCIPvarChgUbLocal( 8098 SCIP_VAR* var, /**< problem variable to change */ 8099 BMS_BLKMEM* blkmem, /**< block memory */ 8100 SCIP_SET* set, /**< global SCIP settings */ 8101 SCIP_STAT* stat, /**< problem statistics */ 8102 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 8103 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 8104 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 8105 SCIP_Real newbound /**< new bound for variable */ 8106 ) 8107 { 8108 assert(var != NULL); 8109 assert(blkmem != NULL); 8110 assert(set != NULL); 8111 assert(var->scip == set->scip); 8112 8113 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside 8114 * of the domain within feastol 8115 */ 8116 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->locdom.lb)); 8117 8118 /* adjust bound to integral value if variable is of integral type */ 8119 newbound = adjustedUb(set, SCIPvarGetType(var), newbound); 8120 8121 /* check that the adjusted bound is feasible */ 8122 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->locdom.lb)); 8123 8124 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM ) 8125 { 8126 /* we do not want to undercut the lowerbound, which could have happened due to numerics */ 8127 newbound = MAX(newbound, var->locdom.lb); 8128 } 8129 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound)); 8130 8131 SCIPsetDebugMsg(set, "changing upper bound of <%s>[%g,%g] to %g\n", var->name, var->locdom.lb, var->locdom.ub, newbound); 8132 8133 if( SCIPsetIsEQ(set, var->locdom.ub, newbound) && (!SCIPsetIsEQ(set, var->glbdom.ub, newbound) || var->locdom.ub == newbound) /*lint !e777*/ 8134 && !(newbound != var->locdom.ub && newbound * var->locdom.ub <= 0.0) ) /*lint !e777*/ 8135 return SCIP_OKAY; 8136 8137 /* change bounds of attached variables */ 8138 switch( SCIPvarGetStatus(var) ) 8139 { 8140 case SCIP_VARSTATUS_ORIGINAL: 8141 if( var->data.original.transvar != NULL ) 8142 { 8143 SCIP_CALL( SCIPvarChgUbLocal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, newbound) ); 8144 } 8145 else 8146 { 8147 assert(set->stage == SCIP_STAGE_PROBLEM); 8148 SCIP_CALL( varProcessChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) ); 8149 } 8150 break; 8151 8152 case SCIP_VARSTATUS_COLUMN: 8153 case SCIP_VARSTATUS_LOOSE: 8154 SCIP_CALL( varProcessChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) ); 8155 break; 8156 8157 case SCIP_VARSTATUS_FIXED: 8158 SCIPerrorMessage("cannot change the bounds of a fixed variable\n"); 8159 return SCIP_INVALIDDATA; 8160 8161 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 8162 assert(var->data.aggregate.var != NULL); 8163 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) ) 8164 { 8165 SCIP_Real childnewbound; 8166 8167 /* a > 0 -> change upper bound of y */ 8168 assert((SCIPsetIsInfinity(set, var->locdom.ub) && SCIPsetIsInfinity(set, var->data.aggregate.var->locdom.ub)) 8169 || SCIPsetIsFeasEQ(set, var->locdom.ub, 8170 var->data.aggregate.var->locdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant)); 8171 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 8172 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 8173 else 8174 childnewbound = newbound; 8175 SCIP_CALL( SCIPvarChgUbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, 8176 childnewbound) ); 8177 } 8178 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) ) 8179 { 8180 SCIP_Real childnewbound; 8181 8182 /* a < 0 -> change lower bound of y */ 8183 assert((SCIPsetIsInfinity(set, var->locdom.ub) && SCIPsetIsInfinity(set, -var->data.aggregate.var->locdom.lb)) 8184 || SCIPsetIsFeasEQ(set, var->locdom.ub, 8185 var->data.aggregate.var->locdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant)); 8186 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 8187 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 8188 else 8189 childnewbound = -newbound; 8190 SCIP_CALL( SCIPvarChgLbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, 8191 childnewbound) ); 8192 } 8193 else 8194 { 8195 SCIPerrorMessage("scalar is zero in aggregation\n"); 8196 return SCIP_INVALIDDATA; 8197 } 8198 break; 8199 8200 case SCIP_VARSTATUS_MULTAGGR: 8201 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n"); 8202 return SCIP_INVALIDDATA; 8203 8204 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 8205 assert(var->negatedvar != NULL); 8206 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 8207 assert(var->negatedvar->negatedvar == var); 8208 SCIP_CALL( SCIPvarChgLbLocal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue, 8209 var->data.negate.constant - newbound) ); 8210 break; 8211 8212 default: 8213 SCIPerrorMessage("unknown variable status\n"); 8214 return SCIP_INVALIDDATA; 8215 } 8216 8217 return SCIP_OKAY; 8218 } 8219 8220 /** changes current local bound of variable; if possible, adjusts bound to integral value; stores inference 8221 * information in variable 8222 */ 8223 SCIP_RETCODE SCIPvarChgBdLocal( 8224 SCIP_VAR* var, /**< problem variable to change */ 8225 BMS_BLKMEM* blkmem, /**< block memory */ 8226 SCIP_SET* set, /**< global SCIP settings */ 8227 SCIP_STAT* stat, /**< problem statistics */ 8228 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */ 8229 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */ 8230 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 8231 SCIP_Real newbound, /**< new bound for variable */ 8232 SCIP_BOUNDTYPE boundtype /**< type of bound: lower or upper bound */ 8233 ) 8234 { 8235 /* apply bound change to the LP data */ 8236 switch( boundtype ) 8237 { 8238 case SCIP_BOUNDTYPE_LOWER: 8239 return SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound); 8240 case SCIP_BOUNDTYPE_UPPER: 8241 return SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound); 8242 default: 8243 SCIPerrorMessage("unknown bound type\n"); 8244 return SCIP_INVALIDDATA; 8245 } 8246 } 8247 8248 /** changes lower bound of variable in current dive; if possible, adjusts bound to integral value */ 8249 SCIP_RETCODE SCIPvarChgLbDive( 8250 SCIP_VAR* var, /**< problem variable to change */ 8251 SCIP_SET* set, /**< global SCIP settings */ 8252 SCIP_LP* lp, /**< current LP data */ 8253 SCIP_Real newbound /**< new bound for variable */ 8254 ) 8255 { 8256 assert(var != NULL); 8257 assert(set != NULL); 8258 assert(var->scip == set->scip); 8259 assert(lp != NULL); 8260 assert(SCIPlpDiving(lp)); 8261 8262 /* adjust bound for integral variables */ 8263 SCIPvarAdjustLb(var, set, &newbound); 8264 8265 SCIPsetDebugMsg(set, "changing lower bound of <%s> to %g in current dive\n", var->name, newbound); 8266 8267 /* change bounds of attached variables */ 8268 switch( SCIPvarGetStatus(var) ) 8269 { 8270 case SCIP_VARSTATUS_ORIGINAL: 8271 assert(var->data.original.transvar != NULL); 8272 SCIP_CALL( SCIPvarChgLbDive(var->data.original.transvar, set, lp, newbound) ); 8273 break; 8274 8275 case SCIP_VARSTATUS_COLUMN: 8276 assert(var->data.col != NULL); 8277 SCIP_CALL( SCIPcolChgLb(var->data.col, set, lp, newbound) ); 8278 break; 8279 8280 case SCIP_VARSTATUS_LOOSE: 8281 SCIPerrorMessage("cannot change variable's bounds in dive for LOOSE variables\n"); 8282 return SCIP_INVALIDDATA; 8283 8284 case SCIP_VARSTATUS_FIXED: 8285 SCIPerrorMessage("cannot change the bounds of a fixed variable\n"); 8286 return SCIP_INVALIDDATA; 8287 8288 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 8289 assert(var->data.aggregate.var != NULL); 8290 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) ) 8291 { 8292 SCIP_Real childnewbound; 8293 8294 /* a > 0 -> change lower bound of y */ 8295 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 8296 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 8297 else 8298 childnewbound = newbound; 8299 SCIP_CALL( SCIPvarChgLbDive(var->data.aggregate.var, set, lp, childnewbound) ); 8300 } 8301 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) ) 8302 { 8303 SCIP_Real childnewbound; 8304 8305 /* a < 0 -> change upper bound of y */ 8306 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 8307 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 8308 else 8309 childnewbound = -newbound; 8310 SCIP_CALL( SCIPvarChgUbDive(var->data.aggregate.var, set, lp, childnewbound) ); 8311 } 8312 else 8313 { 8314 SCIPerrorMessage("scalar is zero in aggregation\n"); 8315 return SCIP_INVALIDDATA; 8316 } 8317 break; 8318 8319 case SCIP_VARSTATUS_MULTAGGR: 8320 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n"); 8321 return SCIP_INVALIDDATA; 8322 8323 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 8324 assert(var->negatedvar != NULL); 8325 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 8326 assert(var->negatedvar->negatedvar == var); 8327 SCIP_CALL( SCIPvarChgUbDive(var->negatedvar, set, lp, var->data.negate.constant - newbound) ); 8328 break; 8329 8330 default: 8331 SCIPerrorMessage("unknown variable status\n"); 8332 return SCIP_INVALIDDATA; 8333 } 8334 8335 return SCIP_OKAY; 8336 } 8337 8338 /** changes upper bound of variable in current dive; if possible, adjusts bound to integral value */ 8339 SCIP_RETCODE SCIPvarChgUbDive( 8340 SCIP_VAR* var, /**< problem variable to change */ 8341 SCIP_SET* set, /**< global SCIP settings */ 8342 SCIP_LP* lp, /**< current LP data */ 8343 SCIP_Real newbound /**< new bound for variable */ 8344 ) 8345 { 8346 assert(var != NULL); 8347 assert(set != NULL); 8348 assert(var->scip == set->scip); 8349 assert(lp != NULL); 8350 assert(SCIPlpDiving(lp)); 8351 8352 /* adjust bound for integral variables */ 8353 SCIPvarAdjustUb(var, set, &newbound); 8354 8355 SCIPsetDebugMsg(set, "changing upper bound of <%s> to %g in current dive\n", var->name, newbound); 8356 8357 /* change bounds of attached variables */ 8358 switch( SCIPvarGetStatus(var) ) 8359 { 8360 case SCIP_VARSTATUS_ORIGINAL: 8361 assert(var->data.original.transvar != NULL); 8362 SCIP_CALL( SCIPvarChgUbDive(var->data.original.transvar, set, lp, newbound) ); 8363 break; 8364 8365 case SCIP_VARSTATUS_COLUMN: 8366 assert(var->data.col != NULL); 8367 SCIP_CALL( SCIPcolChgUb(var->data.col, set, lp, newbound) ); 8368 break; 8369 8370 case SCIP_VARSTATUS_LOOSE: 8371 SCIPerrorMessage("cannot change variable's bounds in dive for LOOSE variables\n"); 8372 return SCIP_INVALIDDATA; 8373 8374 case SCIP_VARSTATUS_FIXED: 8375 SCIPerrorMessage("cannot change the bounds of a fixed variable\n"); 8376 return SCIP_INVALIDDATA; 8377 8378 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 8379 assert(var->data.aggregate.var != NULL); 8380 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) ) 8381 { 8382 SCIP_Real childnewbound; 8383 8384 /* a > 0 -> change upper bound of y */ 8385 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 8386 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 8387 else 8388 childnewbound = newbound; 8389 SCIP_CALL( SCIPvarChgUbDive(var->data.aggregate.var, set, lp, childnewbound) ); 8390 } 8391 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) ) 8392 { 8393 SCIP_Real childnewbound; 8394 8395 /* a < 0 -> change lower bound of y */ 8396 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) ) 8397 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar; 8398 else 8399 childnewbound = -newbound; 8400 SCIP_CALL( SCIPvarChgLbDive(var->data.aggregate.var, set, lp, childnewbound) ); 8401 } 8402 else 8403 { 8404 SCIPerrorMessage("scalar is zero in aggregation\n"); 8405 return SCIP_INVALIDDATA; 8406 } 8407 break; 8408 8409 case SCIP_VARSTATUS_MULTAGGR: 8410 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n"); 8411 return SCIP_INVALIDDATA; 8412 8413 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 8414 assert(var->negatedvar != NULL); 8415 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 8416 assert(var->negatedvar->negatedvar == var); 8417 SCIP_CALL( SCIPvarChgLbDive(var->negatedvar, set, lp, var->data.negate.constant - newbound) ); 8418 break; 8419 8420 default: 8421 SCIPerrorMessage("unknown variable status\n"); 8422 return SCIP_INVALIDDATA; 8423 } 8424 8425 return SCIP_OKAY; 8426 } 8427 8428 /** for a multi-aggregated variable, gives the local lower bound computed by adding the local bounds from all 8429 * aggregation variables, this lower bound may be tighter than the one given by SCIPvarGetLbLocal, since the latter is 8430 * not updated if bounds of aggregation variables are changing 8431 * 8432 * calling this function for a non-multi-aggregated variable is not allowed 8433 */ 8434 SCIP_Real SCIPvarGetMultaggrLbLocal( 8435 SCIP_VAR* var, /**< problem variable */ 8436 SCIP_SET* set /**< global SCIP settings */ 8437 ) 8438 { 8439 int i; 8440 SCIP_Real lb; 8441 SCIP_Real bnd; 8442 SCIP_VAR* aggrvar; 8443 SCIP_Bool posinf; 8444 SCIP_Bool neginf; 8445 8446 assert(var != NULL); 8447 assert(set != NULL); 8448 assert(var->scip == set->scip); 8449 assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR); 8450 8451 posinf = FALSE; 8452 neginf = FALSE; 8453 lb = var->data.multaggr.constant; 8454 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i ) 8455 { 8456 aggrvar = var->data.multaggr.vars[i]; 8457 if( var->data.multaggr.scalars[i] > 0.0 ) 8458 { 8459 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbLocal(aggrvar, set) : SCIPvarGetLbLocal(aggrvar); 8460 8461 if( SCIPsetIsInfinity(set, bnd) ) 8462 posinf = TRUE; 8463 else if( SCIPsetIsInfinity(set, -bnd) ) 8464 neginf = TRUE; 8465 else 8466 lb += var->data.multaggr.scalars[i] * bnd; 8467 } 8468 else 8469 { 8470 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbLocal(aggrvar, set) : SCIPvarGetUbLocal(aggrvar); 8471 8472 if( SCIPsetIsInfinity(set, -bnd) ) 8473 posinf = TRUE; 8474 else if( SCIPsetIsInfinity(set, bnd) ) 8475 neginf = TRUE; 8476 else 8477 lb += var->data.multaggr.scalars[i] * bnd; 8478 } 8479 8480 /* stop if two diffrent infinities (or a -infinity) were found and return local lower bound of multi aggregated 8481 * variable 8482 */ 8483 if( neginf ) 8484 return SCIPvarGetLbLocal(var); 8485 } 8486 8487 /* if positive infinity flag was set to true return infinity */ 8488 if( posinf ) 8489 return SCIPsetInfinity(set); 8490 8491 return (MAX(lb, SCIPvarGetLbLocal(var))); /*lint !e666*/ 8492 } 8493 8494 /** for a multi-aggregated variable, gives the local upper bound computed by adding the local bounds from all 8495 * aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbLocal, since the latter is 8496 * not updated if bounds of aggregation variables are changing 8497 * 8498 * calling this function for a non-multi-aggregated variable is not allowed 8499 */ 8500 SCIP_Real SCIPvarGetMultaggrUbLocal( 8501 SCIP_VAR* var, /**< problem variable */ 8502 SCIP_SET* set /**< global SCIP settings */ 8503 ) 8504 { 8505 int i; 8506 SCIP_Real ub; 8507 SCIP_Real bnd; 8508 SCIP_VAR* aggrvar; 8509 SCIP_Bool posinf; 8510 SCIP_Bool neginf; 8511 8512 assert(var != NULL); 8513 assert(set != NULL); 8514 assert(var->scip == set->scip); 8515 assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR); 8516 8517 posinf = FALSE; 8518 neginf = FALSE; 8519 ub = var->data.multaggr.constant; 8520 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i ) 8521 { 8522 aggrvar = var->data.multaggr.vars[i]; 8523 if( var->data.multaggr.scalars[i] > 0.0 ) 8524 { 8525 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbLocal(aggrvar, set) : SCIPvarGetUbLocal(aggrvar); 8526 8527 if( SCIPsetIsInfinity(set, bnd) ) 8528 posinf = TRUE; 8529 else if( SCIPsetIsInfinity(set, -bnd) ) 8530 neginf = TRUE; 8531 else 8532 ub += var->data.multaggr.scalars[i] * bnd; 8533 } 8534 else 8535 { 8536 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbLocal(aggrvar, set) : SCIPvarGetLbLocal(aggrvar); 8537 8538 if( SCIPsetIsInfinity(set, -bnd) ) 8539 posinf = TRUE; 8540 else if( SCIPsetIsInfinity(set, bnd) ) 8541 neginf = TRUE; 8542 else 8543 ub += var->data.multaggr.scalars[i] * bnd; 8544 } 8545 8546 /* stop if two diffrent infinities (or a -infinity) were found and return local upper bound of multi aggregated 8547 * variable 8548 */ 8549 if( posinf ) 8550 return SCIPvarGetUbLocal(var); 8551 } 8552 8553 /* if negative infinity flag was set to true return -infinity */ 8554 if( neginf ) 8555 return -SCIPsetInfinity(set); 8556 8557 return (MIN(ub, SCIPvarGetUbLocal(var))); /*lint !e666*/ 8558 } 8559 8560 /** for a multi-aggregated variable, gives the global lower bound computed by adding the global bounds from all 8561 * aggregation variables, this global bound may be tighter than the one given by SCIPvarGetLbGlobal, since the latter is 8562 * not updated if bounds of aggregation variables are changing 8563 * 8564 * calling this function for a non-multi-aggregated variable is not allowed 8565 */ 8566 SCIP_Real SCIPvarGetMultaggrLbGlobal( 8567 SCIP_VAR* var, /**< problem variable */ 8568 SCIP_SET* set /**< global SCIP settings */ 8569 ) 8570 { 8571 int i; 8572 SCIP_Real lb; 8573 SCIP_Real bnd; 8574 SCIP_VAR* aggrvar; 8575 SCIP_Bool posinf; 8576 SCIP_Bool neginf; 8577 8578 assert(var != NULL); 8579 assert(set != NULL); 8580 assert(var->scip == set->scip); 8581 assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR); 8582 8583 posinf = FALSE; 8584 neginf = FALSE; 8585 lb = var->data.multaggr.constant; 8586 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i ) 8587 { 8588 aggrvar = var->data.multaggr.vars[i]; 8589 if( var->data.multaggr.scalars[i] > 0.0 ) 8590 { 8591 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbGlobal(aggrvar, set) : SCIPvarGetLbGlobal(aggrvar); 8592 8593 if( SCIPsetIsInfinity(set, bnd) ) 8594 posinf = TRUE; 8595 else if( SCIPsetIsInfinity(set, -bnd) ) 8596 neginf = TRUE; 8597 else 8598 lb += var->data.multaggr.scalars[i] * bnd; 8599 } 8600 else 8601 { 8602 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbGlobal(aggrvar, set) : SCIPvarGetUbGlobal(aggrvar); 8603 8604 if( SCIPsetIsInfinity(set, -bnd) ) 8605 posinf = TRUE; 8606 else if( SCIPsetIsInfinity(set, bnd) ) 8607 neginf = TRUE; 8608 else 8609 lb += var->data.multaggr.scalars[i] * bnd; 8610 } 8611 8612 /* stop if two diffrent infinities (or a -infinity) were found and return global lower bound of multi aggregated 8613 * variable 8614 */ 8615 if( neginf ) 8616 return SCIPvarGetLbGlobal(var); 8617 } 8618 8619 /* if positive infinity flag was set to true return infinity */ 8620 if( posinf ) 8621 return SCIPsetInfinity(set); 8622 8623 return (MAX(lb, SCIPvarGetLbGlobal(var))); /*lint !e666*/ 8624 } 8625 8626 /** for a multi-aggregated variable, gives the global upper bound computed by adding the global bounds from all 8627 * aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbGlobal, since the latter is 8628 * not updated if bounds of aggregation variables are changing 8629 * 8630 * calling this function for a non-multi-aggregated variable is not allowed 8631 */ 8632 SCIP_Real SCIPvarGetMultaggrUbGlobal( 8633 SCIP_VAR* var, /**< problem variable */ 8634 SCIP_SET* set /**< global SCIP settings */ 8635 ) 8636 { 8637 int i; 8638 SCIP_Real ub; 8639 SCIP_Real bnd; 8640 SCIP_VAR* aggrvar; 8641 SCIP_Bool posinf; 8642 SCIP_Bool neginf; 8643 8644 assert(var != NULL); 8645 assert(set != NULL); 8646 assert(var->scip == set->scip); 8647 assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR); 8648 8649 posinf = FALSE; 8650 neginf = FALSE; 8651 ub = var->data.multaggr.constant; 8652 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i ) 8653 { 8654 aggrvar = var->data.multaggr.vars[i]; 8655 if( var->data.multaggr.scalars[i] > 0.0 ) 8656 { 8657 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbGlobal(aggrvar, set) : SCIPvarGetUbGlobal(aggrvar); 8658 8659 if( SCIPsetIsInfinity(set, bnd) ) 8660 posinf = TRUE; 8661 else if( SCIPsetIsInfinity(set, -bnd) ) 8662 neginf = TRUE; 8663 else 8664 ub += var->data.multaggr.scalars[i] * bnd; 8665 } 8666 else 8667 { 8668 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbGlobal(aggrvar, set) : SCIPvarGetLbGlobal(aggrvar); 8669 8670 if( SCIPsetIsInfinity(set, -bnd) ) 8671 posinf = TRUE; 8672 else if( SCIPsetIsInfinity(set, bnd) ) 8673 neginf = TRUE; 8674 else 8675 ub += var->data.multaggr.scalars[i] * bnd; 8676 } 8677 8678 /* stop if two diffrent infinities (or a -infinity) were found and return local upper bound of multi aggregated 8679 * variable 8680 */ 8681 if( posinf ) 8682 return SCIPvarGetUbGlobal(var); 8683 } 8684 8685 /* if negative infinity flag was set to true return -infinity */ 8686 if( neginf ) 8687 return -SCIPsetInfinity(set); 8688 8689 return (MIN(ub, SCIPvarGetUbGlobal(var))); /*lint !e666*/ 8690 } 8691 8692 /** adds a hole to the original domain of the variable */ 8693 SCIP_RETCODE SCIPvarAddHoleOriginal( 8694 SCIP_VAR* var, /**< problem variable */ 8695 BMS_BLKMEM* blkmem, /**< block memory */ 8696 SCIP_SET* set, /**< global SCIP settings */ 8697 SCIP_Real left, /**< left bound of open interval in new hole */ 8698 SCIP_Real right /**< right bound of open interval in new hole */ 8699 ) 8700 { 8701 SCIP_Bool added; 8702 8703 assert(var != NULL); 8704 assert(!SCIPvarIsTransformed(var)); 8705 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED); 8706 assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS); 8707 assert(set != NULL); 8708 assert(var->scip == set->scip); 8709 assert(set->stage == SCIP_STAGE_PROBLEM); 8710 8711 SCIPsetDebugMsg(set, "adding original hole (%g,%g) to <%s>\n", left, right, var->name); 8712 8713 if( SCIPsetIsEQ(set, left, right) ) 8714 return SCIP_OKAY; 8715 8716 /* the interval should not be empty */ 8717 assert(SCIPsetIsLT(set, left, right)); 8718 8719 /* the the interval bound should already be adjusted */ 8720 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left))); 8721 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right))); 8722 8723 /* the the interval should lay between the lower and upper bound */ 8724 assert(SCIPsetIsGE(set, left, SCIPvarGetLbOriginal(var))); 8725 assert(SCIPsetIsLE(set, right, SCIPvarGetUbOriginal(var))); 8726 8727 /* add domain hole */ 8728 SCIP_CALL( domAddHole(&var->data.original.origdom, blkmem, set, left, right, &added) ); 8729 8730 /* merges overlapping holes into single holes, moves bounds respectively if hole was added */ 8731 if( added ) 8732 { 8733 domMerge(&var->data.original.origdom, blkmem, set, NULL, NULL); 8734 } 8735 8736 /**@todo add hole in parent and child variables (just like with bound changes); 8737 * warning! original vars' holes are in original blkmem, transformed vars' holes in transformed blkmem 8738 */ 8739 8740 return SCIP_OKAY; 8741 } 8742 8743 /** performs the current add of domain, changes all parents accordingly */ 8744 static 8745 SCIP_RETCODE varProcessAddHoleGlobal( 8746 SCIP_VAR* var, /**< problem variable */ 8747 BMS_BLKMEM* blkmem, /**< block memory */ 8748 SCIP_SET* set, /**< global SCIP settings */ 8749 SCIP_STAT* stat, /**< problem statistics */ 8750 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 8751 SCIP_Real left, /**< left bound of open interval in new hole */ 8752 SCIP_Real right, /**< right bound of open interval in new hole */ 8753 SCIP_Bool* added /**< pointer to store whether the hole was added */ 8754 ) 8755 { 8756 SCIP_VAR* parentvar; 8757 SCIP_Real newlb; 8758 SCIP_Real newub; 8759 int i; 8760 8761 assert(var != NULL); 8762 assert(added != NULL); 8763 assert(blkmem != NULL); 8764 8765 /* the interval should not be empty */ 8766 assert(SCIPsetIsLT(set, left, right)); 8767 8768 /* the interval bound should already be adjusted */ 8769 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left))); 8770 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right))); 8771 8772 /* the interval should lay between the lower and upper bound */ 8773 assert(SCIPsetIsGE(set, left, SCIPvarGetLbGlobal(var))); 8774 assert(SCIPsetIsLE(set, right, SCIPvarGetUbGlobal(var))); 8775 8776 /* @todo add debugging mechanism for holes when using a debugging solution */ 8777 8778 /* add hole to hole list */ 8779 SCIP_CALL( domAddHole(&var->glbdom, blkmem, set, left, right, added) ); 8780 8781 /* check if the hole is redundant */ 8782 if( !(*added) ) 8783 return SCIP_OKAY; 8784 8785 /* current bounds */ 8786 newlb = var->glbdom.lb; 8787 newub = var->glbdom.ub; 8788 8789 /* merge domain holes */ 8790 domMerge(&var->glbdom, blkmem, set, &newlb, &newub); 8791 8792 /* the bound should not be changed */ 8793 assert(SCIPsetIsEQ(set, newlb, var->glbdom.lb)); 8794 assert(SCIPsetIsEQ(set, newub, var->glbdom.ub)); 8795 8796 /* issue bound change event */ 8797 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL)); 8798 if( var->eventfilter != NULL ) 8799 { 8800 SCIP_CALL( varEventGholeAdded(var, blkmem, set, eventqueue, left, right) ); 8801 } 8802 8803 /* process parent variables */ 8804 for( i = 0; i < var->nparentvars; ++i ) 8805 { 8806 SCIP_Real parentnewleft; 8807 SCIP_Real parentnewright; 8808 SCIP_Bool localadded; 8809 8810 parentvar = var->parentvars[i]; 8811 assert(parentvar != NULL); 8812 8813 switch( SCIPvarGetStatus(parentvar) ) 8814 { 8815 case SCIP_VARSTATUS_ORIGINAL: 8816 parentnewleft = left; 8817 parentnewright = right; 8818 break; 8819 8820 case SCIP_VARSTATUS_COLUMN: 8821 case SCIP_VARSTATUS_LOOSE: 8822 case SCIP_VARSTATUS_FIXED: 8823 case SCIP_VARSTATUS_MULTAGGR: 8824 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n"); 8825 return SCIP_INVALIDDATA; 8826 8827 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 8828 assert(parentvar->data.aggregate.var == var); 8829 8830 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) ) 8831 { 8832 /* a > 0 -> change upper bound of x */ 8833 parentnewleft = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant; 8834 parentnewright = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant; 8835 } 8836 else 8837 { 8838 /* a < 0 -> change lower bound of x */ 8839 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar)); 8840 8841 parentnewright = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant; 8842 parentnewleft = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant; 8843 } 8844 break; 8845 8846 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */ 8847 assert(parentvar->negatedvar != NULL); 8848 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED); 8849 assert(parentvar->negatedvar->negatedvar == parentvar); 8850 8851 parentnewright = -left + parentvar->data.negate.constant; 8852 parentnewleft = -right + parentvar->data.negate.constant; 8853 break; 8854 8855 default: 8856 SCIPerrorMessage("unknown variable status\n"); 8857 return SCIP_INVALIDDATA; 8858 } 8859 8860 SCIPsetDebugMsg(set, "add global hole (%g,%g) to parent variable <%s>\n", parentnewleft, parentnewright, SCIPvarGetName(parentvar)); 8861 8862 /* perform hole added for parent variable */ 8863 assert(blkmem != NULL); 8864 assert(SCIPsetIsLT(set, parentnewleft, parentnewright)); 8865 SCIP_CALL( varProcessAddHoleGlobal(parentvar, blkmem, set, stat, eventqueue, 8866 parentnewleft, parentnewright, &localadded) ); 8867 assert(localadded); 8868 } 8869 8870 return SCIP_OKAY; 8871 } 8872 8873 /** adds a hole to the variable's global and local domain */ 8874 SCIP_RETCODE SCIPvarAddHoleGlobal( 8875 SCIP_VAR* var, /**< problem variable */ 8876 BMS_BLKMEM* blkmem, /**< block memory */ 8877 SCIP_SET* set, /**< global SCIP settings */ 8878 SCIP_STAT* stat, /**< problem statistics */ 8879 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 8880 SCIP_Real left, /**< left bound of open interval in new hole */ 8881 SCIP_Real right, /**< right bound of open interval in new hole */ 8882 SCIP_Bool* added /**< pointer to store whether the hole was added */ 8883 ) 8884 { 8885 SCIP_Real childnewleft; 8886 SCIP_Real childnewright; 8887 8888 assert(var != NULL); 8889 assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS); 8890 assert(blkmem != NULL); 8891 assert(added != NULL); 8892 8893 SCIPsetDebugMsg(set, "adding global hole (%g,%g) to <%s>\n", left, right, var->name); 8894 8895 /* the interval should not be empty */ 8896 assert(SCIPsetIsLT(set, left, right)); 8897 8898 /* the the interval bound should already be adjusted */ 8899 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left))); 8900 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right))); 8901 8902 /* the the interval should lay between the lower and upper bound */ 8903 assert(SCIPsetIsGE(set, left, SCIPvarGetLbGlobal(var))); 8904 assert(SCIPsetIsLE(set, right, SCIPvarGetUbGlobal(var))); 8905 8906 /* change bounds of attached variables */ 8907 switch( SCIPvarGetStatus(var) ) 8908 { 8909 case SCIP_VARSTATUS_ORIGINAL: 8910 if( var->data.original.transvar != NULL ) 8911 { 8912 SCIP_CALL( SCIPvarAddHoleGlobal(var->data.original.transvar, blkmem, set, stat, eventqueue, 8913 left, right, added) ); 8914 } 8915 else 8916 { 8917 assert(set->stage == SCIP_STAGE_PROBLEM); 8918 8919 SCIP_CALL( varProcessAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) ); 8920 if( *added ) 8921 { 8922 SCIP_Bool localadded; 8923 8924 SCIP_CALL( SCIPvarAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, &localadded) ); 8925 } 8926 } 8927 break; 8928 8929 case SCIP_VARSTATUS_COLUMN: 8930 case SCIP_VARSTATUS_LOOSE: 8931 SCIP_CALL( varProcessAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) ); 8932 if( *added ) 8933 { 8934 SCIP_Bool localadded; 8935 8936 SCIP_CALL( SCIPvarAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, &localadded) ); 8937 } 8938 break; 8939 8940 case SCIP_VARSTATUS_FIXED: 8941 SCIPerrorMessage("cannot add hole of a fixed variable\n"); 8942 return SCIP_INVALIDDATA; 8943 8944 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 8945 assert(var->data.aggregate.var != NULL); 8946 8947 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) ) 8948 { 8949 /* a > 0 -> change lower bound of y */ 8950 childnewleft = (left - var->data.aggregate.constant)/var->data.aggregate.scalar; 8951 childnewright = (right - var->data.aggregate.constant)/var->data.aggregate.scalar; 8952 } 8953 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) ) 8954 { 8955 childnewright = (left - var->data.aggregate.constant)/var->data.aggregate.scalar; 8956 childnewleft = (right - var->data.aggregate.constant)/var->data.aggregate.scalar; 8957 } 8958 else 8959 { 8960 SCIPerrorMessage("scalar is zero in aggregation\n"); 8961 return SCIP_INVALIDDATA; 8962 } 8963 SCIP_CALL( SCIPvarAddHoleGlobal(var->data.aggregate.var, blkmem, set, stat, eventqueue, 8964 childnewleft, childnewright, added) ); 8965 break; 8966 8967 case SCIP_VARSTATUS_MULTAGGR: 8968 SCIPerrorMessage("cannot add a hole of a multi-aggregated variable.\n"); 8969 return SCIP_INVALIDDATA; 8970 8971 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 8972 assert(var->negatedvar != NULL); 8973 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 8974 assert(var->negatedvar->negatedvar == var); 8975 8976 childnewright = -left + var->data.negate.constant; 8977 childnewleft = -right + var->data.negate.constant; 8978 8979 SCIP_CALL( SCIPvarAddHoleGlobal(var->negatedvar, blkmem, set, stat, eventqueue, 8980 childnewleft, childnewright, added) ); 8981 break; 8982 8983 default: 8984 SCIPerrorMessage("unknown variable status\n"); 8985 return SCIP_INVALIDDATA; 8986 } 8987 8988 return SCIP_OKAY; 8989 } 8990 8991 /** performs the current add of domain, changes all parents accordingly */ 8992 static 8993 SCIP_RETCODE varProcessAddHoleLocal( 8994 SCIP_VAR* var, /**< problem variable */ 8995 BMS_BLKMEM* blkmem, /**< block memory */ 8996 SCIP_SET* set, /**< global SCIP settings */ 8997 SCIP_STAT* stat, /**< problem statistics */ 8998 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 8999 SCIP_Real left, /**< left bound of open interval in new hole */ 9000 SCIP_Real right, /**< right bound of open interval in new hole */ 9001 SCIP_Bool* added /**< pointer to store whether the hole was added, or NULL */ 9002 ) 9003 { 9004 SCIP_VAR* parentvar; 9005 SCIP_Real newlb; 9006 SCIP_Real newub; 9007 int i; 9008 9009 assert(var != NULL); 9010 assert(added != NULL); 9011 assert(blkmem != NULL); 9012 9013 /* the interval should not be empty */ 9014 assert(SCIPsetIsLT(set, left, right)); 9015 9016 /* the the interval bound should already be adjusted */ 9017 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left))); 9018 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right))); 9019 9020 /* the the interval should lay between the lower and upper bound */ 9021 assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var))); 9022 assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var))); 9023 9024 /* add hole to hole list */ 9025 SCIP_CALL( domAddHole(&var->locdom, blkmem, set, left, right, added) ); 9026 9027 /* check if the hole is redundant */ 9028 if( !(*added) ) 9029 return SCIP_OKAY; 9030 9031 /* current bounds */ 9032 newlb = var->locdom.lb; 9033 newub = var->locdom.ub; 9034 9035 /* merge domain holes */ 9036 domMerge(&var->locdom, blkmem, set, &newlb, &newub); 9037 9038 /* the bound should not be changed */ 9039 assert(SCIPsetIsEQ(set, newlb, var->locdom.lb)); 9040 assert(SCIPsetIsEQ(set, newub, var->locdom.ub)); 9041 9042 #if 0 9043 /* issue bound change event */ 9044 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL)); 9045 if( var->eventfilter != NULL ) 9046 { 9047 SCIP_CALL( varEventLholeAdded(var, blkmem, set, lp, branchcand, eventqueue, left, right) ); 9048 } 9049 #endif 9050 9051 /* process parent variables */ 9052 for( i = 0; i < var->nparentvars; ++i ) 9053 { 9054 SCIP_Real parentnewleft; 9055 SCIP_Real parentnewright; 9056 SCIP_Bool localadded; 9057 9058 parentvar = var->parentvars[i]; 9059 assert(parentvar != NULL); 9060 9061 switch( SCIPvarGetStatus(parentvar) ) 9062 { 9063 case SCIP_VARSTATUS_ORIGINAL: 9064 parentnewleft = left; 9065 parentnewright = right; 9066 break; 9067 9068 case SCIP_VARSTATUS_COLUMN: 9069 case SCIP_VARSTATUS_LOOSE: 9070 case SCIP_VARSTATUS_FIXED: 9071 case SCIP_VARSTATUS_MULTAGGR: 9072 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n"); 9073 return SCIP_INVALIDDATA; 9074 9075 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 9076 assert(parentvar->data.aggregate.var == var); 9077 9078 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) ) 9079 { 9080 /* a > 0 -> change upper bound of x */ 9081 parentnewleft = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant; 9082 parentnewright = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant; 9083 } 9084 else 9085 { 9086 /* a < 0 -> change lower bound of x */ 9087 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar)); 9088 9089 parentnewright = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant; 9090 parentnewleft = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant; 9091 } 9092 break; 9093 9094 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */ 9095 assert(parentvar->negatedvar != NULL); 9096 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED); 9097 assert(parentvar->negatedvar->negatedvar == parentvar); 9098 9099 parentnewright = -left + parentvar->data.negate.constant; 9100 parentnewleft = -right + parentvar->data.negate.constant; 9101 break; 9102 9103 default: 9104 SCIPerrorMessage("unknown variable status\n"); 9105 return SCIP_INVALIDDATA; 9106 } 9107 9108 SCIPsetDebugMsg(set, "add local hole (%g,%g) to parent variable <%s>\n", parentnewleft, parentnewright, SCIPvarGetName(parentvar)); 9109 9110 /* perform hole added for parent variable */ 9111 assert(blkmem != NULL); 9112 assert(SCIPsetIsLT(set, parentnewleft, parentnewright)); 9113 SCIP_CALL( varProcessAddHoleLocal(parentvar, blkmem, set, stat, eventqueue, 9114 parentnewleft, parentnewright, &localadded) ); 9115 assert(localadded); 9116 } 9117 9118 return SCIP_OKAY; 9119 } 9120 9121 /** adds a hole to the variable's current local domain */ 9122 SCIP_RETCODE SCIPvarAddHoleLocal( 9123 SCIP_VAR* var, /**< problem variable */ 9124 BMS_BLKMEM* blkmem, /**< block memory */ 9125 SCIP_SET* set, /**< global SCIP settings */ 9126 SCIP_STAT* stat, /**< problem statistics */ 9127 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */ 9128 SCIP_Real left, /**< left bound of open interval in new hole */ 9129 SCIP_Real right, /**< right bound of open interval in new hole */ 9130 SCIP_Bool* added /**< pointer to store whether the hole was added */ 9131 ) 9132 { 9133 SCIP_Real childnewleft; 9134 SCIP_Real childnewright; 9135 9136 assert(var != NULL); 9137 9138 SCIPsetDebugMsg(set, "adding local hole (%g,%g) to <%s>\n", left, right, var->name); 9139 9140 assert(set != NULL); 9141 assert(var->scip == set->scip); 9142 assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS); 9143 assert(blkmem != NULL); 9144 assert(added != NULL); 9145 9146 /* the interval should not be empty */ 9147 assert(SCIPsetIsLT(set, left, right)); 9148 9149 /* the the interval bound should already be adjusted */ 9150 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left))); 9151 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right))); 9152 9153 /* the the interval should lay between the lower and upper bound */ 9154 assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var))); 9155 assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var))); 9156 9157 /* change bounds of attached variables */ 9158 switch( SCIPvarGetStatus(var) ) 9159 { 9160 case SCIP_VARSTATUS_ORIGINAL: 9161 if( var->data.original.transvar != NULL ) 9162 { 9163 SCIP_CALL( SCIPvarAddHoleLocal(var->data.original.transvar, blkmem, set, stat, eventqueue, 9164 left, right, added) ); 9165 } 9166 else 9167 { 9168 assert(set->stage == SCIP_STAGE_PROBLEM); 9169 SCIPstatIncrement(stat, set, domchgcount); 9170 SCIP_CALL( varProcessAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, added) ); 9171 } 9172 break; 9173 9174 case SCIP_VARSTATUS_COLUMN: 9175 case SCIP_VARSTATUS_LOOSE: 9176 SCIPstatIncrement(stat, set, domchgcount); 9177 SCIP_CALL( varProcessAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, added) ); 9178 break; 9179 9180 case SCIP_VARSTATUS_FIXED: 9181 SCIPerrorMessage("cannot add domain hole to a fixed variable\n"); 9182 return SCIP_INVALIDDATA; 9183 9184 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 9185 assert(var->data.aggregate.var != NULL); 9186 9187 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) ) 9188 { 9189 /* a > 0 -> change lower bound of y */ 9190 childnewleft = (left - var->data.aggregate.constant)/var->data.aggregate.scalar; 9191 childnewright = (right - var->data.aggregate.constant)/var->data.aggregate.scalar; 9192 } 9193 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) ) 9194 { 9195 childnewright = (left - var->data.aggregate.constant)/var->data.aggregate.scalar; 9196 childnewleft = (right - var->data.aggregate.constant)/var->data.aggregate.scalar; 9197 } 9198 else 9199 { 9200 SCIPerrorMessage("scalar is zero in aggregation\n"); 9201 return SCIP_INVALIDDATA; 9202 } 9203 SCIP_CALL( SCIPvarAddHoleLocal(var->data.aggregate.var, blkmem, set, stat, eventqueue, 9204 childnewleft, childnewright, added) ); 9205 break; 9206 9207 case SCIP_VARSTATUS_MULTAGGR: 9208 SCIPerrorMessage("cannot add domain hole to a multi-aggregated variable.\n"); 9209 return SCIP_INVALIDDATA; 9210 9211 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 9212 assert(var->negatedvar != NULL); 9213 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 9214 assert(var->negatedvar->negatedvar == var); 9215 9216 childnewright = -left + var->data.negate.constant; 9217 childnewleft = -right + var->data.negate.constant; 9218 9219 SCIP_CALL( SCIPvarAddHoleLocal(var->negatedvar, blkmem, set, stat, eventqueue, childnewleft, childnewright, added) ); 9220 break; 9221 9222 default: 9223 SCIPerrorMessage("unknown variable status\n"); 9224 return SCIP_INVALIDDATA; 9225 } 9226 9227 return SCIP_OKAY; 9228 } 9229 9230 /** resets the global and local bounds of original variable to their original values */ 9231 SCIP_RETCODE SCIPvarResetBounds( 9232 SCIP_VAR* var, /**< problem variable */ 9233 BMS_BLKMEM* blkmem, /**< block memory */ 9234 SCIP_SET* set, /**< global SCIP settings */ 9235 SCIP_STAT* stat /**< problem statistics */ 9236 ) 9237 { 9238 assert(var != NULL); 9239 assert(set != NULL); 9240 assert(var->scip == set->scip); 9241 assert(SCIPvarIsOriginal(var)); 9242 /* resetting of bounds on original variables which have a transformed counterpart easily fails if, e.g., 9243 * the transformed variable has been fixed */ 9244 assert(SCIPvarGetTransVar(var) == NULL); 9245 9246 /* copy the original bounds back to the global and local bounds */ 9247 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, NULL, NULL, NULL, NULL, var->data.original.origdom.lb) ); 9248 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, NULL, NULL, NULL, NULL, var->data.original.origdom.ub) ); 9249 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.lb) ); 9250 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.ub) ); 9251 9252 /* free the global and local holelists and duplicate the original ones */ 9253 /**@todo this has also to be called recursively with methods similar to SCIPvarChgLbGlobal() */ 9254 holelistFree(&var->glbdom.holelist, blkmem); 9255 holelistFree(&var->locdom.holelist, blkmem); 9256 SCIP_CALL( holelistDuplicate(&var->glbdom.holelist, blkmem, set, var->data.original.origdom.holelist) ); 9257 SCIP_CALL( holelistDuplicate(&var->locdom.holelist, blkmem, set, var->data.original.origdom.holelist) ); 9258 9259 return SCIP_OKAY; 9260 } 9261 9262 /** issues a IMPLADDED event on the given variable */ 9263 static 9264 SCIP_RETCODE varEventImplAdded( 9265 SCIP_VAR* var, /**< problem variable to change */ 9266 BMS_BLKMEM* blkmem, /**< block memory */ 9267 SCIP_SET* set, /**< global SCIP settings */ 9268 SCIP_EVENTQUEUE* eventqueue /**< event queue */ 9269 ) 9270 { 9271 SCIP_EVENT* event; 9272 9273 assert(var != NULL); 9274 9275 /* issue IMPLADDED event on variable */ 9276 SCIP_CALL( SCIPeventCreateImplAdded(&event, blkmem, var) ); 9277 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) ); 9278 9279 return SCIP_OKAY; 9280 } 9281 9282 /** actually performs the addition of a variable bound to the variable's vbound arrays */ 9283 static 9284 SCIP_RETCODE varAddVbound( 9285 SCIP_VAR* var, /**< problem variable x in x <= b*z + d or x >= b*z + d */ 9286 BMS_BLKMEM* blkmem, /**< block memory */ 9287 SCIP_SET* set, /**< global SCIP settings */ 9288 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 9289 SCIP_BOUNDTYPE vbtype, /**< type of variable bound (LOWER or UPPER) */ 9290 SCIP_VAR* vbvar, /**< variable z in x <= b*z + d or x >= b*z + d */ 9291 SCIP_Real vbcoef, /**< coefficient b in x <= b*z + d or x >= b*z + d */ 9292 SCIP_Real vbconstant /**< constant d in x <= b*z + d or x >= b*z + d */ 9293 ) 9294 { 9295 SCIP_Bool added; 9296 9297 /* It can happen that the variable "var" and the variable "vbvar" are the same variable. For example if a variable 9298 * gets aggregated, the variable bounds (vbound) of that variable are copied to the other variable. A variable bound 9299 * variable of the aggregated variable might be the same as the one its gets aggregated too. 9300 * 9301 * If the variable "var" and the variable "vbvar" are the same, the variable bound which should be added here has to 9302 * be redundant. This is the case since an infeasibility should have be detected in the previous methods. As well as 9303 * the bounds of the variable which should be also already be tightened in the previous methods. Therefore, the 9304 * variable bound can be ignored. 9305 * 9306 * From the way the the variable bound system is implemented (detecting infeasibility, tighten bounds), the 9307 * equivalence of the variables should be checked here. 9308 */ 9309 if( var == vbvar ) 9310 { 9311 /* in this case the variable bound has to be redundant, this means for possible assignments to this variable; this 9312 * can be checked via the global bounds of the variable */ 9313 #ifndef NDEBUG 9314 SCIP_Real lb; 9315 SCIP_Real ub; 9316 9317 lb = SCIPvarGetLbGlobal(var); 9318 ub = SCIPvarGetUbGlobal(var); 9319 9320 if(vbtype == SCIP_BOUNDTYPE_LOWER) 9321 { 9322 if( vbcoef > 0.0 ) 9323 { 9324 assert(SCIPsetIsGE(set, lb, lb * vbcoef + vbconstant) ); 9325 assert(SCIPsetIsGE(set, ub, ub * vbcoef + vbconstant) ); 9326 } 9327 else 9328 { 9329 assert(SCIPsetIsGE(set, lb, ub * vbcoef + vbconstant) ); 9330 assert(SCIPsetIsGE(set, ub, lb * vbcoef + vbconstant) ); 9331 } 9332 } 9333 else 9334 { 9335 assert(vbtype == SCIP_BOUNDTYPE_UPPER); 9336 if( vbcoef > 0.0 ) 9337 { 9338 assert(SCIPsetIsLE(set, lb, lb * vbcoef + vbconstant) ); 9339 assert(SCIPsetIsLE(set, ub, ub * vbcoef + vbconstant) ); 9340 } 9341 else 9342 { 9343 assert(SCIPsetIsLE(set, lb, ub * vbcoef + vbconstant) ); 9344 assert(SCIPsetIsLE(set, ub, lb * vbcoef + vbconstant) ); 9345 } 9346 } 9347 #endif 9348 SCIPsetDebugMsg(set, "redundant variable bound: <%s> %s %g<%s> %+g\n", 9349 SCIPvarGetName(var), vbtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", vbcoef, SCIPvarGetName(vbvar), vbconstant); 9350 9351 return SCIP_OKAY; 9352 } 9353 9354 SCIPsetDebugMsg(set, "adding variable bound: <%s> %s %g<%s> %+g\n", 9355 SCIPvarGetName(var), vbtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", vbcoef, SCIPvarGetName(vbvar), vbconstant); 9356 9357 /* check variable bound on debugging solution */ 9358 SCIP_CALL( SCIPdebugCheckVbound(set, var, vbtype, vbvar, vbcoef, vbconstant) ); /*lint !e506 !e774*/ 9359 9360 /* perform the addition */ 9361 if( vbtype == SCIP_BOUNDTYPE_LOWER ) 9362 { 9363 SCIP_CALL( SCIPvboundsAdd(&var->vlbs, blkmem, set, vbtype, vbvar, vbcoef, vbconstant, &added) ); 9364 } 9365 else 9366 { 9367 SCIP_CALL( SCIPvboundsAdd(&var->vubs, blkmem, set, vbtype, vbvar, vbcoef, vbconstant, &added) ); 9368 } 9369 var->closestvblpcount = -1; 9370 9371 if( added ) 9372 { 9373 /* issue IMPLADDED event */ 9374 SCIP_CALL( varEventImplAdded(var, blkmem, set, eventqueue) ); 9375 } 9376 9377 return SCIP_OKAY; 9378 } 9379 9380 /** checks whether the given implication is redundant or infeasible w.r.t. the implied variables global bounds */ 9381 static 9382 void checkImplic( 9383 SCIP_SET* set, /**< global SCIP settings */ 9384 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */ 9385 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */ 9386 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */ 9387 SCIP_Bool* redundant, /**< pointer to store whether the implication is redundant */ 9388 SCIP_Bool* infeasible /**< pointer to store whether the implication is infeasible */ 9389 ) 9390 { 9391 SCIP_Real impllb; 9392 SCIP_Real implub; 9393 9394 assert(redundant != NULL); 9395 assert(infeasible != NULL); 9396 9397 impllb = SCIPvarGetLbGlobal(implvar); 9398 implub = SCIPvarGetUbGlobal(implvar); 9399 if( impltype == SCIP_BOUNDTYPE_LOWER ) 9400 { 9401 *infeasible = SCIPsetIsFeasGT(set, implbound, implub); 9402 *redundant = SCIPsetIsFeasLE(set, implbound, impllb); 9403 } 9404 else 9405 { 9406 *infeasible = SCIPsetIsFeasLT(set, implbound, impllb); 9407 *redundant = SCIPsetIsFeasGE(set, implbound, implub); 9408 } 9409 } 9410 9411 /** applies the given implication, if it is not redundant */ 9412 static 9413 SCIP_RETCODE applyImplic( 9414 BMS_BLKMEM* blkmem, /**< block memory */ 9415 SCIP_SET* set, /**< global SCIP settings */ 9416 SCIP_STAT* stat, /**< problem statistics */ 9417 SCIP_PROB* transprob, /**< transformed problem */ 9418 SCIP_PROB* origprob, /**< original problem */ 9419 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */ 9420 SCIP_REOPT* reopt, /**< reoptimization data structure */ 9421 SCIP_LP* lp, /**< current LP data */ 9422 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 9423 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 9424 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 9425 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */ 9426 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */ 9427 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */ 9428 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */ 9429 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */ 9430 ) 9431 { 9432 SCIP_Real implub; 9433 SCIP_Real impllb; 9434 9435 assert(infeasible != NULL); 9436 9437 *infeasible = FALSE; 9438 9439 implub = SCIPvarGetUbGlobal(implvar); 9440 impllb = SCIPvarGetLbGlobal(implvar); 9441 if( impltype == SCIP_BOUNDTYPE_LOWER ) 9442 { 9443 if( SCIPsetIsFeasGT(set, implbound, implub) ) 9444 { 9445 /* the implication produces a conflict: the problem is infeasible */ 9446 *infeasible = TRUE; 9447 } 9448 else if( SCIPsetIsFeasGT(set, implbound, impllb) ) 9449 { 9450 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 9451 * with the local bound, in this case we need to store the bound change as pending bound change 9452 */ 9453 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 9454 { 9455 assert(tree != NULL); 9456 assert(transprob != NULL); 9457 assert(SCIPprobIsTransformed(transprob)); 9458 9459 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 9460 tree, reopt, lp, branchcand, eventqueue, cliquetable, implvar, implbound, SCIP_BOUNDTYPE_LOWER, FALSE) ); 9461 } 9462 else 9463 { 9464 SCIP_CALL( SCIPvarChgLbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, implbound) ); 9465 } 9466 9467 if( nbdchgs != NULL ) 9468 (*nbdchgs)++; 9469 } 9470 } 9471 else 9472 { 9473 if( SCIPsetIsFeasLT(set, implbound, impllb) ) 9474 { 9475 /* the implication produces a conflict: the problem is infeasible */ 9476 *infeasible = TRUE; 9477 } 9478 else if( SCIPsetIsFeasLT(set, implbound, implub) ) 9479 { 9480 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 9481 * with the local bound, in this case we need to store the bound change as pending bound change 9482 */ 9483 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 9484 { 9485 assert(tree != NULL); 9486 assert(transprob != NULL); 9487 assert(SCIPprobIsTransformed(transprob)); 9488 9489 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 9490 tree, reopt, lp, branchcand, eventqueue, cliquetable, implvar, implbound, SCIP_BOUNDTYPE_UPPER, FALSE) ); 9491 } 9492 else 9493 { 9494 SCIP_CALL( SCIPvarChgUbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, implbound) ); 9495 } 9496 9497 if( nbdchgs != NULL ) 9498 (*nbdchgs)++; 9499 } 9500 } 9501 9502 return SCIP_OKAY; 9503 } 9504 9505 /** actually performs the addition of an implication to the variable's implication arrays, 9506 * and adds the corresponding implication or variable bound to the implied variable; 9507 * if the implication is conflicting, the variable is fixed to the opposite value; 9508 * if the variable is already fixed to the given value, the implication is performed immediately; 9509 * if the implication is redundant with respect to the variables' global bounds, it is ignored 9510 */ 9511 static 9512 SCIP_RETCODE varAddImplic( 9513 SCIP_VAR* var, /**< problem variable */ 9514 BMS_BLKMEM* blkmem, /**< block memory */ 9515 SCIP_SET* set, /**< global SCIP settings */ 9516 SCIP_STAT* stat, /**< problem statistics */ 9517 SCIP_PROB* transprob, /**< transformed problem */ 9518 SCIP_PROB* origprob, /**< original problem */ 9519 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */ 9520 SCIP_REOPT* reopt, /**< reoptimization data structure */ 9521 SCIP_LP* lp, /**< current LP data */ 9522 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 9523 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 9524 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 9525 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */ 9526 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */ 9527 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */ 9528 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */ 9529 SCIP_Bool isshortcut, /**< is the implication a shortcut, i.e., added as part of the transitive closure of another implication? */ 9530 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */ 9531 int* nbdchgs, /**< pointer to count the number of performed bound changes, or NULL */ 9532 SCIP_Bool* added /**< pointer to store whether an implication was added */ 9533 ) 9534 { 9535 SCIP_Bool redundant; 9536 SCIP_Bool conflict; 9537 9538 assert(var != NULL); 9539 assert(SCIPvarIsActive(var)); 9540 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 9541 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY); 9542 assert(SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED); 9543 assert(infeasible != NULL); 9544 assert(added != NULL); 9545 9546 /* check implication on debugging solution */ 9547 SCIP_CALL( SCIPdebugCheckImplic(set, var, varfixing, implvar, impltype, implbound) ); /*lint !e506 !e774*/ 9548 9549 *infeasible = FALSE; 9550 *added = FALSE; 9551 9552 /* check, if the implication is redundant or infeasible */ 9553 checkImplic(set, implvar, impltype, implbound, &redundant, &conflict); 9554 assert(!redundant || !conflict); 9555 if( redundant ) 9556 return SCIP_OKAY; 9557 9558 if( var == implvar ) 9559 { 9560 /* special cases appear were a bound to a variable implies itself to be outside the bounds: 9561 * x == varfixing => x < 0 or x > 1 9562 */ 9563 if( SCIPsetIsLT(set, implbound, 0.0) || SCIPsetIsGT(set, implbound, 1.0) ) 9564 conflict = TRUE; 9565 else 9566 { 9567 /* variable implies itself: x == varfixing => x == (impltype == SCIP_BOUNDTYPE_LOWER) */ 9568 assert(SCIPsetIsZero(set, implbound) || SCIPsetIsEQ(set, implbound, 1.0)); 9569 assert(SCIPsetIsZero(set, implbound) == (impltype == SCIP_BOUNDTYPE_UPPER)); 9570 assert(SCIPsetIsEQ(set, implbound, 1.0) == (impltype == SCIP_BOUNDTYPE_LOWER)); 9571 conflict = conflict || ((varfixing == TRUE) == (impltype == SCIP_BOUNDTYPE_UPPER)); 9572 if( !conflict ) 9573 return SCIP_OKAY; 9574 } 9575 } 9576 9577 /* check, if the variable is already fixed */ 9578 if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 ) 9579 { 9580 /* if the variable is fixed to the given value, perform the implication; otherwise, ignore the implication */ 9581 if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) ) 9582 { 9583 SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue, 9584 cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) ); 9585 } 9586 return SCIP_OKAY; 9587 } 9588 9589 assert((impltype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, implbound, SCIPvarGetLbGlobal(implvar))) 9590 || (impltype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, implbound, SCIPvarGetUbGlobal(implvar)))); 9591 9592 if( !conflict ) 9593 { 9594 assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */ 9595 9596 if( SCIPvarIsBinary(implvar) ) 9597 { 9598 SCIP_VAR* vars[2]; 9599 SCIP_Bool vals[2]; 9600 9601 assert(SCIPsetIsFeasEQ(set, implbound, 1.0) || SCIPsetIsFeasZero(set, implbound)); 9602 assert((impltype == SCIP_BOUNDTYPE_UPPER) == SCIPsetIsFeasZero(set, implbound)); 9603 9604 vars[0] = var; 9605 vars[1] = implvar; 9606 vals[0] = varfixing; 9607 vals[1] = (impltype == SCIP_BOUNDTYPE_UPPER); 9608 9609 /* add the clique to the clique table */ 9610 SCIP_CALL( SCIPcliquetableAdd(cliquetable, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, 9611 eventqueue, vars, vals, 2, FALSE, &conflict, nbdchgs) ); 9612 9613 if( !conflict ) 9614 return SCIP_OKAY; 9615 } 9616 else 9617 { 9618 /* add implication x == 0/1 -> y <= b / y >= b to the implications list of x */ 9619 SCIPsetDebugMsg(set, "adding implication: <%s> == %u ==> <%s> %s %g\n", 9620 SCIPvarGetName(var), varfixing, 9621 SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_UPPER ? "<=" : ">=", implbound); 9622 SCIP_CALL( SCIPimplicsAdd(&var->implics, blkmem, set, stat, varfixing, implvar, impltype, implbound, 9623 isshortcut, &conflict, added) ); 9624 } 9625 } 9626 assert(!conflict || !(*added)); 9627 9628 /* on conflict, fix the variable to the opposite value */ 9629 if( conflict ) 9630 { 9631 SCIPsetDebugMsg(set, " -> implication yields a conflict: fix <%s> == %d\n", SCIPvarGetName(var), !varfixing); 9632 9633 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 9634 * with the local bound, in this case we need to store the bound change as pending bound change 9635 */ 9636 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 9637 { 9638 assert(tree != NULL); 9639 assert(transprob != NULL); 9640 assert(SCIPprobIsTransformed(transprob)); 9641 9642 if( varfixing ) 9643 { 9644 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 9645 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) ); 9646 } 9647 else 9648 { 9649 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 9650 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) ); 9651 } 9652 } 9653 else 9654 { 9655 if( varfixing ) 9656 { 9657 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 0.0) ); 9658 } 9659 else 9660 { 9661 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 1.0) ); 9662 } 9663 } 9664 if( nbdchgs != NULL ) 9665 (*nbdchgs)++; 9666 9667 return SCIP_OKAY; 9668 } 9669 else if( *added ) 9670 { 9671 /* issue IMPLADDED event */ 9672 SCIP_CALL( varEventImplAdded(var, blkmem, set, eventqueue) ); 9673 } 9674 else 9675 { 9676 /* the implication was redundant: the inverse is also redundant */ 9677 return SCIP_OKAY; 9678 } 9679 9680 assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */ 9681 9682 /* check, whether implied variable is binary */ 9683 if( !SCIPvarIsBinary(implvar) ) 9684 { 9685 SCIP_Real lb; 9686 SCIP_Real ub; 9687 9688 /* add inverse variable bound to the variable bounds of y with global bounds y \in [lb,ub]: 9689 * x == 0 -> y <= b <-> y <= (ub - b)*x + b 9690 * x == 1 -> y <= b <-> y <= (b - ub)*x + ub 9691 * x == 0 -> y >= b <-> y >= (lb - b)*x + b 9692 * x == 1 -> y >= b <-> y >= (b - lb)*x + lb 9693 * for numerical reasons, ignore variable bounds with large absolute coefficient 9694 */ 9695 lb = SCIPvarGetLbGlobal(implvar); 9696 ub = SCIPvarGetUbGlobal(implvar); 9697 if( impltype == SCIP_BOUNDTYPE_UPPER ) 9698 { 9699 if( REALABS(implbound - ub) <= MAXABSVBCOEF ) 9700 { 9701 SCIP_CALL( varAddVbound(implvar, blkmem, set, eventqueue, SCIP_BOUNDTYPE_UPPER, var, 9702 varfixing ? implbound - ub : ub - implbound, varfixing ? ub : implbound) ); 9703 } 9704 } 9705 else 9706 { 9707 if( REALABS(implbound - lb) <= MAXABSVBCOEF ) 9708 { 9709 SCIP_CALL( varAddVbound(implvar, blkmem, set, eventqueue, SCIP_BOUNDTYPE_LOWER, var, 9710 varfixing ? implbound - lb : lb - implbound, varfixing ? lb : implbound) ); 9711 } 9712 } 9713 } 9714 9715 return SCIP_OKAY; 9716 } 9717 9718 /** adds transitive closure for binary implication x = a -> y = b */ 9719 static 9720 SCIP_RETCODE varAddTransitiveBinaryClosureImplic( 9721 SCIP_VAR* var, /**< problem variable */ 9722 BMS_BLKMEM* blkmem, /**< block memory */ 9723 SCIP_SET* set, /**< global SCIP settings */ 9724 SCIP_STAT* stat, /**< problem statistics */ 9725 SCIP_PROB* transprob, /**< transformed problem */ 9726 SCIP_PROB* origprob, /**< original problem */ 9727 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */ 9728 SCIP_REOPT* reopt, /**< reoptimization data structure */ 9729 SCIP_LP* lp, /**< current LP data */ 9730 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 9731 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 9732 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 9733 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */ 9734 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */ 9735 SCIP_Bool implvarfixing, /**< fixing b in implication */ 9736 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */ 9737 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */ 9738 ) 9739 { 9740 SCIP_VAR** implvars; 9741 SCIP_BOUNDTYPE* impltypes; 9742 SCIP_Real* implbounds; 9743 int nimpls; 9744 int i; 9745 9746 *infeasible = FALSE; 9747 9748 /* binary variable: implications of implvar */ 9749 nimpls = SCIPimplicsGetNImpls(implvar->implics, implvarfixing); 9750 implvars = SCIPimplicsGetVars(implvar->implics, implvarfixing); 9751 impltypes = SCIPimplicsGetTypes(implvar->implics, implvarfixing); 9752 implbounds = SCIPimplicsGetBounds(implvar->implics, implvarfixing); 9753 9754 /* if variable has too many implications, the implication graph may become too dense */ 9755 i = MIN(nimpls, MAXIMPLSCLOSURE) - 1; 9756 9757 /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and 9758 * implvars[i] is fixed, s.t. the implication y == varfixing -> z <= b / z >= b is deleted; this affects the 9759 * array over which we currently iterate; the only thing that can happen, is that elements of the array are 9760 * deleted; in this case, the subsequent elements are moved to the front; if we iterate from back to front, the 9761 * only thing that can happen is that we add the same implication twice - this does no harm 9762 */ 9763 while ( i >= 0 && !(*infeasible) ) 9764 { 9765 SCIP_Bool added; 9766 9767 assert(implvars[i] != implvar); 9768 9769 /* we have x == varfixing -> y == implvarfixing -> z <= b / z >= b: 9770 * add implication x == varfixing -> z <= b / z >= b to the implications list of x 9771 */ 9772 if( SCIPvarIsActive(implvars[i]) ) 9773 { 9774 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand, 9775 eventqueue, varfixing, implvars[i], impltypes[i], implbounds[i], TRUE, infeasible, nbdchgs, &added) ); 9776 assert(SCIPimplicsGetNImpls(implvar->implics, implvarfixing) <= nimpls); 9777 nimpls = SCIPimplicsGetNImpls(implvar->implics, implvarfixing); 9778 i = MIN(i, nimpls); /* some elements from the array could have been removed */ 9779 } 9780 --i; 9781 } 9782 9783 return SCIP_OKAY; 9784 } 9785 9786 /** adds given implication to the variable's implication list, and adds all implications directly implied by this 9787 * implication to the variable's implication list; 9788 * if the implication is conflicting, the variable is fixed to the opposite value; 9789 * if the variable is already fixed to the given value, the implication is performed immediately; 9790 * if the implication is redundant with respect to the variables' global bounds, it is ignored 9791 */ 9792 static 9793 SCIP_RETCODE varAddTransitiveImplic( 9794 SCIP_VAR* var, /**< problem variable */ 9795 BMS_BLKMEM* blkmem, /**< block memory */ 9796 SCIP_SET* set, /**< global SCIP settings */ 9797 SCIP_STAT* stat, /**< problem statistics */ 9798 SCIP_PROB* transprob, /**< transformed problem */ 9799 SCIP_PROB* origprob, /**< original problem */ 9800 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */ 9801 SCIP_REOPT* reopt, /**< reoptimization data structure */ 9802 SCIP_LP* lp, /**< current LP data */ 9803 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 9804 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 9805 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 9806 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */ 9807 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */ 9808 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */ 9809 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */ 9810 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */ 9811 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */ 9812 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */ 9813 ) 9814 { 9815 SCIP_Bool added; 9816 9817 assert(var != NULL); 9818 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY); 9819 assert(SCIPvarIsActive(var)); 9820 assert(implvar != NULL); 9821 assert(SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED); 9822 assert(infeasible != NULL); 9823 9824 /* add implication x == varfixing -> y <= b / y >= b to the implications list of x */ 9825 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand, 9826 eventqueue, varfixing, implvar, impltype, implbound, FALSE, infeasible, nbdchgs, &added) ); 9827 9828 if( *infeasible || var == implvar || !transitive || !added ) 9829 return SCIP_OKAY; 9830 9831 assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */ 9832 9833 /* add transitive closure */ 9834 if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY ) 9835 { 9836 SCIP_Bool implvarfixing; 9837 9838 implvarfixing = (impltype == SCIP_BOUNDTYPE_LOWER); 9839 9840 /* binary variable: implications of implvar */ 9841 SCIP_CALL( varAddTransitiveBinaryClosureImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 9842 cliquetable, branchcand, eventqueue, varfixing, implvar, implvarfixing, infeasible, nbdchgs) ); 9843 9844 /* inverse implication */ 9845 if( !(*infeasible) ) 9846 { 9847 SCIP_CALL( varAddTransitiveBinaryClosureImplic(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 9848 cliquetable, branchcand, eventqueue, !implvarfixing, var, !varfixing, infeasible, nbdchgs) ); 9849 } 9850 } 9851 else 9852 { 9853 /* non-binary variable: variable lower bounds of implvar */ 9854 if( impltype == SCIP_BOUNDTYPE_UPPER && implvar->vlbs != NULL ) 9855 { 9856 SCIP_VAR** vlbvars; 9857 SCIP_Real* vlbcoefs; 9858 SCIP_Real* vlbconstants; 9859 int nvlbvars; 9860 int i; 9861 9862 nvlbvars = SCIPvboundsGetNVbds(implvar->vlbs); 9863 vlbvars = SCIPvboundsGetVars(implvar->vlbs); 9864 vlbcoefs = SCIPvboundsGetCoefs(implvar->vlbs); 9865 vlbconstants = SCIPvboundsGetConstants(implvar->vlbs); 9866 9867 /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and 9868 * vlbvars[i] is fixed, s.t. the variable bound is deleted; this affects the array over which we currently 9869 * iterate; the only thing that can happen, is that elements of the array are deleted; in this case, the 9870 * subsequent elements are moved to the front; if we iterate from back to front, the only thing that can happen 9871 * is that we add the same implication twice - this does no harm 9872 */ 9873 i = nvlbvars-1; 9874 while ( i >= 0 && !(*infeasible) ) 9875 { 9876 assert(vlbvars[i] != implvar); 9877 assert(!SCIPsetIsZero(set, vlbcoefs[i])); 9878 9879 /* we have x == varfixing -> y <= b and y >= c*z + d: 9880 * c > 0: add implication x == varfixing -> z <= (b-d)/c to the implications list of x 9881 * c < 0: add implication x == varfixing -> z >= (b-d)/c to the implications list of x 9882 * 9883 * @note during an aggregation the aggregated variable "aggrvar" (the one which will have the status 9884 * SCIP_VARSTATUS_AGGREGATED afterwards) copies its variable lower and uppers bounds to the 9885 * aggregation variable (the one which will stay active); 9886 * 9887 * W.l.o.g. we consider the variable upper bounds for now. Let "vubvar" be a variable upper bound of 9888 * the aggregated variable "aggvar"; During that copying of that variable upper bound variable 9889 * "vubvar" the variable lower and upper bounds of this variable "vubvar" are also considered; note 9890 * that the "aggvar" can be a variable lower bound variable of the variable "vubvar"; Due to that 9891 * situation it can happen that we reach that code place where "vlbvars[i] == aggvar". In particular 9892 * the "aggvar" has already the variable status SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED 9893 * but is still active since the aggregation is not finished yet (in SCIPvarAggregate()); therefore we 9894 * have to explicitly check that the active variable has not a variable status 9895 * SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED; 9896 */ 9897 if( SCIPvarIsActive(vlbvars[i]) && SCIPvarGetStatus(vlbvars[i]) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(vlbvars[i]) != SCIP_VARSTATUS_NEGATED ) 9898 { 9899 SCIP_Real vbimplbound; 9900 9901 vbimplbound = (implbound - vlbconstants[i])/vlbcoefs[i]; 9902 if( vlbcoefs[i] >= 0.0 ) 9903 { 9904 vbimplbound = adjustedUb(set, SCIPvarGetType(vlbvars[i]), vbimplbound); 9905 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 9906 branchcand, eventqueue, varfixing, vlbvars[i], SCIP_BOUNDTYPE_UPPER, vbimplbound, TRUE, 9907 infeasible, nbdchgs, &added) ); 9908 } 9909 else 9910 { 9911 vbimplbound = adjustedLb(set, SCIPvarGetType(vlbvars[i]), vbimplbound); 9912 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 9913 branchcand, eventqueue, varfixing, vlbvars[i], SCIP_BOUNDTYPE_LOWER, vbimplbound, TRUE, 9914 infeasible, nbdchgs, &added) ); 9915 } 9916 nvlbvars = SCIPvboundsGetNVbds(implvar->vlbs); 9917 i = MIN(i, nvlbvars); /* some elements from the array could have been removed */ 9918 } 9919 --i; 9920 } 9921 } 9922 9923 /* non-binary variable: variable upper bounds of implvar */ 9924 if( impltype == SCIP_BOUNDTYPE_LOWER && implvar->vubs != NULL ) 9925 { 9926 SCIP_VAR** vubvars; 9927 SCIP_Real* vubcoefs; 9928 SCIP_Real* vubconstants; 9929 int nvubvars; 9930 int i; 9931 9932 nvubvars = SCIPvboundsGetNVbds(implvar->vubs); 9933 vubvars = SCIPvboundsGetVars(implvar->vubs); 9934 vubcoefs = SCIPvboundsGetCoefs(implvar->vubs); 9935 vubconstants = SCIPvboundsGetConstants(implvar->vubs); 9936 9937 /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and 9938 * vubvars[i] is fixed, s.t. the variable bound is deleted; this affects the array over which we currently 9939 * iterate; the only thing that can happen, is that elements of the array are deleted; in this case, the 9940 * subsequent elements are moved to the front; if we iterate from back to front, the only thing that can happen 9941 * is that we add the same implication twice - this does no harm 9942 */ 9943 i = nvubvars-1; 9944 while ( i >= 0 && !(*infeasible) ) 9945 { 9946 assert(vubvars[i] != implvar); 9947 assert(!SCIPsetIsZero(set, vubcoefs[i])); 9948 9949 /* we have x == varfixing -> y >= b and y <= c*z + d: 9950 * c > 0: add implication x == varfixing -> z >= (b-d)/c to the implications list of x 9951 * c < 0: add implication x == varfixing -> z <= (b-d)/c to the implications list of x 9952 * 9953 * @note during an aggregation the aggregated variable "aggrvar" (the one which will have the status 9954 * SCIP_VARSTATUS_AGGREGATED afterwards) copies its variable lower and uppers bounds to the 9955 * aggregation variable (the one which will stay active); 9956 * 9957 * W.l.o.g. we consider the variable lower bounds for now. Let "vlbvar" be a variable lower bound of 9958 * the aggregated variable "aggvar"; During that copying of that variable lower bound variable 9959 * "vlbvar" the variable lower and upper bounds of this variable "vlbvar" are also considered; note 9960 * that the "aggvar" can be a variable upper bound variable of the variable "vlbvar"; Due to that 9961 * situation it can happen that we reach that code place where "vubvars[i] == aggvar". In particular 9962 * the "aggvar" has already the variable status SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED 9963 * but is still active since the aggregation is not finished yet (in SCIPvarAggregate()); therefore we 9964 * have to explicitly check that the active variable has not a variable status 9965 * SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED; 9966 */ 9967 if( SCIPvarIsActive(vubvars[i]) && SCIPvarGetStatus(vubvars[i]) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(vubvars[i]) != SCIP_VARSTATUS_NEGATED ) 9968 { 9969 SCIP_Real vbimplbound; 9970 9971 vbimplbound = (implbound - vubconstants[i])/vubcoefs[i]; 9972 if( vubcoefs[i] >= 0.0 ) 9973 { 9974 vbimplbound = adjustedLb(set, SCIPvarGetType(vubvars[i]), vbimplbound); 9975 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 9976 branchcand, eventqueue, varfixing, vubvars[i], SCIP_BOUNDTYPE_LOWER, vbimplbound, TRUE, 9977 infeasible, nbdchgs, &added) ); 9978 } 9979 else 9980 { 9981 vbimplbound = adjustedUb(set, SCIPvarGetType(vubvars[i]), vbimplbound); 9982 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 9983 branchcand, eventqueue, varfixing, vubvars[i], SCIP_BOUNDTYPE_UPPER, vbimplbound, TRUE, 9984 infeasible, nbdchgs, &added) ); 9985 } 9986 nvubvars = SCIPvboundsGetNVbds(implvar->vubs); 9987 i = MIN(i, nvubvars); /* some elements from the array could have been removed */ 9988 } 9989 --i; 9990 } 9991 } 9992 } 9993 9994 return SCIP_OKAY; 9995 } 9996 9997 /** informs variable x about a globally valid variable lower bound x >= b*z + d with integer variable z; 9998 * if z is binary, the corresponding valid implication for z is also added; 9999 * improves the global bounds of the variable and the vlb variable if possible 10000 */ 10001 SCIP_RETCODE SCIPvarAddVlb( 10002 SCIP_VAR* var, /**< problem variable */ 10003 BMS_BLKMEM* blkmem, /**< block memory */ 10004 SCIP_SET* set, /**< global SCIP settings */ 10005 SCIP_STAT* stat, /**< problem statistics */ 10006 SCIP_PROB* transprob, /**< transformed problem */ 10007 SCIP_PROB* origprob, /**< original problem */ 10008 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */ 10009 SCIP_REOPT* reopt, /**< reoptimization data structure */ 10010 SCIP_LP* lp, /**< current LP data */ 10011 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 10012 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 10013 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 10014 SCIP_VAR* vlbvar, /**< variable z in x >= b*z + d */ 10015 SCIP_Real vlbcoef, /**< coefficient b in x >= b*z + d */ 10016 SCIP_Real vlbconstant, /**< constant d in x >= b*z + d */ 10017 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */ 10018 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */ 10019 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */ 10020 ) 10021 { 10022 assert(var != NULL); 10023 assert(set != NULL); 10024 assert(var->scip == set->scip); 10025 assert(SCIPvarGetType(vlbvar) != SCIP_VARTYPE_CONTINUOUS); 10026 assert(infeasible != NULL); 10027 10028 SCIPsetDebugMsg(set, "adding variable lower bound <%s> >= %g<%s> + %g\n", SCIPvarGetName(var), vlbcoef, SCIPvarGetName(vlbvar), vlbconstant); 10029 10030 *infeasible = FALSE; 10031 if( nbdchgs != NULL ) 10032 *nbdchgs = 0; 10033 10034 switch( SCIPvarGetStatus(var) ) 10035 { 10036 case SCIP_VARSTATUS_ORIGINAL: 10037 assert(var->data.original.transvar != NULL); 10038 SCIP_CALL( SCIPvarAddVlb(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10039 cliquetable, branchcand, eventqueue, vlbvar, vlbcoef, vlbconstant, transitive, infeasible, nbdchgs) ); 10040 break; 10041 10042 case SCIP_VARSTATUS_COLUMN: 10043 case SCIP_VARSTATUS_LOOSE: 10044 case SCIP_VARSTATUS_FIXED: 10045 /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */ 10046 SCIP_CALL( SCIPvarGetProbvarSum(&vlbvar, set, &vlbcoef, &vlbconstant) ); 10047 SCIPsetDebugMsg(set, " -> transformed to variable lower bound <%s> >= %g<%s> + %g\n", SCIPvarGetName(var), vlbcoef, SCIPvarGetName(vlbvar), vlbconstant); 10048 10049 /* if the vlb coefficient is zero, just update the lower bound of the variable */ 10050 if( SCIPsetIsZero(set, vlbcoef) ) 10051 { 10052 if( SCIPsetIsFeasGT(set, vlbconstant, SCIPvarGetUbGlobal(var)) ) 10053 *infeasible = TRUE; 10054 else if( SCIPsetIsFeasGT(set, vlbconstant, SCIPvarGetLbGlobal(var)) ) 10055 { 10056 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10057 * with the local bound, in this case we need to store the bound change as pending bound change 10058 */ 10059 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10060 { 10061 assert(tree != NULL); 10062 assert(transprob != NULL); 10063 assert(SCIPprobIsTransformed(transprob)); 10064 10065 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10066 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, vlbconstant, SCIP_BOUNDTYPE_LOWER, FALSE) ); 10067 } 10068 else 10069 { 10070 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, vlbconstant) ); 10071 } 10072 10073 if( nbdchgs != NULL ) 10074 (*nbdchgs)++; 10075 } 10076 } 10077 else if( var == vlbvar ) 10078 { 10079 /* the variables cancels out, the variable bound constraint is either redundant or proves global infeasibility */ 10080 if( SCIPsetIsEQ(set, vlbcoef, 1.0) ) 10081 { 10082 if( SCIPsetIsPositive(set, vlbconstant) ) 10083 *infeasible = TRUE; 10084 return SCIP_OKAY; 10085 } 10086 else 10087 { 10088 SCIP_Real lb = SCIPvarGetLbGlobal(var); 10089 SCIP_Real ub = SCIPvarGetUbGlobal(var); 10090 10091 /* the variable bound constraint defines a new upper bound */ 10092 if( SCIPsetIsGT(set, vlbcoef, 1.0) ) 10093 { 10094 SCIP_Real newub = vlbconstant / (1.0 - vlbcoef); 10095 10096 if( SCIPsetIsFeasLT(set, newub, lb) ) 10097 { 10098 *infeasible = TRUE; 10099 return SCIP_OKAY; 10100 } 10101 else if( SCIPsetIsFeasLT(set, newub, ub) ) 10102 { 10103 /* bound might be adjusted due to integrality condition */ 10104 newub = adjustedUb(set, SCIPvarGetType(var), newub); 10105 10106 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10107 * with the local bound, in this case we need to store the bound change as pending bound change 10108 */ 10109 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10110 { 10111 assert(tree != NULL); 10112 assert(transprob != NULL); 10113 assert(SCIPprobIsTransformed(transprob)); 10114 10115 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10116 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newub, SCIP_BOUNDTYPE_UPPER, FALSE) ); 10117 } 10118 else 10119 { 10120 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newub) ); 10121 } 10122 10123 if( nbdchgs != NULL ) 10124 (*nbdchgs)++; 10125 } 10126 } 10127 /* the variable bound constraint defines a new lower bound */ 10128 else 10129 { 10130 SCIP_Real newlb; 10131 10132 assert(SCIPsetIsLT(set, vlbcoef, 1.0)); 10133 10134 newlb = vlbconstant / (1.0 - vlbcoef); 10135 10136 if( SCIPsetIsFeasGT(set, newlb, ub) ) 10137 { 10138 *infeasible = TRUE; 10139 return SCIP_OKAY; 10140 } 10141 else if( SCIPsetIsFeasGT(set, newlb, lb) ) 10142 { 10143 /* bound might be adjusted due to integrality condition */ 10144 newlb = adjustedLb(set, SCIPvarGetType(var), newlb); 10145 10146 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10147 * with the local bound, in this case we need to store the bound change as pending bound change 10148 */ 10149 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10150 { 10151 assert(tree != NULL); 10152 assert(transprob != NULL); 10153 assert(SCIPprobIsTransformed(transprob)); 10154 10155 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10156 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newlb, SCIP_BOUNDTYPE_LOWER, FALSE) ); 10157 } 10158 else 10159 { 10160 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newlb) ); 10161 } 10162 10163 if( nbdchgs != NULL ) 10164 (*nbdchgs)++; 10165 } 10166 } 10167 } 10168 } 10169 else if( SCIPvarIsActive(vlbvar) ) 10170 { 10171 SCIP_Real xlb; 10172 SCIP_Real xub; 10173 SCIP_Real zlb; 10174 SCIP_Real zub; 10175 SCIP_Real minvlb; 10176 SCIP_Real maxvlb; 10177 10178 assert(SCIPvarGetStatus(vlbvar) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(vlbvar) == SCIP_VARSTATUS_COLUMN); 10179 assert(vlbcoef != 0.0); 10180 10181 minvlb = -SCIPsetInfinity(set); 10182 maxvlb = SCIPsetInfinity(set); 10183 10184 xlb = SCIPvarGetLbGlobal(var); 10185 xub = SCIPvarGetUbGlobal(var); 10186 zlb = SCIPvarGetLbGlobal(vlbvar); 10187 zub = SCIPvarGetUbGlobal(vlbvar); 10188 10189 /* improve global bounds of vlb variable, and calculate minimal and maximal value of variable bound */ 10190 if( vlbcoef >= 0.0 ) 10191 { 10192 SCIP_Real newzub; 10193 10194 if( !SCIPsetIsInfinity(set, xub) ) 10195 { 10196 /* x >= b*z + d -> z <= (x-d)/b */ 10197 newzub = (xub - vlbconstant)/vlbcoef; 10198 10199 /* return if the new bound is less than -infinity */ 10200 if( SCIPsetIsInfinity(set, REALABS(newzub)) ) 10201 return SCIP_OKAY; 10202 10203 if( SCIPsetIsFeasLT(set, newzub, zlb) ) 10204 { 10205 *infeasible = TRUE; 10206 return SCIP_OKAY; 10207 } 10208 if( SCIPsetIsFeasLT(set, newzub, zub) ) 10209 { 10210 /* bound might be adjusted due to integrality condition */ 10211 newzub = adjustedUb(set, SCIPvarGetType(vlbvar), newzub); 10212 10213 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10214 * with the local bound, in this case we need to store the bound change as pending bound change 10215 */ 10216 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10217 { 10218 assert(tree != NULL); 10219 assert(transprob != NULL); 10220 assert(SCIPprobIsTransformed(transprob)); 10221 10222 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10223 tree, reopt, lp, branchcand, eventqueue, cliquetable, vlbvar, newzub, SCIP_BOUNDTYPE_UPPER, FALSE) ); 10224 } 10225 else 10226 { 10227 SCIP_CALL( SCIPvarChgUbGlobal(vlbvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzub) ); 10228 } 10229 zub = newzub; 10230 10231 if( nbdchgs != NULL ) 10232 (*nbdchgs)++; 10233 } 10234 maxvlb = vlbcoef * zub + vlbconstant; 10235 if( !SCIPsetIsInfinity(set, -zlb) ) 10236 minvlb = vlbcoef * zlb + vlbconstant; 10237 } 10238 else 10239 { 10240 if( !SCIPsetIsInfinity(set, zub) ) 10241 maxvlb = vlbcoef * zub + vlbconstant; 10242 if( !SCIPsetIsInfinity(set, -zlb) ) 10243 minvlb = vlbcoef * zlb + vlbconstant; 10244 } 10245 } 10246 else 10247 { 10248 SCIP_Real newzlb; 10249 10250 if( !SCIPsetIsInfinity(set, xub) ) 10251 { 10252 /* x >= b*z + d -> z >= (x-d)/b */ 10253 newzlb = (xub - vlbconstant)/vlbcoef; 10254 10255 /* return if the new bound is larger than infinity */ 10256 if( SCIPsetIsInfinity(set, REALABS(newzlb)) ) 10257 return SCIP_OKAY; 10258 10259 if( SCIPsetIsFeasGT(set, newzlb, zub) ) 10260 { 10261 *infeasible = TRUE; 10262 return SCIP_OKAY; 10263 } 10264 if( SCIPsetIsFeasGT(set, newzlb, zlb) ) 10265 { 10266 /* bound might be adjusted due to integrality condition */ 10267 newzlb = adjustedLb(set, SCIPvarGetType(vlbvar), newzlb); 10268 10269 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10270 * with the local bound, in this case we need to store the bound change as pending bound change 10271 */ 10272 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10273 { 10274 assert(tree != NULL); 10275 assert(transprob != NULL); 10276 assert(SCIPprobIsTransformed(transprob)); 10277 10278 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10279 tree, reopt, lp, branchcand, eventqueue, cliquetable, vlbvar, newzlb, SCIP_BOUNDTYPE_LOWER, FALSE) ); 10280 } 10281 else 10282 { 10283 SCIP_CALL( SCIPvarChgLbGlobal(vlbvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzlb) ); 10284 } 10285 zlb = newzlb; 10286 10287 if( nbdchgs != NULL ) 10288 (*nbdchgs)++; 10289 } 10290 maxvlb = vlbcoef * zlb + vlbconstant; 10291 if( !SCIPsetIsInfinity(set, zub) ) 10292 minvlb = vlbcoef * zub + vlbconstant; 10293 } 10294 else 10295 { 10296 if( !SCIPsetIsInfinity(set, -zlb) ) 10297 maxvlb = vlbcoef * zlb + vlbconstant; 10298 if( !SCIPsetIsInfinity(set, zub) ) 10299 minvlb = vlbcoef * zub + vlbconstant; 10300 } 10301 } 10302 if( maxvlb < minvlb ) 10303 maxvlb = minvlb; 10304 10305 /* adjust bounds due to integrality of variable */ 10306 minvlb = adjustedLb(set, SCIPvarGetType(var), minvlb); 10307 maxvlb = adjustedLb(set, SCIPvarGetType(var), maxvlb); 10308 10309 /* check bounds for feasibility */ 10310 if( SCIPsetIsFeasGT(set, minvlb, xub) || (var == vlbvar && SCIPsetIsEQ(set, vlbcoef, 1.0) && SCIPsetIsFeasPositive(set, vlbconstant)) ) 10311 { 10312 *infeasible = TRUE; 10313 return SCIP_OKAY; 10314 } 10315 /* improve global lower bound of variable */ 10316 if( SCIPsetIsFeasGT(set, minvlb, xlb) ) 10317 { 10318 /* bound might be adjusted due to integrality condition */ 10319 minvlb = adjustedLb(set, SCIPvarGetType(var), minvlb); 10320 10321 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10322 * with the local bound, in this case we need to store the bound change as pending bound change 10323 */ 10324 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10325 { 10326 assert(tree != NULL); 10327 assert(transprob != NULL); 10328 assert(SCIPprobIsTransformed(transprob)); 10329 10330 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10331 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, minvlb, SCIP_BOUNDTYPE_LOWER, FALSE) ); 10332 } 10333 else 10334 { 10335 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, minvlb) ); 10336 } 10337 xlb = minvlb; 10338 10339 if( nbdchgs != NULL ) 10340 (*nbdchgs)++; 10341 } 10342 minvlb = xlb; 10343 10344 /* improve variable bound for binary z by moving the variable's global bound to the vlb constant */ 10345 if( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY ) 10346 { 10347 /* b > 0: x >= (maxvlb - minvlb) * z + minvlb 10348 * b < 0: x >= (minvlb - maxvlb) * z + maxvlb 10349 */ 10350 10351 assert(!SCIPsetIsInfinity(set, maxvlb) && !SCIPsetIsInfinity(set, -minvlb)); 10352 10353 if( vlbcoef >= 0.0 ) 10354 { 10355 vlbcoef = maxvlb - minvlb; 10356 vlbconstant = minvlb; 10357 } 10358 else 10359 { 10360 vlbcoef = minvlb - maxvlb; 10361 vlbconstant = maxvlb; 10362 } 10363 } 10364 10365 /* add variable bound to the variable bounds list */ 10366 if( SCIPsetIsFeasGT(set, maxvlb, xlb) ) 10367 { 10368 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED); 10369 assert(!SCIPsetIsZero(set, vlbcoef)); 10370 10371 /* if one of the variables is binary, add the corresponding implication to the variable's implication 10372 * list, thereby also adding the variable bound (or implication) to the other variable 10373 */ 10374 if( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY ) 10375 { 10376 /* add corresponding implication: 10377 * b > 0, x >= b*z + d <-> z == 1 -> x >= b+d 10378 * b < 0, x >= b*z + d <-> z == 0 -> x >= d 10379 */ 10380 SCIP_CALL( varAddTransitiveImplic(vlbvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10381 cliquetable, branchcand, eventqueue, (vlbcoef >= 0.0), var, SCIP_BOUNDTYPE_LOWER, maxvlb, transitive, 10382 infeasible, nbdchgs) ); 10383 } 10384 else if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY ) 10385 { 10386 /* add corresponding implication: 10387 * b > 0, x >= b*z + d <-> x == 0 -> z <= -d/b 10388 * b < 0, x >= b*z + d <-> x == 0 -> z >= -d/b 10389 */ 10390 SCIP_Real implbound; 10391 implbound = -vlbconstant/vlbcoef; 10392 10393 /* tighten the implication bound if the variable is integer */ 10394 if( SCIPvarIsIntegral(vlbvar) ) 10395 { 10396 if( vlbcoef >= 0 ) 10397 implbound = SCIPsetFloor(set, implbound); 10398 else 10399 implbound = SCIPsetCeil(set, implbound); 10400 } 10401 SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10402 cliquetable, branchcand, eventqueue, FALSE, vlbvar, (vlbcoef >= 0.0 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER), 10403 implbound, transitive, infeasible, nbdchgs) ); 10404 } 10405 else 10406 { 10407 SCIP_CALL( varAddVbound(var, blkmem, set, eventqueue, SCIP_BOUNDTYPE_LOWER, vlbvar, vlbcoef, vlbconstant) ); 10408 } 10409 } 10410 } 10411 break; 10412 10413 case SCIP_VARSTATUS_AGGREGATED: 10414 /* x = a*y + c: x >= b*z + d <=> a*y + c >= b*z + d <=> y >= b/a * z + (d-c)/a, if a > 0 10415 * y <= b/a * z + (d-c)/a, if a < 0 10416 */ 10417 assert(var->data.aggregate.var != NULL); 10418 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) ) 10419 { 10420 /* a > 0 -> add variable lower bound */ 10421 SCIP_CALL( SCIPvarAddVlb(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10422 cliquetable, branchcand, eventqueue, vlbvar, vlbcoef/var->data.aggregate.scalar, 10423 (vlbconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) ); 10424 } 10425 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) ) 10426 { 10427 /* a < 0 -> add variable upper bound */ 10428 SCIP_CALL( SCIPvarAddVub(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10429 cliquetable, branchcand, eventqueue, vlbvar, vlbcoef/var->data.aggregate.scalar, 10430 (vlbconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) ); 10431 } 10432 else 10433 { 10434 SCIPerrorMessage("scalar is zero in aggregation\n"); 10435 return SCIP_INVALIDDATA; 10436 } 10437 break; 10438 10439 case SCIP_VARSTATUS_MULTAGGR: 10440 /* nothing to do here */ 10441 break; 10442 10443 case SCIP_VARSTATUS_NEGATED: 10444 /* x = offset - x': x >= b*z + d <=> offset - x' >= b*z + d <=> x' <= -b*z + (offset-d) */ 10445 assert(var->negatedvar != NULL); 10446 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 10447 assert(var->negatedvar->negatedvar == var); 10448 SCIP_CALL( SCIPvarAddVub(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 10449 branchcand, eventqueue, vlbvar, -vlbcoef, var->data.negate.constant - vlbconstant, transitive, infeasible, 10450 nbdchgs) ); 10451 break; 10452 10453 default: 10454 SCIPerrorMessage("unknown variable status\n"); 10455 return SCIP_INVALIDDATA; 10456 } 10457 10458 return SCIP_OKAY; 10459 } 10460 10461 /** informs variable x about a globally valid variable upper bound x <= b*z + d with integer variable z; 10462 * if z is binary, the corresponding valid implication for z is also added; 10463 * updates the global bounds of the variable and the vub variable correspondingly 10464 */ 10465 SCIP_RETCODE SCIPvarAddVub( 10466 SCIP_VAR* var, /**< problem variable */ 10467 BMS_BLKMEM* blkmem, /**< block memory */ 10468 SCIP_SET* set, /**< global SCIP settings */ 10469 SCIP_STAT* stat, /**< problem statistics */ 10470 SCIP_PROB* transprob, /**< transformed problem */ 10471 SCIP_PROB* origprob, /**< original problem */ 10472 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */ 10473 SCIP_REOPT* reopt, /**< reoptimization data structure */ 10474 SCIP_LP* lp, /**< current LP data */ 10475 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 10476 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 10477 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 10478 SCIP_VAR* vubvar, /**< variable z in x <= b*z + d */ 10479 SCIP_Real vubcoef, /**< coefficient b in x <= b*z + d */ 10480 SCIP_Real vubconstant, /**< constant d in x <= b*z + d */ 10481 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */ 10482 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */ 10483 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */ 10484 ) 10485 { 10486 assert(var != NULL); 10487 assert(set != NULL); 10488 assert(var->scip == set->scip); 10489 assert(SCIPvarGetType(vubvar) != SCIP_VARTYPE_CONTINUOUS); 10490 assert(infeasible != NULL); 10491 10492 SCIPsetDebugMsg(set, "adding variable upper bound <%s> <= %g<%s> + %g\n", SCIPvarGetName(var), vubcoef, SCIPvarGetName(vubvar), vubconstant); 10493 10494 *infeasible = FALSE; 10495 if( nbdchgs != NULL ) 10496 *nbdchgs = 0; 10497 10498 switch( SCIPvarGetStatus(var) ) 10499 { 10500 case SCIP_VARSTATUS_ORIGINAL: 10501 assert(var->data.original.transvar != NULL); 10502 SCIP_CALL( SCIPvarAddVub(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10503 cliquetable, branchcand, eventqueue, vubvar, vubcoef, vubconstant, transitive, infeasible, nbdchgs) ); 10504 break; 10505 10506 case SCIP_VARSTATUS_COLUMN: 10507 case SCIP_VARSTATUS_LOOSE: 10508 case SCIP_VARSTATUS_FIXED: 10509 /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */ 10510 SCIP_CALL( SCIPvarGetProbvarSum(&vubvar, set, &vubcoef, &vubconstant) ); 10511 SCIPsetDebugMsg(set, " -> transformed to variable upper bound <%s> <= %g<%s> + %g\n", 10512 SCIPvarGetName(var), vubcoef, SCIPvarGetName(vubvar), vubconstant); 10513 10514 /* if the vub coefficient is zero, just update the upper bound of the variable */ 10515 if( SCIPsetIsZero(set, vubcoef) ) 10516 { 10517 if( SCIPsetIsFeasLT(set, vubconstant, SCIPvarGetLbGlobal(var)) ) 10518 *infeasible = TRUE; 10519 else if( SCIPsetIsFeasLT(set, vubconstant, SCIPvarGetUbGlobal(var)) ) 10520 { 10521 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10522 * with the local bound, in this case we need to store the bound change as pending bound change 10523 */ 10524 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10525 { 10526 assert(tree != NULL); 10527 assert(transprob != NULL); 10528 assert(SCIPprobIsTransformed(transprob)); 10529 10530 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10531 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, vubconstant, SCIP_BOUNDTYPE_UPPER, FALSE) ); 10532 } 10533 else 10534 { 10535 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, vubconstant) ); 10536 } 10537 10538 if( nbdchgs != NULL ) 10539 (*nbdchgs)++; 10540 } 10541 } 10542 else if( var == vubvar ) 10543 { 10544 /* the variables cancels out, the variable bound constraint is either redundant or proves global infeasibility */ 10545 if( SCIPsetIsEQ(set, vubcoef, 1.0) ) 10546 { 10547 if( SCIPsetIsNegative(set, vubconstant) ) 10548 *infeasible = TRUE; 10549 return SCIP_OKAY; 10550 } 10551 else 10552 { 10553 SCIP_Real lb = SCIPvarGetLbGlobal(var); 10554 SCIP_Real ub = SCIPvarGetUbGlobal(var); 10555 10556 /* the variable bound constraint defines a new lower bound */ 10557 if( SCIPsetIsGT(set, vubcoef, 1.0) ) 10558 { 10559 SCIP_Real newlb = vubconstant / (1.0 - vubcoef); 10560 10561 if( SCIPsetIsFeasGT(set, newlb, ub) ) 10562 { 10563 *infeasible = TRUE; 10564 return SCIP_OKAY; 10565 } 10566 else if( SCIPsetIsFeasGT(set, newlb, lb) ) 10567 { 10568 /* bound might be adjusted due to integrality condition */ 10569 newlb = adjustedLb(set, SCIPvarGetType(var), newlb); 10570 10571 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10572 * with the local bound, in this case we need to store the bound change as pending bound change 10573 */ 10574 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10575 { 10576 assert(tree != NULL); 10577 assert(transprob != NULL); 10578 assert(SCIPprobIsTransformed(transprob)); 10579 10580 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10581 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newlb, SCIP_BOUNDTYPE_LOWER, FALSE) ); 10582 } 10583 else 10584 { 10585 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newlb) ); 10586 } 10587 10588 if( nbdchgs != NULL ) 10589 (*nbdchgs)++; 10590 } 10591 } 10592 /* the variable bound constraint defines a new upper bound */ 10593 else 10594 { 10595 SCIP_Real newub; 10596 10597 assert(SCIPsetIsLT(set, vubcoef, 1.0)); 10598 10599 newub = vubconstant / (1.0 - vubcoef); 10600 10601 if( SCIPsetIsFeasLT(set, newub, lb) ) 10602 { 10603 *infeasible = TRUE; 10604 return SCIP_OKAY; 10605 } 10606 else if( SCIPsetIsFeasLT(set, newub, ub) ) 10607 { 10608 /* bound might be adjusted due to integrality condition */ 10609 newub = adjustedUb(set, SCIPvarGetType(var), newub); 10610 10611 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10612 * with the local bound, in this case we need to store the bound change as pending bound change 10613 */ 10614 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10615 { 10616 assert(tree != NULL); 10617 assert(transprob != NULL); 10618 assert(SCIPprobIsTransformed(transprob)); 10619 10620 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10621 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newub, SCIP_BOUNDTYPE_UPPER, FALSE) ); 10622 } 10623 else 10624 { 10625 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newub) ); 10626 } 10627 10628 if( nbdchgs != NULL ) 10629 (*nbdchgs)++; 10630 } 10631 } 10632 } 10633 } 10634 else if( SCIPvarIsActive(vubvar) ) 10635 { 10636 SCIP_Real xlb; 10637 SCIP_Real xub; 10638 SCIP_Real zlb; 10639 SCIP_Real zub; 10640 SCIP_Real minvub; 10641 SCIP_Real maxvub; 10642 10643 assert(SCIPvarGetStatus(vubvar) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(vubvar) == SCIP_VARSTATUS_COLUMN); 10644 assert(vubcoef != 0.0); 10645 10646 minvub = -SCIPsetInfinity(set); 10647 maxvub = SCIPsetInfinity(set); 10648 10649 xlb = SCIPvarGetLbGlobal(var); 10650 xub = SCIPvarGetUbGlobal(var); 10651 zlb = SCIPvarGetLbGlobal(vubvar); 10652 zub = SCIPvarGetUbGlobal(vubvar); 10653 10654 /* improve global bounds of vub variable, and calculate minimal and maximal value of variable bound */ 10655 if( vubcoef >= 0.0 ) 10656 { 10657 SCIP_Real newzlb; 10658 10659 if( !SCIPsetIsInfinity(set, -xlb) ) 10660 { 10661 /* x <= b*z + d -> z >= (x-d)/b */ 10662 newzlb = (xlb - vubconstant)/vubcoef; 10663 if( SCIPsetIsFeasGT(set, newzlb, zub) ) 10664 { 10665 *infeasible = TRUE; 10666 return SCIP_OKAY; 10667 } 10668 if( SCIPsetIsFeasGT(set, newzlb, zlb) ) 10669 { 10670 /* bound might be adjusted due to integrality condition */ 10671 newzlb = adjustedLb(set, SCIPvarGetType(vubvar), newzlb); 10672 10673 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10674 * with the local bound, in this case we need to store the bound change as pending bound change 10675 */ 10676 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10677 { 10678 assert(tree != NULL); 10679 assert(transprob != NULL); 10680 assert(SCIPprobIsTransformed(transprob)); 10681 10682 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10683 tree, reopt, lp, branchcand, eventqueue, cliquetable, vubvar, newzlb, SCIP_BOUNDTYPE_LOWER, FALSE) ); 10684 } 10685 else 10686 { 10687 SCIP_CALL( SCIPvarChgLbGlobal(vubvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzlb) ); 10688 } 10689 zlb = newzlb; 10690 10691 if( nbdchgs != NULL ) 10692 (*nbdchgs)++; 10693 } 10694 minvub = vubcoef * zlb + vubconstant; 10695 if( !SCIPsetIsInfinity(set, zub) ) 10696 maxvub = vubcoef * zub + vubconstant; 10697 } 10698 else 10699 { 10700 if( !SCIPsetIsInfinity(set, zub) ) 10701 maxvub = vubcoef * zub + vubconstant; 10702 if( !SCIPsetIsInfinity(set, -zlb) ) 10703 minvub = vubcoef * zlb + vubconstant; 10704 } 10705 } 10706 else 10707 { 10708 SCIP_Real newzub; 10709 10710 if( !SCIPsetIsInfinity(set, -xlb) ) 10711 { 10712 /* x <= b*z + d -> z <= (x-d)/b */ 10713 newzub = (xlb - vubconstant)/vubcoef; 10714 if( SCIPsetIsFeasLT(set, newzub, zlb) ) 10715 { 10716 *infeasible = TRUE; 10717 return SCIP_OKAY; 10718 } 10719 if( SCIPsetIsFeasLT(set, newzub, zub) ) 10720 { 10721 /* bound might be adjusted due to integrality condition */ 10722 newzub = adjustedUb(set, SCIPvarGetType(vubvar), newzub); 10723 10724 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10725 * with the local bound, in this case we need to store the bound change as pending bound change 10726 */ 10727 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10728 { 10729 assert(tree != NULL); 10730 assert(transprob != NULL); 10731 assert(SCIPprobIsTransformed(transprob)); 10732 10733 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10734 tree, reopt, lp, branchcand, eventqueue, cliquetable, vubvar, newzub, SCIP_BOUNDTYPE_UPPER, FALSE) ); 10735 } 10736 else 10737 { 10738 SCIP_CALL( SCIPvarChgUbGlobal(vubvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzub) ); 10739 } 10740 zub = newzub; 10741 10742 if( nbdchgs != NULL ) 10743 (*nbdchgs)++; 10744 } 10745 minvub = vubcoef * zub + vubconstant; 10746 if( !SCIPsetIsInfinity(set, -zlb) ) 10747 maxvub = vubcoef * zlb + vubconstant; 10748 } 10749 else 10750 { 10751 if( !SCIPsetIsInfinity(set, zub) ) 10752 minvub = vubcoef * zub + vubconstant; 10753 if( !SCIPsetIsInfinity(set, -zlb) ) 10754 maxvub = vubcoef * zlb + vubconstant; 10755 } 10756 } 10757 if( minvub > maxvub ) 10758 minvub = maxvub; 10759 10760 /* adjust bounds due to integrality of vub variable */ 10761 minvub = adjustedUb(set, SCIPvarGetType(var), minvub); 10762 maxvub = adjustedUb(set, SCIPvarGetType(var), maxvub); 10763 10764 /* check bounds for feasibility */ 10765 if( SCIPsetIsFeasLT(set, maxvub, xlb) || (var == vubvar && SCIPsetIsEQ(set, vubcoef, 1.0) && SCIPsetIsFeasNegative(set, vubconstant)) ) 10766 { 10767 *infeasible = TRUE; 10768 return SCIP_OKAY; 10769 } 10770 10771 /* improve global upper bound of variable */ 10772 if( SCIPsetIsFeasLT(set, maxvub, xub) ) 10773 { 10774 /* bound might be adjusted due to integrality condition */ 10775 maxvub = adjustedUb(set, SCIPvarGetType(var), maxvub); 10776 10777 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 10778 * with the local bound, in this case we need to store the bound change as pending bound change 10779 */ 10780 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 10781 { 10782 assert(tree != NULL); 10783 assert(transprob != NULL); 10784 assert(SCIPprobIsTransformed(transprob)); 10785 10786 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 10787 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, maxvub, SCIP_BOUNDTYPE_UPPER, FALSE) ); 10788 } 10789 else 10790 { 10791 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, maxvub) ); 10792 } 10793 xub = maxvub; 10794 10795 if( nbdchgs != NULL ) 10796 (*nbdchgs)++; 10797 } 10798 maxvub = xub; 10799 10800 /* improve variable bound for binary z by moving the variable's global bound to the vub constant */ 10801 if( SCIPvarIsBinary(vubvar) ) 10802 { 10803 /* b > 0: x <= (maxvub - minvub) * z + minvub 10804 * b < 0: x <= (minvub - maxvub) * z + maxvub 10805 */ 10806 10807 assert(!SCIPsetIsInfinity(set, maxvub) && !SCIPsetIsInfinity(set, -minvub)); 10808 10809 if( vubcoef >= 0.0 ) 10810 { 10811 vubcoef = maxvub - minvub; 10812 vubconstant = minvub; 10813 } 10814 else 10815 { 10816 vubcoef = minvub - maxvub; 10817 vubconstant = maxvub; 10818 } 10819 } 10820 10821 /* add variable bound to the variable bounds list */ 10822 if( SCIPsetIsFeasLT(set, minvub, xub) ) 10823 { 10824 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED); 10825 assert(!SCIPsetIsZero(set, vubcoef)); 10826 10827 /* if one of the variables is binary, add the corresponding implication to the variable's implication 10828 * list, thereby also adding the variable bound (or implication) to the other variable 10829 */ 10830 if( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY ) 10831 { 10832 /* add corresponding implication: 10833 * b > 0, x <= b*z + d <-> z == 0 -> x <= d 10834 * b < 0, x <= b*z + d <-> z == 1 -> x <= b+d 10835 */ 10836 SCIP_CALL( varAddTransitiveImplic(vubvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10837 cliquetable, branchcand, eventqueue, (vubcoef < 0.0), var, SCIP_BOUNDTYPE_UPPER, minvub, transitive, 10838 infeasible, nbdchgs) ); 10839 } 10840 else if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY ) 10841 { 10842 /* add corresponding implication: 10843 * b > 0, x <= b*z + d <-> x == 1 -> z >= (1-d)/b 10844 * b < 0, x <= b*z + d <-> x == 1 -> z <= (1-d)/b 10845 */ 10846 SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10847 cliquetable, branchcand, eventqueue, TRUE, vubvar, (vubcoef >= 0.0 ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER), 10848 (1.0-vubconstant)/vubcoef, transitive, infeasible, nbdchgs) ); 10849 } 10850 else 10851 { 10852 SCIP_CALL( varAddVbound(var, blkmem, set, eventqueue, SCIP_BOUNDTYPE_UPPER, vubvar, vubcoef, vubconstant) ); 10853 } 10854 } 10855 } 10856 break; 10857 10858 case SCIP_VARSTATUS_AGGREGATED: 10859 /* x = a*y + c: x <= b*z + d <=> a*y + c <= b*z + d <=> y <= b/a * z + (d-c)/a, if a > 0 10860 * y >= b/a * z + (d-c)/a, if a < 0 10861 */ 10862 assert(var->data.aggregate.var != NULL); 10863 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) ) 10864 { 10865 /* a > 0 -> add variable upper bound */ 10866 SCIP_CALL( SCIPvarAddVub(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10867 cliquetable, branchcand, eventqueue, vubvar, vubcoef/var->data.aggregate.scalar, 10868 (vubconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) ); 10869 } 10870 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) ) 10871 { 10872 /* a < 0 -> add variable lower bound */ 10873 SCIP_CALL( SCIPvarAddVlb(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10874 cliquetable, branchcand, eventqueue, vubvar, vubcoef/var->data.aggregate.scalar, 10875 (vubconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) ); 10876 } 10877 else 10878 { 10879 SCIPerrorMessage("scalar is zero in aggregation\n"); 10880 return SCIP_INVALIDDATA; 10881 } 10882 break; 10883 10884 case SCIP_VARSTATUS_MULTAGGR: 10885 /* nothing to do here */ 10886 break; 10887 10888 case SCIP_VARSTATUS_NEGATED: 10889 /* x = offset - x': x <= b*z + d <=> offset - x' <= b*z + d <=> x' >= -b*z + (offset-d) */ 10890 assert(var->negatedvar != NULL); 10891 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 10892 assert(var->negatedvar->negatedvar == var); 10893 SCIP_CALL( SCIPvarAddVlb(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 10894 branchcand, eventqueue, vubvar, -vubcoef, var->data.negate.constant - vubconstant, transitive, infeasible, 10895 nbdchgs) ); 10896 break; 10897 10898 default: 10899 SCIPerrorMessage("unknown variable status\n"); 10900 return SCIP_INVALIDDATA; 10901 } 10902 10903 return SCIP_OKAY; 10904 } 10905 10906 /** informs binary variable x about a globally valid implication: x == 0 or x == 1 ==> y <= b or y >= b; 10907 * also adds the corresponding implication or variable bound to the implied variable; 10908 * if the implication is conflicting, the variable is fixed to the opposite value; 10909 * if the variable is already fixed to the given value, the implication is performed immediately; 10910 * if the implication is redundant with respect to the variables' global bounds, it is ignored 10911 */ 10912 SCIP_RETCODE SCIPvarAddImplic( 10913 SCIP_VAR* var, /**< problem variable */ 10914 BMS_BLKMEM* blkmem, /**< block memory */ 10915 SCIP_SET* set, /**< global SCIP settings */ 10916 SCIP_STAT* stat, /**< problem statistics */ 10917 SCIP_PROB* transprob, /**< transformed problem */ 10918 SCIP_PROB* origprob, /**< original problem */ 10919 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */ 10920 SCIP_REOPT* reopt, /**< reoptimization data structure */ 10921 SCIP_LP* lp, /**< current LP data */ 10922 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 10923 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 10924 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 10925 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */ 10926 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */ 10927 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */ 10928 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */ 10929 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */ 10930 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */ 10931 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */ 10932 ) 10933 { 10934 assert(var != NULL); 10935 assert(set != NULL); 10936 assert(var->scip == set->scip); 10937 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY); 10938 assert(infeasible != NULL); 10939 10940 *infeasible = FALSE; 10941 if( nbdchgs != NULL ) 10942 *nbdchgs = 0; 10943 10944 switch( SCIPvarGetStatus(var) ) 10945 { 10946 case SCIP_VARSTATUS_ORIGINAL: 10947 assert(var->data.original.transvar != NULL); 10948 SCIP_CALL( SCIPvarAddImplic(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 10949 cliquetable, branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible, 10950 nbdchgs) ); 10951 break; 10952 10953 case SCIP_VARSTATUS_COLUMN: 10954 case SCIP_VARSTATUS_LOOSE: 10955 /* if the variable is fixed (although it has no FIXED status), and varfixing corresponds to the fixed value of 10956 * the variable, the implication can be applied directly; 10957 * otherwise, add implication to the implications list (and add inverse of implication to the implied variable) 10958 */ 10959 if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 ) 10960 { 10961 if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) ) 10962 { 10963 SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue, 10964 cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) ); 10965 } 10966 } 10967 else 10968 { 10969 SCIP_CALL( SCIPvarGetProbvarBound(&implvar, &implbound, &impltype) ); 10970 SCIPvarAdjustBd(implvar, set, impltype, &implbound); 10971 if( SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED ) 10972 { 10973 SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 10974 branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible, nbdchgs) ); 10975 } 10976 } 10977 break; 10978 10979 case SCIP_VARSTATUS_FIXED: 10980 /* if varfixing corresponds to the fixed value of the variable, the implication can be applied directly */ 10981 if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) ) 10982 { 10983 SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue, 10984 cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) ); 10985 } 10986 break; 10987 10988 case SCIP_VARSTATUS_AGGREGATED: 10989 /* implication added for x == 1: 10990 * x == 1 && x = 1*z + 0 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b 10991 * x == 1 && x = -1*z + 1 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b 10992 * implication added for x == 0: 10993 * x == 0 && x = 1*z + 0 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b 10994 * x == 0 && x = -1*z + 1 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b 10995 * 10996 * use only binary variables z 10997 */ 10998 assert(var->data.aggregate.var != NULL); 10999 if( SCIPvarIsBinary(var->data.aggregate.var) ) 11000 { 11001 assert( (SCIPsetIsEQ(set, var->data.aggregate.scalar, 1.0) && SCIPsetIsZero(set, var->data.aggregate.constant)) 11002 || (SCIPsetIsEQ(set, var->data.aggregate.scalar, -1.0) && SCIPsetIsEQ(set, var->data.aggregate.constant, 1.0)) ); 11003 11004 if( var->data.aggregate.scalar > 0 ) 11005 { 11006 SCIP_CALL( SCIPvarAddImplic(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 11007 cliquetable, branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible, 11008 nbdchgs) ); 11009 } 11010 else 11011 { 11012 SCIP_CALL( SCIPvarAddImplic(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 11013 cliquetable, branchcand, eventqueue, !varfixing, implvar, impltype, implbound, transitive, infeasible, 11014 nbdchgs) ); 11015 } 11016 } 11017 break; 11018 11019 case SCIP_VARSTATUS_MULTAGGR: 11020 /* nothing to do here */ 11021 break; 11022 11023 case SCIP_VARSTATUS_NEGATED: 11024 /* implication added for x == 1: 11025 * x == 1 && x = -1*z + 1 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b 11026 * implication added for x == 0: 11027 * x == 0 && x = -1*z + 1 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b 11028 */ 11029 assert(var->negatedvar != NULL); 11030 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 11031 assert(var->negatedvar->negatedvar == var); 11032 assert(SCIPvarIsBinary(var->negatedvar)); 11033 11034 if( SCIPvarGetType(var->negatedvar) == SCIP_VARTYPE_BINARY ) 11035 { 11036 SCIP_CALL( SCIPvarAddImplic(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 11037 cliquetable, branchcand, eventqueue, !varfixing, implvar, impltype, implbound, transitive, infeasible, nbdchgs) ); 11038 } 11039 /* in case one both variables are not of binary type we have to add the implication as variable bounds */ 11040 else 11041 { 11042 /* if the implied variable is of binary type exchange the variables */ 11043 if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY ) 11044 { 11045 SCIP_CALL( SCIPvarAddImplic(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 11046 branchcand, eventqueue, (impltype == SCIP_BOUNDTYPE_UPPER) ? TRUE : FALSE, var->negatedvar, 11047 varfixing ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER, varfixing ? 1.0 : 0.0, transitive, 11048 infeasible, nbdchgs) ); 11049 } 11050 else 11051 { 11052 /* both variables are not of binary type but are implicit binary; in that case we can only add this 11053 * implication as variable bounds 11054 */ 11055 11056 /* add variable lower bound on the negation of var */ 11057 if( varfixing ) 11058 { 11059 /* (x = 1 => i) z = 0 ii) z = 1) <=> ( i) z = 1 ii) z = 0 => ~x = 1), this is done by adding ~x >= b*z + d 11060 * as variable lower bound 11061 */ 11062 SCIP_CALL( SCIPvarAddVlb(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 11063 cliquetable, branchcand, eventqueue, implvar, (impltype == SCIP_BOUNDTYPE_UPPER) ? 1.0 : -1.0, 11064 (impltype == SCIP_BOUNDTYPE_UPPER) ? 0.0 : 1.0, transitive, infeasible, nbdchgs) ); 11065 } 11066 else 11067 { 11068 /* (x = 0 => i) z = 0 ii) z = 1) <=> ( i) z = 1 ii) z = 0 => ~x = 0), this is done by adding ~x <= b*z + d 11069 * as variable upper bound 11070 */ 11071 SCIP_CALL( SCIPvarAddVub(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, 11072 cliquetable, branchcand, eventqueue, implvar, (impltype == SCIP_BOUNDTYPE_UPPER) ? -1.0 : 1.0, 11073 (impltype == SCIP_BOUNDTYPE_UPPER) ? 1.0 : 0.0, transitive, infeasible, nbdchgs) ); 11074 } 11075 11076 /* add variable bound on implvar */ 11077 if( impltype == SCIP_BOUNDTYPE_UPPER ) 11078 { 11079 /* (z = 1 => i) x = 0 ii) x = 1) <=> ( i) ~x = 0 ii) ~x = 1 => z = 0), this is done by adding z <= b*~x + d 11080 * as variable upper bound 11081 */ 11082 SCIP_CALL( SCIPvarAddVub(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 11083 branchcand, eventqueue, var->negatedvar, (varfixing) ? 1.0 : -1.0, 11084 (varfixing) ? 0.0 : 1.0, transitive, infeasible, nbdchgs) ); 11085 } 11086 else 11087 { 11088 /* (z = 0 => i) x = 0 ii) x = 1) <=> ( i) ~x = 0 ii) ~x = 1 => z = 1), this is done by adding z >= b*~x + d 11089 * as variable upper bound 11090 */ 11091 SCIP_CALL( SCIPvarAddVlb(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, 11092 branchcand, eventqueue, var->negatedvar, (varfixing) ? -1.0 : 1.0, (varfixing) ? 1.0 : 0.0, 11093 transitive, infeasible, nbdchgs) ); 11094 } 11095 } 11096 } 11097 break; 11098 11099 default: 11100 SCIPerrorMessage("unknown variable status\n"); 11101 return SCIP_INVALIDDATA; 11102 } 11103 11104 return SCIP_OKAY; 11105 } 11106 11107 /** returns whether there is an implication x == varfixing -> y <= b or y >= b in the implication graph; 11108 * implications that are represented as cliques in the clique table are not regarded (use SCIPvarsHaveCommonClique()); 11109 * both variables must be active, variable x must be binary 11110 */ 11111 SCIP_Bool SCIPvarHasImplic( 11112 SCIP_VAR* var, /**< problem variable x */ 11113 SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */ 11114 SCIP_VAR* implvar, /**< variable y to search for */ 11115 SCIP_BOUNDTYPE impltype /**< type of implication y <=/>= b to search for */ 11116 ) 11117 { 11118 assert(var != NULL); 11119 assert(implvar != NULL); 11120 assert(SCIPvarIsActive(var)); 11121 assert(SCIPvarIsActive(implvar)); 11122 assert(SCIPvarIsBinary(var)); 11123 11124 return var->implics != NULL && SCIPimplicsContainsImpl(var->implics, varfixing, implvar, impltype); 11125 } 11126 11127 /** returns whether there is an implication x == varfixing -> y == implvarfixing in the implication graph; 11128 * implications that are represented as cliques in the clique table are not regarded (use SCIPvarsHaveCommonClique()); 11129 * both variables must be active binary variables 11130 */ 11131 SCIP_Bool SCIPvarHasBinaryImplic( 11132 SCIP_VAR* var, /**< problem variable x */ 11133 SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */ 11134 SCIP_VAR* implvar, /**< variable y to search for */ 11135 SCIP_Bool implvarfixing /**< value of the implied variable to search for */ 11136 ) 11137 { 11138 assert(SCIPvarIsBinary(implvar)); 11139 11140 return SCIPvarHasImplic(var, varfixing, implvar, implvarfixing ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER); 11141 } 11142 11143 /** gets the values of b in implications x == varfixing -> y <= b or y >= b in the implication graph; 11144 * the values are set to SCIP_INVALID if there is no implied bound 11145 */ 11146 void SCIPvarGetImplicVarBounds( 11147 SCIP_VAR* var, /**< problem variable x */ 11148 SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */ 11149 SCIP_VAR* implvar, /**< variable y to search for */ 11150 SCIP_Real* lb, /**< buffer to store the value of the implied lower bound */ 11151 SCIP_Real* ub /**< buffer to store the value of the implied upper bound */ 11152 ) 11153 { 11154 int lowerpos; 11155 int upperpos; 11156 SCIP_Real* bounds; 11157 11158 assert(lb != NULL); 11159 assert(ub != NULL); 11160 11161 *lb = SCIP_INVALID; 11162 *ub = SCIP_INVALID; 11163 11164 if( var->implics == NULL ) 11165 return; 11166 11167 SCIPimplicsGetVarImplicPoss(var->implics, varfixing, implvar, &lowerpos, &upperpos); 11168 bounds = SCIPvarGetImplBounds(var, varfixing); 11169 11170 if( bounds == NULL ) 11171 return; 11172 11173 if( lowerpos >= 0 ) 11174 *lb = bounds[lowerpos]; 11175 11176 if( upperpos >= 0 ) 11177 *ub = bounds[upperpos]; 11178 } 11179 11180 11181 /** fixes the bounds of a binary variable to the given value, counting bound changes and detecting infeasibility */ 11182 SCIP_RETCODE SCIPvarFixBinary( 11183 SCIP_VAR* var, /**< problem variable */ 11184 BMS_BLKMEM* blkmem, /**< block memory */ 11185 SCIP_SET* set, /**< global SCIP settings */ 11186 SCIP_STAT* stat, /**< problem statistics */ 11187 SCIP_PROB* transprob, /**< transformed problem */ 11188 SCIP_PROB* origprob, /**< original problem */ 11189 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */ 11190 SCIP_REOPT* reopt, /**< reoptimization data structure */ 11191 SCIP_LP* lp, /**< current LP data */ 11192 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 11193 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 11194 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 11195 SCIP_Bool value, /**< value to fix variable to */ 11196 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */ 11197 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */ 11198 ) 11199 { 11200 assert(var != NULL); 11201 assert(set != NULL); 11202 assert(var->scip == set->scip); 11203 assert(infeasible != NULL); 11204 11205 *infeasible = FALSE; 11206 11207 if( value == FALSE ) 11208 { 11209 if( var->glbdom.lb > 0.5 ) 11210 *infeasible = TRUE; 11211 else if( var->glbdom.ub > 0.5 ) 11212 { 11213 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 11214 * with the local bound, in this case we need to store the bound change as pending bound change 11215 */ 11216 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 11217 { 11218 assert(tree != NULL); 11219 assert(transprob != NULL); 11220 assert(SCIPprobIsTransformed(transprob)); 11221 11222 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 11223 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) ); 11224 } 11225 else 11226 { 11227 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 0.0) ); 11228 } 11229 11230 if( nbdchgs != NULL ) 11231 (*nbdchgs)++; 11232 } 11233 } 11234 else 11235 { 11236 if( var->glbdom.ub < 0.5 ) 11237 *infeasible = TRUE; 11238 else if( var->glbdom.lb < 0.5 ) 11239 { 11240 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts 11241 * with the local bound, in this case we need to store the bound change as pending bound change 11242 */ 11243 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING ) 11244 { 11245 assert(tree != NULL); 11246 assert(transprob != NULL); 11247 assert(SCIPprobIsTransformed(transprob)); 11248 11249 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, 11250 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) ); 11251 } 11252 else 11253 { 11254 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 1.0) ); 11255 } 11256 11257 if( nbdchgs != NULL ) 11258 (*nbdchgs)++; 11259 } 11260 } 11261 11262 return SCIP_OKAY; 11263 } 11264 11265 /** adds the variable to the given clique and updates the list of cliques the binary variable is member of; 11266 * if the variable now appears twice in the clique with the same value, it is fixed to the opposite value; 11267 * if the variable now appears twice in the clique with opposite values, all other variables are fixed to 11268 * the opposite of the value they take in the clique 11269 */ 11270 SCIP_RETCODE SCIPvarAddClique( 11271 SCIP_VAR* var, /**< problem variable */ 11272 BMS_BLKMEM* blkmem, /**< block memory */ 11273 SCIP_SET* set, /**< global SCIP settings */ 11274 SCIP_STAT* stat, /**< problem statistics */ 11275 SCIP_PROB* transprob, /**< transformed problem */ 11276 SCIP_PROB* origprob, /**< original problem */ 11277 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */ 11278 SCIP_REOPT* reopt, /**< reoptimization data structure */ 11279 SCIP_LP* lp, /**< current LP data */ 11280 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 11281 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 11282 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 11283 SCIP_Bool value, /**< value of the variable in the clique */ 11284 SCIP_CLIQUE* clique, /**< clique the variable should be added to */ 11285 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */ 11286 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */ 11287 ) 11288 { 11289 assert(var != NULL); 11290 assert(set != NULL); 11291 assert(var->scip == set->scip); 11292 assert(SCIPvarIsBinary(var)); 11293 assert(infeasible != NULL); 11294 11295 *infeasible = FALSE; 11296 11297 /* get corresponding active problem variable */ 11298 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) ); 11299 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN 11300 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE 11301 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED 11302 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); 11303 assert(SCIPvarIsBinary(var)); 11304 11305 /* only column and loose variables may be member of a clique */ 11306 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE ) 11307 { 11308 SCIP_Bool doubleentry; 11309 SCIP_Bool oppositeentry; 11310 11311 /* add variable to clique */ 11312 SCIP_CALL( SCIPcliqueAddVar(clique, blkmem, set, var, value, &doubleentry, &oppositeentry) ); 11313 11314 /* add clique to variable's clique list */ 11315 SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, value, clique) ); 11316 11317 /* check consistency of cliquelist */ 11318 SCIPcliquelistCheck(var->cliquelist, var); 11319 11320 /* if the variable now appears twice with the same value in the clique, it can be fixed to the opposite value */ 11321 if( doubleentry ) 11322 { 11323 SCIP_CALL( SCIPvarFixBinary(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, 11324 eventqueue, cliquetable, !value, infeasible, nbdchgs) ); 11325 } 11326 11327 /* if the variable appears with both values in the clique, all other variables of the clique can be fixed 11328 * to the opposite of the value they take in the clique 11329 */ 11330 if( oppositeentry ) 11331 { 11332 SCIP_VAR** vars; 11333 SCIP_Bool* values; 11334 int nvars; 11335 int i; 11336 11337 nvars = SCIPcliqueGetNVars(clique); 11338 vars = SCIPcliqueGetVars(clique); 11339 values = SCIPcliqueGetValues(clique); 11340 for( i = 0; i < nvars && !(*infeasible); ++i ) 11341 { 11342 if( vars[i] == var ) 11343 continue; 11344 11345 SCIP_CALL( SCIPvarFixBinary(vars[i], blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, 11346 eventqueue, cliquetable, !values[i], infeasible, nbdchgs) ); 11347 } 11348 } 11349 } 11350 11351 return SCIP_OKAY; 11352 } 11353 11354 /** adds a filled clique to the cliquelists of all corresponding variables */ 11355 SCIP_RETCODE SCIPvarsAddClique( 11356 SCIP_VAR** vars, /**< problem variables */ 11357 SCIP_Bool* values, /**< values of the variables in the clique */ 11358 int nvars, /**< number of problem variables */ 11359 BMS_BLKMEM* blkmem, /**< block memory */ 11360 SCIP_SET* set, /**< global SCIP settings */ 11361 SCIP_CLIQUE* clique /**< clique that contains all given variables and values */ 11362 ) 11363 { 11364 SCIP_VAR* var; 11365 int v; 11366 11367 assert(vars != NULL); 11368 assert(values != NULL); 11369 assert(nvars > 0); 11370 assert(set != NULL); 11371 assert(blkmem != NULL); 11372 assert(clique != NULL); 11373 11374 for( v = nvars - 1; v >= 0; --v ) 11375 { 11376 var = vars[v]; 11377 assert(SCIPvarIsBinary(var)); 11378 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); 11379 11380 /* add clique to variable's clique list */ 11381 SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, values[v], clique) ); 11382 11383 /* check consistency of cliquelist */ 11384 SCIPcliquelistCheck(var->cliquelist, var); 11385 } 11386 11387 return SCIP_OKAY; 11388 } 11389 11390 /** adds a clique to the list of cliques of the given binary variable, but does not change the clique 11391 * itself 11392 */ 11393 SCIP_RETCODE SCIPvarAddCliqueToList( 11394 SCIP_VAR* var, /**< problem variable */ 11395 BMS_BLKMEM* blkmem, /**< block memory */ 11396 SCIP_SET* set, /**< global SCIP settings */ 11397 SCIP_Bool value, /**< value of the variable in the clique */ 11398 SCIP_CLIQUE* clique /**< clique that should be removed from the variable's clique list */ 11399 ) 11400 { 11401 assert(var != NULL); 11402 assert(SCIPvarIsBinary(var)); 11403 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); 11404 11405 /* add clique to variable's clique list */ 11406 SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, value, clique) ); 11407 11408 return SCIP_OKAY; 11409 } 11410 11411 11412 /** deletes a clique from the list of cliques the binary variable is member of, but does not change the clique 11413 * itself 11414 */ 11415 SCIP_RETCODE SCIPvarDelCliqueFromList( 11416 SCIP_VAR* var, /**< problem variable */ 11417 BMS_BLKMEM* blkmem, /**< block memory */ 11418 SCIP_Bool value, /**< value of the variable in the clique */ 11419 SCIP_CLIQUE* clique /**< clique that should be removed from the variable's clique list */ 11420 ) 11421 { 11422 assert(var != NULL); 11423 assert(SCIPvarIsBinary(var)); 11424 11425 /* delete clique from variable's clique list */ 11426 SCIP_CALL( SCIPcliquelistDel(&var->cliquelist, blkmem, value, clique) ); 11427 11428 return SCIP_OKAY; 11429 } 11430 11431 /** deletes the variable from the given clique and updates the list of cliques the binary variable is member of */ 11432 SCIP_RETCODE SCIPvarDelClique( 11433 SCIP_VAR* var, /**< problem variable */ 11434 BMS_BLKMEM* blkmem, /**< block memory */ 11435 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 11436 SCIP_Bool value, /**< value of the variable in the clique */ 11437 SCIP_CLIQUE* clique /**< clique the variable should be removed from */ 11438 ) 11439 { 11440 assert(var != NULL); 11441 assert(SCIPvarIsBinary(var)); 11442 11443 /* get corresponding active problem variable */ 11444 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) ); 11445 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN 11446 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE 11447 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED 11448 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); 11449 assert(SCIPvarIsBinary(var)); 11450 11451 /* only column and loose variables may be member of a clique */ 11452 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE ) 11453 { 11454 /* delete clique from variable's clique list */ 11455 SCIP_CALL( SCIPcliquelistDel(&var->cliquelist, blkmem, value, clique) ); 11456 11457 /* delete variable from clique */ 11458 SCIPcliqueDelVar(clique, cliquetable, var, value); 11459 11460 /* check consistency of cliquelist */ 11461 SCIPcliquelistCheck(var->cliquelist, var); 11462 } 11463 11464 return SCIP_OKAY; 11465 } 11466 11467 /** returns whether there is a clique that contains both given variable/value pairs; 11468 * the variables must be active binary variables; 11469 * if regardimplics is FALSE, only the cliques in the clique table are looked at; 11470 * if regardimplics is TRUE, both the cliques and the implications of the implication graph are regarded 11471 * 11472 * @note a variable with it's negated variable are NOT! in a clique 11473 * @note a variable with itself are in a clique 11474 */ 11475 SCIP_Bool SCIPvarsHaveCommonClique( 11476 SCIP_VAR* var1, /**< first variable */ 11477 SCIP_Bool value1, /**< value of first variable */ 11478 SCIP_VAR* var2, /**< second variable */ 11479 SCIP_Bool value2, /**< value of second variable */ 11480 SCIP_Bool regardimplics /**< should the implication graph also be searched for a clique? */ 11481 ) 11482 { 11483 assert(var1 != NULL); 11484 assert(var2 != NULL); 11485 assert(SCIPvarIsActive(var1)); 11486 assert(SCIPvarIsActive(var2)); 11487 assert(SCIPvarIsBinary(var1)); 11488 assert(SCIPvarIsBinary(var2)); 11489 11490 return (SCIPcliquelistsHaveCommonClique(var1->cliquelist, value1, var2->cliquelist, value2) 11491 || (regardimplics && SCIPvarHasImplic(var1, value1, var2, value2 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER))); 11492 } 11493 11494 /** actually changes the branch factor of the variable and of all parent variables */ 11495 static 11496 SCIP_RETCODE varProcessChgBranchFactor( 11497 SCIP_VAR* var, /**< problem variable */ 11498 SCIP_SET* set, /**< global SCIP settings */ 11499 SCIP_Real branchfactor /**< factor to weigh variable's branching score with */ 11500 ) 11501 { 11502 SCIP_VAR* parentvar; 11503 SCIP_Real eps; 11504 int i; 11505 11506 assert(var != NULL); 11507 assert(set != NULL); 11508 assert(var->scip == set->scip); 11509 11510 /* only use positive values */ 11511 eps = SCIPsetEpsilon(set); 11512 branchfactor = MAX(branchfactor, eps); 11513 11514 SCIPsetDebugMsg(set, "process changing branch factor of <%s> from %f to %f\n", var->name, var->branchfactor, branchfactor); 11515 11516 if( SCIPsetIsEQ(set, branchfactor, var->branchfactor) ) 11517 return SCIP_OKAY; 11518 11519 /* change the branch factor */ 11520 var->branchfactor = branchfactor; 11521 11522 /* process parent variables */ 11523 for( i = 0; i < var->nparentvars; ++i ) 11524 { 11525 parentvar = var->parentvars[i]; 11526 assert(parentvar != NULL); 11527 11528 switch( SCIPvarGetStatus(parentvar) ) 11529 { 11530 case SCIP_VARSTATUS_ORIGINAL: 11531 /* do not change priorities across the border between transformed and original problem */ 11532 break; 11533 11534 case SCIP_VARSTATUS_COLUMN: 11535 case SCIP_VARSTATUS_LOOSE: 11536 case SCIP_VARSTATUS_FIXED: 11537 case SCIP_VARSTATUS_MULTAGGR: 11538 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n"); 11539 SCIPABORT(); 11540 return SCIP_INVALIDDATA; /*lint !e527*/ 11541 11542 case SCIP_VARSTATUS_AGGREGATED: 11543 case SCIP_VARSTATUS_NEGATED: 11544 SCIP_CALL( varProcessChgBranchFactor(parentvar, set, branchfactor) ); 11545 break; 11546 11547 default: 11548 SCIPerrorMessage("unknown variable status\n"); 11549 SCIPABORT(); 11550 return SCIP_ERROR; /*lint !e527*/ 11551 } 11552 } 11553 11554 return SCIP_OKAY; 11555 } 11556 11557 /** sets the branch factor of the variable; this value can be used in the branching methods to scale the score 11558 * values of the variables; higher factor leads to a higher probability that this variable is chosen for branching 11559 */ 11560 SCIP_RETCODE SCIPvarChgBranchFactor( 11561 SCIP_VAR* var, /**< problem variable */ 11562 SCIP_SET* set, /**< global SCIP settings */ 11563 SCIP_Real branchfactor /**< factor to weigh variable's branching score with */ 11564 ) 11565 { 11566 int v; 11567 11568 assert(var != NULL); 11569 assert(set != NULL); 11570 assert(var->scip == set->scip); 11571 assert(branchfactor >= 0.0); 11572 11573 SCIPdebugMessage("changing branch factor of <%s> from %g to %g\n", var->name, var->branchfactor, branchfactor); 11574 11575 if( SCIPsetIsEQ(set, var->branchfactor, branchfactor) ) 11576 return SCIP_OKAY; 11577 11578 /* change priorities of attached variables */ 11579 switch( SCIPvarGetStatus(var) ) 11580 { 11581 case SCIP_VARSTATUS_ORIGINAL: 11582 if( var->data.original.transvar != NULL ) 11583 { 11584 SCIP_CALL( SCIPvarChgBranchFactor(var->data.original.transvar, set, branchfactor) ); 11585 } 11586 else 11587 { 11588 assert(set->stage == SCIP_STAGE_PROBLEM); 11589 var->branchfactor = branchfactor; 11590 } 11591 break; 11592 11593 case SCIP_VARSTATUS_COLUMN: 11594 case SCIP_VARSTATUS_LOOSE: 11595 case SCIP_VARSTATUS_FIXED: 11596 SCIP_CALL( varProcessChgBranchFactor(var, set, branchfactor) ); 11597 break; 11598 11599 case SCIP_VARSTATUS_AGGREGATED: 11600 assert(!var->donotaggr); 11601 assert(var->data.aggregate.var != NULL); 11602 SCIP_CALL( SCIPvarChgBranchFactor(var->data.aggregate.var, set, branchfactor) ); 11603 break; 11604 11605 case SCIP_VARSTATUS_MULTAGGR: 11606 assert(!var->donotmultaggr); 11607 for( v = 0; v < var->data.multaggr.nvars; ++v ) 11608 { 11609 SCIP_CALL( SCIPvarChgBranchFactor(var->data.multaggr.vars[v], set, branchfactor) ); 11610 } 11611 break; 11612 11613 case SCIP_VARSTATUS_NEGATED: 11614 assert(var->negatedvar != NULL); 11615 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 11616 assert(var->negatedvar->negatedvar == var); 11617 SCIP_CALL( SCIPvarChgBranchFactor(var->negatedvar, set, branchfactor) ); 11618 break; 11619 11620 default: 11621 SCIPerrorMessage("unknown variable status\n"); 11622 SCIPABORT(); 11623 return SCIP_ERROR; /*lint !e527*/ 11624 } 11625 11626 return SCIP_OKAY; 11627 } 11628 11629 /** actually changes the branch priority of the variable and of all parent variables */ 11630 static 11631 SCIP_RETCODE varProcessChgBranchPriority( 11632 SCIP_VAR* var, /**< problem variable */ 11633 int branchpriority /**< branching priority of the variable */ 11634 ) 11635 { 11636 SCIP_VAR* parentvar; 11637 int i; 11638 11639 assert(var != NULL); 11640 11641 SCIPdebugMessage("process changing branch priority of <%s> from %d to %d\n", 11642 var->name, var->branchpriority, branchpriority); 11643 11644 if( branchpriority == var->branchpriority ) 11645 return SCIP_OKAY; 11646 11647 /* change the branch priority */ 11648 var->branchpriority = branchpriority; 11649 11650 /* process parent variables */ 11651 for( i = 0; i < var->nparentvars; ++i ) 11652 { 11653 parentvar = var->parentvars[i]; 11654 assert(parentvar != NULL); 11655 11656 switch( SCIPvarGetStatus(parentvar) ) 11657 { 11658 case SCIP_VARSTATUS_ORIGINAL: 11659 /* do not change priorities across the border between transformed and original problem */ 11660 break; 11661 11662 case SCIP_VARSTATUS_COLUMN: 11663 case SCIP_VARSTATUS_LOOSE: 11664 case SCIP_VARSTATUS_FIXED: 11665 case SCIP_VARSTATUS_MULTAGGR: 11666 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n"); 11667 SCIPABORT(); 11668 return SCIP_INVALIDDATA; /*lint !e527*/ 11669 11670 case SCIP_VARSTATUS_AGGREGATED: 11671 case SCIP_VARSTATUS_NEGATED: 11672 SCIP_CALL( varProcessChgBranchPriority(parentvar, branchpriority) ); 11673 break; 11674 11675 default: 11676 SCIPerrorMessage("unknown variable status\n"); 11677 return SCIP_ERROR; 11678 } 11679 } 11680 11681 return SCIP_OKAY; 11682 } 11683 11684 /** sets the branch priority of the variable; variables with higher branch priority are always preferred to variables 11685 * with lower priority in selection of branching variable 11686 */ 11687 SCIP_RETCODE SCIPvarChgBranchPriority( 11688 SCIP_VAR* var, /**< problem variable */ 11689 int branchpriority /**< branching priority of the variable */ 11690 ) 11691 { 11692 int v; 11693 11694 assert(var != NULL); 11695 11696 SCIPdebugMessage("changing branch priority of <%s> from %d to %d\n", var->name, var->branchpriority, branchpriority); 11697 11698 if( var->branchpriority == branchpriority ) 11699 return SCIP_OKAY; 11700 11701 /* change priorities of attached variables */ 11702 switch( SCIPvarGetStatus(var) ) 11703 { 11704 case SCIP_VARSTATUS_ORIGINAL: 11705 if( var->data.original.transvar != NULL ) 11706 { 11707 SCIP_CALL( SCIPvarChgBranchPriority(var->data.original.transvar, branchpriority) ); 11708 } 11709 else 11710 var->branchpriority = branchpriority; 11711 break; 11712 11713 case SCIP_VARSTATUS_COLUMN: 11714 case SCIP_VARSTATUS_LOOSE: 11715 case SCIP_VARSTATUS_FIXED: 11716 SCIP_CALL( varProcessChgBranchPriority(var, branchpriority) ); 11717 break; 11718 11719 case SCIP_VARSTATUS_AGGREGATED: 11720 assert(!var->donotaggr); 11721 assert(var->data.aggregate.var != NULL); 11722 SCIP_CALL( SCIPvarChgBranchPriority(var->data.aggregate.var, branchpriority) ); 11723 break; 11724 11725 case SCIP_VARSTATUS_MULTAGGR: 11726 assert(!var->donotmultaggr); 11727 for( v = 0; v < var->data.multaggr.nvars; ++v ) 11728 { 11729 SCIP_CALL( SCIPvarChgBranchPriority(var->data.multaggr.vars[v], branchpriority) ); 11730 } 11731 break; 11732 11733 case SCIP_VARSTATUS_NEGATED: 11734 assert(var->negatedvar != NULL); 11735 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 11736 assert(var->negatedvar->negatedvar == var); 11737 SCIP_CALL( SCIPvarChgBranchPriority(var->negatedvar, branchpriority) ); 11738 break; 11739 11740 default: 11741 SCIPerrorMessage("unknown variable status\n"); 11742 SCIPABORT(); 11743 return SCIP_ERROR; /*lint !e527*/ 11744 } 11745 11746 return SCIP_OKAY; 11747 } 11748 11749 /** actually changes the branch direction of the variable and of all parent variables */ 11750 static 11751 SCIP_RETCODE varProcessChgBranchDirection( 11752 SCIP_VAR* var, /**< problem variable */ 11753 SCIP_BRANCHDIR branchdirection /**< preferred branch direction of the variable (downwards, upwards, auto) */ 11754 ) 11755 { 11756 SCIP_VAR* parentvar; 11757 int i; 11758 11759 assert(var != NULL); 11760 11761 SCIPdebugMessage("process changing branch direction of <%s> from %u to %d\n", 11762 var->name, var->branchdirection, branchdirection); 11763 11764 if( branchdirection == (SCIP_BRANCHDIR)var->branchdirection ) 11765 return SCIP_OKAY; 11766 11767 /* change the branch direction */ 11768 var->branchdirection = branchdirection; /*lint !e641*/ 11769 11770 /* process parent variables */ 11771 for( i = 0; i < var->nparentvars; ++i ) 11772 { 11773 parentvar = var->parentvars[i]; 11774 assert(parentvar != NULL); 11775 11776 switch( SCIPvarGetStatus(parentvar) ) 11777 { 11778 case SCIP_VARSTATUS_ORIGINAL: 11779 /* do not change directions across the border between transformed and original problem */ 11780 break; 11781 11782 case SCIP_VARSTATUS_COLUMN: 11783 case SCIP_VARSTATUS_LOOSE: 11784 case SCIP_VARSTATUS_FIXED: 11785 case SCIP_VARSTATUS_MULTAGGR: 11786 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n"); 11787 SCIPABORT(); 11788 return SCIP_INVALIDDATA; /*lint !e527*/ 11789 11790 case SCIP_VARSTATUS_AGGREGATED: 11791 if( parentvar->data.aggregate.scalar > 0.0 ) 11792 { 11793 SCIP_CALL( varProcessChgBranchDirection(parentvar, branchdirection) ); 11794 } 11795 else 11796 { 11797 SCIP_CALL( varProcessChgBranchDirection(parentvar, SCIPbranchdirOpposite(branchdirection)) ); 11798 } 11799 break; 11800 11801 case SCIP_VARSTATUS_NEGATED: 11802 SCIP_CALL( varProcessChgBranchDirection(parentvar, SCIPbranchdirOpposite(branchdirection)) ); 11803 break; 11804 11805 default: 11806 SCIPerrorMessage("unknown variable status\n"); 11807 SCIPABORT(); 11808 return SCIP_ERROR; /*lint !e527*/ 11809 } 11810 } 11811 11812 return SCIP_OKAY; 11813 } 11814 11815 /** sets the branch direction of the variable; variables with higher branch direction are always preferred to variables 11816 * with lower direction in selection of branching variable 11817 */ 11818 SCIP_RETCODE SCIPvarChgBranchDirection( 11819 SCIP_VAR* var, /**< problem variable */ 11820 SCIP_BRANCHDIR branchdirection /**< preferred branch direction of the variable (downwards, upwards, auto) */ 11821 ) 11822 { 11823 int v; 11824 11825 assert(var != NULL); 11826 11827 SCIPdebugMessage("changing branch direction of <%s> from %u to %d\n", var->name, var->branchdirection, branchdirection); 11828 11829 if( (SCIP_BRANCHDIR)var->branchdirection == branchdirection ) 11830 return SCIP_OKAY; 11831 11832 /* change directions of attached variables */ 11833 switch( SCIPvarGetStatus(var) ) 11834 { 11835 case SCIP_VARSTATUS_ORIGINAL: 11836 if( var->data.original.transvar != NULL ) 11837 { 11838 SCIP_CALL( SCIPvarChgBranchDirection(var->data.original.transvar, branchdirection) ); 11839 } 11840 else 11841 var->branchdirection = branchdirection; /*lint !e641*/ 11842 break; 11843 11844 case SCIP_VARSTATUS_COLUMN: 11845 case SCIP_VARSTATUS_LOOSE: 11846 case SCIP_VARSTATUS_FIXED: 11847 SCIP_CALL( varProcessChgBranchDirection(var, branchdirection) ); 11848 break; 11849 11850 case SCIP_VARSTATUS_AGGREGATED: 11851 assert(!var->donotaggr); 11852 assert(var->data.aggregate.var != NULL); 11853 if( var->data.aggregate.scalar > 0.0 ) 11854 { 11855 SCIP_CALL( SCIPvarChgBranchDirection(var->data.aggregate.var, branchdirection) ); 11856 } 11857 else 11858 { 11859 SCIP_CALL( SCIPvarChgBranchDirection(var->data.aggregate.var, SCIPbranchdirOpposite(branchdirection)) ); 11860 } 11861 break; 11862 11863 case SCIP_VARSTATUS_MULTAGGR: 11864 assert(!var->donotmultaggr); 11865 for( v = 0; v < var->data.multaggr.nvars; ++v ) 11866 { 11867 /* only update branching direction of aggregation variables, if they don't have a preferred direction yet */ 11868 assert(var->data.multaggr.vars[v] != NULL); 11869 if( (SCIP_BRANCHDIR)var->data.multaggr.vars[v]->branchdirection == SCIP_BRANCHDIR_AUTO ) 11870 { 11871 if( var->data.multaggr.scalars[v] > 0.0 ) 11872 { 11873 SCIP_CALL( SCIPvarChgBranchDirection(var->data.multaggr.vars[v], branchdirection) ); 11874 } 11875 else 11876 { 11877 SCIP_CALL( SCIPvarChgBranchDirection(var->data.multaggr.vars[v], SCIPbranchdirOpposite(branchdirection)) ); 11878 } 11879 } 11880 } 11881 break; 11882 11883 case SCIP_VARSTATUS_NEGATED: 11884 assert(var->negatedvar != NULL); 11885 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 11886 assert(var->negatedvar->negatedvar == var); 11887 SCIP_CALL( SCIPvarChgBranchDirection(var->negatedvar, SCIPbranchdirOpposite(branchdirection)) ); 11888 break; 11889 11890 default: 11891 SCIPerrorMessage("unknown variable status\n"); 11892 SCIPABORT(); 11893 return SCIP_ERROR; /*lint !e527*/ 11894 } 11895 11896 return SCIP_OKAY; 11897 } 11898 11899 /** compares the index of two variables, only active, fixed or negated variables are allowed, if a variable 11900 * is negated then the index of the corresponding active variable is taken, returns -1 if first is 11901 * smaller than, and +1 if first is greater than second variable index; returns 0 if both indices 11902 * are equal, which means both variables are equal 11903 */ 11904 int SCIPvarCompareActiveAndNegated( 11905 SCIP_VAR* var1, /**< first problem variable */ 11906 SCIP_VAR* var2 /**< second problem variable */ 11907 ) 11908 { 11909 assert(var1 != NULL); 11910 assert(var2 != NULL); 11911 assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_FIXED); 11912 assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_FIXED); 11913 11914 if( SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED ) 11915 var1 = SCIPvarGetNegatedVar(var1); 11916 if( SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED ) 11917 var2 = SCIPvarGetNegatedVar(var2); 11918 11919 assert(var1 != NULL); 11920 assert(var2 != NULL); 11921 11922 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) ) 11923 return -1; 11924 else if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) ) 11925 return +1; 11926 11927 assert(var1 == var2); 11928 return 0; 11929 } 11930 11931 /** comparison method for sorting active and negated variables by non-decreasing index, active and negated 11932 * variables are handled as the same variables 11933 */ 11934 SCIP_DECL_SORTPTRCOMP(SCIPvarCompActiveAndNegated) 11935 { 11936 return SCIPvarCompareActiveAndNegated((SCIP_VAR*)elem1, (SCIP_VAR*)elem2); 11937 } 11938 11939 /** compares the index of two variables, returns -1 if first is smaller than, and +1 if first is greater than second 11940 * variable index; returns 0 if both indices are equal, which means both variables are equal 11941 */ 11942 int SCIPvarCompare( 11943 SCIP_VAR* var1, /**< first problem variable */ 11944 SCIP_VAR* var2 /**< second problem variable */ 11945 ) 11946 { 11947 assert(var1 != NULL); 11948 assert(var2 != NULL); 11949 11950 if( var1->index < var2->index ) 11951 return -1; 11952 else if( var1->index > var2->index ) 11953 return +1; 11954 else 11955 { 11956 assert(var1 == var2); 11957 return 0; 11958 } 11959 } 11960 11961 /** comparison method for sorting variables by non-decreasing index */ 11962 SCIP_DECL_SORTPTRCOMP(SCIPvarComp) 11963 { 11964 return SCIPvarCompare((SCIP_VAR*)elem1, (SCIP_VAR*)elem2); 11965 } 11966 11967 /** comparison method for sorting variables by non-decreasing objective coefficient */ 11968 SCIP_DECL_SORTPTRCOMP(SCIPvarCompObj) 11969 { 11970 SCIP_Real obj1; 11971 SCIP_Real obj2; 11972 11973 obj1 = SCIPvarGetObj((SCIP_VAR*)elem1); 11974 obj2 = SCIPvarGetObj((SCIP_VAR*)elem2); 11975 11976 if( obj1 < obj2 ) 11977 return -1; 11978 else if( obj1 > obj2 ) 11979 return +1; 11980 else 11981 return 0; 11982 } 11983 11984 /** hash key retrieval function for variables */ 11985 SCIP_DECL_HASHGETKEY(SCIPvarGetHashkey) 11986 { /*lint --e{715}*/ 11987 return elem; 11988 } 11989 11990 /** returns TRUE iff the indices of both variables are equal */ 11991 SCIP_DECL_HASHKEYEQ(SCIPvarIsHashkeyEq) 11992 { /*lint --e{715}*/ 11993 if( key1 == key2 ) 11994 return TRUE; 11995 return FALSE; 11996 } 11997 11998 /** returns the hash value of the key */ 11999 SCIP_DECL_HASHKEYVAL(SCIPvarGetHashkeyVal) 12000 { /*lint --e{715}*/ 12001 assert( SCIPvarGetIndex((SCIP_VAR*) key) >= 0 ); 12002 return (unsigned int) SCIPvarGetIndex((SCIP_VAR*) key); 12003 } 12004 12005 /** return for given variables all their active counterparts; all active variables will be pairwise different */ 12006 SCIP_RETCODE SCIPvarsGetActiveVars( 12007 SCIP_SET* set, /**< global SCIP settings */ 12008 SCIP_VAR** vars, /**< variable array with given variables and as output all active 12009 * variables, if enough slots exist 12010 */ 12011 int* nvars, /**< number of given variables, and as output number of active variables, 12012 * if enough slots exist 12013 */ 12014 int varssize, /**< available slots in vars array */ 12015 int* requiredsize /**< pointer to store the required array size for the active variables */ 12016 ) 12017 { 12018 SCIP_VAR** activevars; 12019 int nactivevars; 12020 int activevarssize; 12021 12022 SCIP_VAR* var; 12023 int v; 12024 12025 SCIP_VAR** tmpvars; 12026 SCIP_VAR** multvars; 12027 int tmpvarssize; 12028 int ntmpvars; 12029 int noldtmpvars; 12030 int nmultvars; 12031 12032 assert(set != NULL); 12033 assert(nvars != NULL); 12034 assert(vars != NULL || *nvars == 0); 12035 assert(varssize >= *nvars); 12036 assert(requiredsize != NULL); 12037 12038 *requiredsize = 0; 12039 12040 if( *nvars == 0 ) 12041 return SCIP_OKAY; 12042 12043 nactivevars = 0; 12044 activevarssize = *nvars; 12045 ntmpvars = *nvars; 12046 tmpvarssize = *nvars; 12047 12048 /* temporary memory */ 12049 SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) ); 12050 /* coverity[copy_paste_error] */ 12051 SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) ); 12052 12053 noldtmpvars = ntmpvars; 12054 12055 /* sort all variables to combine equal variables easily */ 12056 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars); 12057 for( v = ntmpvars - 1; v > 0; --v ) 12058 { 12059 /* combine same variables */ 12060 if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 ) 12061 { 12062 --ntmpvars; 12063 tmpvars[v] = tmpvars[ntmpvars]; 12064 } 12065 } 12066 /* sort all variables again to combine equal variables later on */ 12067 if( noldtmpvars > ntmpvars ) 12068 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars); 12069 12070 /* collect for each variable the representation in active variables */ 12071 while( ntmpvars >= 1 ) 12072 { 12073 --ntmpvars; 12074 var = tmpvars[ntmpvars]; 12075 assert( var != NULL ); 12076 12077 switch( SCIPvarGetStatus(var) ) 12078 { 12079 case SCIP_VARSTATUS_ORIGINAL: 12080 if( var->data.original.transvar == NULL ) 12081 { 12082 SCIPerrorMessage("original variable has no transformed variable attached\n"); 12083 SCIPABORT(); 12084 return SCIP_INVALIDDATA; /*lint !e527*/ 12085 } 12086 tmpvars[ntmpvars] = var->data.original.transvar; 12087 ++ntmpvars; 12088 break; 12089 12090 case SCIP_VARSTATUS_AGGREGATED: 12091 tmpvars[ntmpvars] = var->data.aggregate.var; 12092 ++ntmpvars; 12093 break; 12094 12095 case SCIP_VARSTATUS_NEGATED: 12096 tmpvars[ntmpvars] = var->negatedvar; 12097 ++ntmpvars; 12098 break; 12099 12100 case SCIP_VARSTATUS_LOOSE: 12101 case SCIP_VARSTATUS_COLUMN: 12102 /* check for space in temporary memory */ 12103 if( nactivevars >= activevarssize ) 12104 { 12105 activevarssize *= 2; 12106 SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) ); 12107 assert(nactivevars < activevarssize); 12108 } 12109 activevars[nactivevars] = var; 12110 nactivevars++; 12111 break; 12112 12113 case SCIP_VARSTATUS_MULTAGGR: 12114 /* x = a_1*y_1 + ... + a_n*y_n + c */ 12115 nmultvars = var->data.multaggr.nvars; 12116 multvars = var->data.multaggr.vars; 12117 12118 /* check for space in temporary memory */ 12119 if( nmultvars + ntmpvars > tmpvarssize ) 12120 { 12121 while( nmultvars + ntmpvars > tmpvarssize ) 12122 tmpvarssize *= 2; 12123 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) ); 12124 assert(nmultvars + ntmpvars <= tmpvarssize); 12125 } 12126 12127 /* copy all multi-aggregation variables into our working array */ 12128 BMScopyMemoryArray(&tmpvars[ntmpvars], multvars, nmultvars); /*lint !e866*/ 12129 12130 /* get active, fixed or multi-aggregated corresponding variables for all new ones */ 12131 SCIPvarsGetProbvar(&tmpvars[ntmpvars], nmultvars); 12132 12133 ntmpvars += nmultvars; 12134 noldtmpvars = ntmpvars; 12135 12136 /* sort all variables to combine equal variables easily */ 12137 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars); 12138 for( v = ntmpvars - 1; v > 0; --v ) 12139 { 12140 /* combine same variables */ 12141 if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 ) 12142 { 12143 --ntmpvars; 12144 tmpvars[v] = tmpvars[ntmpvars]; 12145 } 12146 } 12147 /* sort all variables again to combine equal variables later on */ 12148 if( noldtmpvars > ntmpvars ) 12149 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars); 12150 12151 break; 12152 12153 case SCIP_VARSTATUS_FIXED: 12154 /* no need for memorizing fixed variables */ 12155 break; 12156 12157 default: 12158 SCIPerrorMessage("unknown variable status\n"); 12159 SCIPABORT(); 12160 return SCIP_INVALIDDATA; /*lint !e527*/ 12161 } 12162 } 12163 12164 /* sort variable array by variable index */ 12165 SCIPsortPtr((void**)activevars, SCIPvarComp, nactivevars); 12166 12167 /* eliminate duplicates and count required size */ 12168 v = nactivevars - 1; 12169 while( v > 0 ) 12170 { 12171 /* combine both variable since they are the same */ 12172 if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 ) 12173 { 12174 --nactivevars; 12175 activevars[v] = activevars[nactivevars]; 12176 } 12177 --v; 12178 } 12179 *requiredsize = nactivevars; 12180 12181 if( varssize >= *requiredsize ) 12182 { 12183 assert(vars != NULL); 12184 12185 *nvars = *requiredsize; 12186 BMScopyMemoryArray(vars, activevars, nactivevars); 12187 } 12188 12189 SCIPsetFreeBufferArray(set, &tmpvars); 12190 SCIPsetFreeBufferArray(set, &activevars); 12191 12192 return SCIP_OKAY; 12193 } 12194 12195 /** gets corresponding active, fixed, or multi-aggregated problem variables of given variables, 12196 * @note the content of the given array will/might change 12197 */ 12198 void SCIPvarsGetProbvar( 12199 SCIP_VAR** vars, /**< array of problem variables */ 12200 int nvars /**< number of variables */ 12201 ) 12202 { 12203 int v; 12204 12205 assert(vars != NULL || nvars == 0); 12206 12207 for( v = nvars - 1; v >= 0; --v ) 12208 { 12209 assert(vars != NULL); 12210 assert(vars[v] != NULL); 12211 12212 vars[v] = SCIPvarGetProbvar(vars[v]); 12213 assert(vars[v] != NULL); 12214 } 12215 } 12216 12217 /** gets corresponding active, fixed, or multi-aggregated problem variable of a variable */ 12218 SCIP_VAR* SCIPvarGetProbvar( 12219 SCIP_VAR* var /**< problem variable */ 12220 ) 12221 { 12222 SCIP_VAR* retvar; 12223 12224 assert(var != NULL); 12225 12226 retvar = var; 12227 12228 SCIPdebugMessage("get problem variable of <%s>\n", var->name); 12229 12230 while( TRUE ) /*lint !e716 */ 12231 { 12232 assert(retvar != NULL); 12233 12234 switch( SCIPvarGetStatus(retvar) ) 12235 { 12236 case SCIP_VARSTATUS_ORIGINAL: 12237 if( retvar->data.original.transvar == NULL ) 12238 { 12239 SCIPerrorMessage("original variable has no transformed variable attached\n"); 12240 SCIPABORT(); 12241 return NULL; /*lint !e527 */ 12242 } 12243 retvar = retvar->data.original.transvar; 12244 break; 12245 12246 case SCIP_VARSTATUS_LOOSE: 12247 case SCIP_VARSTATUS_COLUMN: 12248 case SCIP_VARSTATUS_FIXED: 12249 return retvar; 12250 12251 case SCIP_VARSTATUS_MULTAGGR: 12252 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */ 12253 if ( retvar->data.multaggr.nvars == 1 ) 12254 retvar = retvar->data.multaggr.vars[0]; 12255 else 12256 return retvar; 12257 break; 12258 12259 case SCIP_VARSTATUS_AGGREGATED: 12260 retvar = retvar->data.aggregate.var; 12261 break; 12262 12263 case SCIP_VARSTATUS_NEGATED: 12264 retvar = retvar->negatedvar; 12265 break; 12266 12267 default: 12268 SCIPerrorMessage("unknown variable status\n"); 12269 SCIPABORT(); 12270 return NULL; /*lint !e527*/ 12271 } 12272 } 12273 } 12274 12275 /** gets corresponding active, fixed, or multi-aggregated problem variables of binary variables and updates the given 12276 * negation status of each variable 12277 */ 12278 SCIP_RETCODE SCIPvarsGetProbvarBinary( 12279 SCIP_VAR*** vars, /**< pointer to binary problem variables */ 12280 SCIP_Bool** negatedarr, /**< pointer to corresponding array to update the negation status */ 12281 int nvars /**< number of variables and values in vars and negated array */ 12282 ) 12283 { 12284 SCIP_VAR** var; 12285 SCIP_Bool* negated; 12286 int v; 12287 12288 assert(vars != NULL); 12289 assert(*vars != NULL || nvars == 0); 12290 assert(negatedarr != NULL); 12291 assert(*negatedarr != NULL || nvars == 0); 12292 12293 for( v = nvars - 1; v >= 0; --v ) 12294 { 12295 var = &((*vars)[v]); 12296 negated = &((*negatedarr)[v]); 12297 12298 /* get problem variable */ 12299 SCIP_CALL( SCIPvarGetProbvarBinary(var, negated) ); 12300 } 12301 12302 return SCIP_OKAY; 12303 } 12304 12305 12306 /** gets corresponding active, fixed, or multi-aggregated problem variable of a binary variable and updates the given 12307 * negation status (this means you have to assign a value to SCIP_Bool negated before calling this method, usually 12308 * FALSE is used) 12309 */ 12310 SCIP_RETCODE SCIPvarGetProbvarBinary( 12311 SCIP_VAR** var, /**< pointer to binary problem variable */ 12312 SCIP_Bool* negated /**< pointer to update the negation status */ 12313 ) 12314 { 12315 SCIP_Bool active = FALSE; 12316 #ifndef NDEBUG 12317 SCIP_Real constant = 0.0; 12318 SCIP_Bool orignegated; 12319 #endif 12320 12321 assert(var != NULL); 12322 assert(*var != NULL); 12323 assert(negated != NULL); 12324 assert(SCIPvarIsBinary(*var)); 12325 12326 #ifndef NDEBUG 12327 orignegated = *negated; 12328 #endif 12329 12330 while( !active && *var != NULL ) 12331 { 12332 switch( SCIPvarGetStatus(*var) ) 12333 { 12334 case SCIP_VARSTATUS_ORIGINAL: 12335 if( (*var)->data.original.transvar == NULL ) 12336 return SCIP_OKAY; 12337 *var = (*var)->data.original.transvar; 12338 break; 12339 12340 case SCIP_VARSTATUS_LOOSE: 12341 case SCIP_VARSTATUS_COLUMN: 12342 case SCIP_VARSTATUS_FIXED: 12343 active = TRUE; 12344 break; 12345 12346 case SCIP_VARSTATUS_MULTAGGR: 12347 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */ 12348 if ( (*var)->data.multaggr.nvars == 1 ) 12349 { 12350 assert( (*var)->data.multaggr.vars != NULL ); 12351 assert( (*var)->data.multaggr.scalars != NULL ); 12352 assert( SCIPvarIsBinary((*var)->data.multaggr.vars[0]) ); 12353 assert(!EPSZ((*var)->data.multaggr.scalars[0], 1e-06)); 12354 12355 /* if not all variables were fully propagated, it might happen that a variable is multi-aggregated to 12356 * another variable which needs to be fixed 12357 * 12358 * e.g. x = y - 1 => (x = 0 && y = 1) 12359 * e.g. x = y + 1 => (x = 1 && y = 0) 12360 * 12361 * is this special case we need to return the muti-aggregation 12362 */ 12363 if( EPSEQ((*var)->data.multaggr.constant, -1.0, 1e-06) || (EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06) && EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06)) ) 12364 { 12365 assert(EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06)); 12366 } 12367 else 12368 { 12369 /* @note due to fixations, a multi-aggregation can have a constant of zero and a negative scalar or even 12370 * a scalar in absolute value unequal to one, in this case this aggregation variable needs to be 12371 * fixed to zero, but this should be done by another enforcement; so not depending on the scalar, 12372 * we will return the aggregated variable; 12373 */ 12374 if( !EPSEQ(REALABS((*var)->data.multaggr.scalars[0]), 1.0, 1e-06) ) 12375 { 12376 active = TRUE; 12377 break; 12378 } 12379 12380 /* @note it may also happen that the constant is larger than 1 or smaller than 0, in that case the 12381 * aggregation variable needs to be fixed to one, but this should be done by another enforcement; 12382 * so if this is the case, we will return the aggregated variable 12383 */ 12384 assert(EPSZ((*var)->data.multaggr.constant, 1e-06) || EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06) 12385 || EPSZ((*var)->data.multaggr.constant + (*var)->data.multaggr.scalars[0], 1e-06) 12386 || EPSEQ((*var)->data.multaggr.constant + (*var)->data.multaggr.scalars[0], 1.0, 1e-06)); 12387 12388 if( !EPSZ((*var)->data.multaggr.constant, 1e-06) && !EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06) ) 12389 { 12390 active = TRUE; 12391 break; 12392 } 12393 12394 assert(EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06) || EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06)); 12395 12396 if( EPSZ((*var)->data.multaggr.constant, 1e-06) ) 12397 { 12398 /* if the scalar is negative, either the aggregation variable is already fixed to zero or has at 12399 * least one uplock (that hopefully will enforce this fixation to zero); can it happen that this 12400 * variable itself is multi-aggregated again? 12401 */ 12402 assert(EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06) ? 12403 ((SCIPvarGetUbGlobal((*var)->data.multaggr.vars[0]) < 0.5) || 12404 SCIPvarGetNLocksUpType((*var)->data.multaggr.vars[0], SCIP_LOCKTYPE_MODEL) > 0) : TRUE); 12405 } 12406 else 12407 { 12408 assert(EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06)); 12409 #ifndef NDEBUG 12410 constant += (*negated) != orignegated ? -1.0 : 1.0; 12411 #endif 12412 12413 *negated = !(*negated); 12414 } 12415 *var = (*var)->data.multaggr.vars[0]; 12416 break; 12417 } 12418 } 12419 active = TRUE; /*lint !e838*/ 12420 break; 12421 12422 case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */ 12423 assert((*var)->data.aggregate.var != NULL); 12424 assert(EPSEQ((*var)->data.aggregate.scalar, 1.0, 1e-06) || EPSEQ((*var)->data.aggregate.scalar, -1.0, 1e-06)); 12425 assert(EPSLE((*var)->data.aggregate.var->glbdom.ub - (*var)->data.aggregate.var->glbdom.lb, 1.0, 1e-06)); 12426 #ifndef NDEBUG 12427 constant += (*negated) != orignegated ? -(*var)->data.aggregate.constant : (*var)->data.aggregate.constant; 12428 #endif 12429 12430 *negated = ((*var)->data.aggregate.scalar > 0.0) ? *negated : !(*negated); 12431 *var = (*var)->data.aggregate.var; 12432 break; 12433 12434 case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */ 12435 assert((*var)->negatedvar != NULL); 12436 #ifndef NDEBUG 12437 constant += (*negated) != orignegated ? -1.0 : 1.0; 12438 #endif 12439 12440 *negated = !(*negated); 12441 *var = (*var)->negatedvar; 12442 break; 12443 12444 default: 12445 SCIPerrorMessage("unknown variable status\n"); 12446 return SCIP_INVALIDDATA; 12447 } 12448 } 12449 assert(active == (*var != NULL)); 12450 12451 if( active ) 12452 { 12453 assert(SCIPvarIsBinary(*var)); 12454 assert(EPSZ(constant, 1e-06) || EPSEQ(constant, 1.0, 1e-06)); 12455 assert(EPSZ(constant, 1e-06) == ((*negated) == orignegated)); 12456 12457 return SCIP_OKAY; 12458 } 12459 else 12460 { 12461 SCIPerrorMessage("active variable path leads to NULL pointer\n"); 12462 return SCIP_INVALIDDATA; 12463 } 12464 } 12465 12466 /** transforms given variable, boundtype and bound to the corresponding active, fixed, or multi-aggregated variable 12467 * values 12468 */ 12469 SCIP_RETCODE SCIPvarGetProbvarBound( 12470 SCIP_VAR** var, /**< pointer to problem variable */ 12471 SCIP_Real* bound, /**< pointer to bound value to transform */ 12472 SCIP_BOUNDTYPE* boundtype /**< pointer to type of bound: lower or upper bound */ 12473 ) 12474 { 12475 assert(var != NULL); 12476 assert(*var != NULL); 12477 assert(bound != NULL); 12478 assert(boundtype != NULL); 12479 12480 SCIPdebugMessage("get probvar bound %g of type %d of variable <%s>\n", *bound, *boundtype, (*var)->name); 12481 12482 switch( SCIPvarGetStatus(*var) ) 12483 { 12484 case SCIP_VARSTATUS_ORIGINAL: 12485 if( (*var)->data.original.transvar == NULL ) 12486 { 12487 SCIPerrorMessage("original variable has no transformed variable attached\n"); 12488 return SCIP_INVALIDDATA; 12489 } 12490 *var = (*var)->data.original.transvar; 12491 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) ); 12492 break; 12493 12494 case SCIP_VARSTATUS_LOOSE: 12495 case SCIP_VARSTATUS_COLUMN: 12496 case SCIP_VARSTATUS_FIXED: 12497 break; 12498 12499 case SCIP_VARSTATUS_MULTAGGR: 12500 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */ 12501 if ( (*var)->data.multaggr.nvars == 1 ) 12502 { 12503 assert( (*var)->data.multaggr.vars != NULL ); 12504 assert( (*var)->data.multaggr.scalars != NULL ); 12505 assert( (*var)->data.multaggr.scalars[0] != 0.0 ); 12506 12507 (*bound) /= (*var)->data.multaggr.scalars[0]; 12508 (*bound) -= (*var)->data.multaggr.constant/(*var)->data.multaggr.scalars[0]; 12509 if ( (*var)->data.multaggr.scalars[0] < 0.0 ) 12510 { 12511 if ( *boundtype == SCIP_BOUNDTYPE_LOWER ) 12512 *boundtype = SCIP_BOUNDTYPE_UPPER; 12513 else 12514 *boundtype = SCIP_BOUNDTYPE_LOWER; 12515 } 12516 *var = (*var)->data.multaggr.vars[0]; 12517 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) ); 12518 } 12519 break; 12520 12521 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = x/a - c/a */ 12522 assert((*var)->data.aggregate.var != NULL); 12523 assert((*var)->data.aggregate.scalar != 0.0); 12524 12525 (*bound) /= (*var)->data.aggregate.scalar; 12526 (*bound) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar; 12527 if( (*var)->data.aggregate.scalar < 0.0 ) 12528 { 12529 if( *boundtype == SCIP_BOUNDTYPE_LOWER ) 12530 *boundtype = SCIP_BOUNDTYPE_UPPER; 12531 else 12532 *boundtype = SCIP_BOUNDTYPE_LOWER; 12533 } 12534 *var = (*var)->data.aggregate.var; 12535 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) ); 12536 break; 12537 12538 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 12539 assert((*var)->negatedvar != NULL); 12540 assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED); 12541 assert((*var)->negatedvar->negatedvar == *var); 12542 (*bound) = (*var)->data.negate.constant - *bound; 12543 if( *boundtype == SCIP_BOUNDTYPE_LOWER ) 12544 *boundtype = SCIP_BOUNDTYPE_UPPER; 12545 else 12546 *boundtype = SCIP_BOUNDTYPE_LOWER; 12547 *var = (*var)->negatedvar; 12548 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) ); 12549 break; 12550 12551 default: 12552 SCIPerrorMessage("unknown variable status\n"); 12553 return SCIP_INVALIDDATA; 12554 } 12555 12556 return SCIP_OKAY; 12557 } 12558 12559 /** transforms given variable and domain hole to the corresponding active, fixed, or multi-aggregated variable 12560 * values 12561 */ 12562 SCIP_RETCODE SCIPvarGetProbvarHole( 12563 SCIP_VAR** var, /**< pointer to problem variable */ 12564 SCIP_Real* left, /**< pointer to left bound of open interval in hole to transform */ 12565 SCIP_Real* right /**< pointer to right bound of open interval in hole to transform */ 12566 ) 12567 { 12568 assert(var != NULL); 12569 assert(*var != NULL); 12570 assert(left != NULL); 12571 assert(right != NULL); 12572 12573 SCIPdebugMessage("get probvar hole (%g,%g) of variable <%s>\n", *left, *right, (*var)->name); 12574 12575 switch( SCIPvarGetStatus(*var) ) 12576 { 12577 case SCIP_VARSTATUS_ORIGINAL: 12578 if( (*var)->data.original.transvar == NULL ) 12579 { 12580 SCIPerrorMessage("original variable has no transformed variable attached\n"); 12581 return SCIP_INVALIDDATA; 12582 } 12583 *var = (*var)->data.original.transvar; 12584 SCIP_CALL( SCIPvarGetProbvarHole(var, left, right) ); 12585 break; 12586 12587 case SCIP_VARSTATUS_LOOSE: 12588 case SCIP_VARSTATUS_COLUMN: 12589 case SCIP_VARSTATUS_FIXED: 12590 case SCIP_VARSTATUS_MULTAGGR: 12591 break; 12592 12593 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = x/a - c/a */ 12594 assert((*var)->data.aggregate.var != NULL); 12595 assert((*var)->data.aggregate.scalar != 0.0); 12596 12597 /* scale back */ 12598 (*left) /= (*var)->data.aggregate.scalar; 12599 (*right) /= (*var)->data.aggregate.scalar; 12600 12601 /* shift back */ 12602 (*left) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar; 12603 (*right) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar; 12604 12605 *var = (*var)->data.aggregate.var; 12606 12607 /* check if the interval bounds have to swapped */ 12608 if( (*var)->data.aggregate.scalar < 0.0 ) 12609 { 12610 SCIP_CALL( SCIPvarGetProbvarHole(var, right, left) ); 12611 } 12612 else 12613 { 12614 SCIP_CALL( SCIPvarGetProbvarHole(var, left, right) ); 12615 } 12616 break; 12617 12618 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 12619 assert((*var)->negatedvar != NULL); 12620 assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED); 12621 assert((*var)->negatedvar->negatedvar == *var); 12622 12623 /* shift and scale back */ 12624 (*left) = (*var)->data.negate.constant - (*left); 12625 (*right) = (*var)->data.negate.constant - (*right); 12626 12627 *var = (*var)->negatedvar; 12628 12629 /* through the negated variable the left and right interval bound have to swapped */ 12630 SCIP_CALL( SCIPvarGetProbvarHole(var, right, left) ); 12631 break; 12632 12633 default: 12634 SCIPerrorMessage("unknown variable status\n"); 12635 return SCIP_INVALIDDATA; 12636 } 12637 12638 return SCIP_OKAY; 12639 } 12640 12641 /** transforms given variable, scalar and constant to the corresponding active, fixed, or 12642 * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed variable, 12643 * "scalar" will be 0.0 and the value of the sum will be stored in "constant"; a multi-aggregation 12644 * with only one active variable (this can happen due to fixings after the multi-aggregation), 12645 * is treated like an aggregation; if the multi-aggregation constant is infinite, "scalar" will be 0.0 12646 */ 12647 SCIP_RETCODE SCIPvarGetProbvarSum( 12648 SCIP_VAR** var, /**< pointer to problem variable x in sum a*x + c */ 12649 SCIP_SET* set, /**< global SCIP settings */ 12650 SCIP_Real* scalar, /**< pointer to scalar a in sum a*x + c */ 12651 SCIP_Real* constant /**< pointer to constant c in sum a*x + c */ 12652 ) 12653 { 12654 assert(var != NULL); 12655 assert(scalar != NULL); 12656 assert(constant != NULL); 12657 12658 while( *var != NULL ) 12659 { 12660 switch( SCIPvarGetStatus(*var) ) 12661 { 12662 case SCIP_VARSTATUS_ORIGINAL: 12663 if( (*var)->data.original.transvar == NULL ) 12664 { 12665 SCIPerrorMessage("original variable has no transformed variable attached\n"); 12666 return SCIP_INVALIDDATA; 12667 } 12668 *var = (*var)->data.original.transvar; 12669 break; 12670 12671 case SCIP_VARSTATUS_LOOSE: 12672 case SCIP_VARSTATUS_COLUMN: 12673 return SCIP_OKAY; 12674 12675 case SCIP_VARSTATUS_FIXED: /* x = c' => a*x + c == (a*c' + c) */ 12676 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) ) 12677 { 12678 if( SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)) ) 12679 { 12680 assert(*scalar != 0.0); 12681 if( (*scalar) * (*var)->glbdom.lb > 0.0 ) 12682 (*constant) = SCIPsetInfinity(set); 12683 else 12684 (*constant) = -SCIPsetInfinity(set); 12685 } 12686 else 12687 (*constant) += *scalar * (*var)->glbdom.lb; 12688 } 12689 #ifndef NDEBUG 12690 else 12691 { 12692 assert(!SCIPsetIsInfinity(set, (*constant)) || !((*scalar) * (*var)->glbdom.lb < 0.0 && 12693 (SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb))))); 12694 assert(!SCIPsetIsInfinity(set, -(*constant)) || !((*scalar) * (*var)->glbdom.lb > 0.0 && 12695 (SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb))))); 12696 } 12697 #endif 12698 *scalar = 0.0; 12699 return SCIP_OKAY; 12700 12701 case SCIP_VARSTATUS_MULTAGGR: 12702 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */ 12703 if ( (*var)->data.multaggr.nvars == 1 ) 12704 { 12705 assert((*var)->data.multaggr.vars != NULL); 12706 assert((*var)->data.multaggr.scalars != NULL); 12707 assert((*var)->data.multaggr.vars[0] != NULL); 12708 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) ) 12709 { 12710 /* the multi-aggregation constant can be infinite, if one of the multi-aggregation variables 12711 * was fixed to +/-infinity; ensure that the constant is set to +/-infinity, too, and the scalar 12712 * is set to 0.0, because the multi-aggregated variable can be seen as fixed, too 12713 */ 12714 if( SCIPsetIsInfinity(set, (*var)->data.multaggr.constant) 12715 || SCIPsetIsInfinity(set, -((*var)->data.multaggr.constant)) ) 12716 { 12717 if( (*scalar) * (*var)->data.multaggr.constant > 0 ) 12718 { 12719 assert(!SCIPsetIsInfinity(set, -(*constant))); 12720 (*constant) = SCIPsetInfinity(set); 12721 } 12722 else 12723 { 12724 assert(!SCIPsetIsInfinity(set, *constant)); 12725 (*constant) = -SCIPsetInfinity(set); 12726 } 12727 (*scalar) = 0.0; 12728 } 12729 else 12730 (*constant) += *scalar * (*var)->data.multaggr.constant; 12731 } 12732 (*scalar) *= (*var)->data.multaggr.scalars[0]; 12733 *var = (*var)->data.multaggr.vars[0]; 12734 break; 12735 } 12736 return SCIP_OKAY; 12737 12738 case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */ 12739 assert((*var)->data.aggregate.var != NULL); 12740 assert(!SCIPsetIsInfinity(set, (*var)->data.aggregate.constant) 12741 && !SCIPsetIsInfinity(set, (*var)->data.aggregate.constant)); 12742 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) ) 12743 (*constant) += *scalar * (*var)->data.aggregate.constant; 12744 (*scalar) *= (*var)->data.aggregate.scalar; 12745 *var = (*var)->data.aggregate.var; 12746 break; 12747 12748 case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */ 12749 assert((*var)->negatedvar != NULL); 12750 assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED); 12751 assert((*var)->negatedvar->negatedvar == *var); 12752 assert(!SCIPsetIsInfinity(set, (*var)->data.negate.constant) 12753 && !SCIPsetIsInfinity(set, (*var)->data.negate.constant)); 12754 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) ) 12755 (*constant) += *scalar * (*var)->data.negate.constant; 12756 (*scalar) *= -1.0; 12757 *var = (*var)->negatedvar; 12758 break; 12759 12760 default: 12761 SCIPerrorMessage("unknown variable status\n"); 12762 SCIPABORT(); 12763 return SCIP_INVALIDDATA; /*lint !e527*/ 12764 } 12765 } 12766 *scalar = 0.0; 12767 12768 return SCIP_OKAY; 12769 } 12770 12771 /** retransforms given variable, scalar and constant to the corresponding original variable, scalar 12772 * and constant, if possible; if the retransformation is impossible, NULL is returned as variable 12773 */ 12774 SCIP_RETCODE SCIPvarGetOrigvarSum( 12775 SCIP_VAR** var, /**< pointer to problem variable x in sum a*x + c */ 12776 SCIP_Real* scalar, /**< pointer to scalar a in sum a*x + c */ 12777 SCIP_Real* constant /**< pointer to constant c in sum a*x + c */ 12778 ) 12779 { 12780 SCIP_VAR* parentvar; 12781 12782 assert(var != NULL); 12783 assert(*var != NULL); 12784 assert(scalar != NULL); 12785 assert(constant != NULL); 12786 12787 while( !SCIPvarIsOriginal(*var) ) 12788 { 12789 /* if the variable has no parent variables, it was generated during solving and has no corresponding original 12790 * var 12791 */ 12792 if( (*var)->nparentvars == 0 ) 12793 { 12794 /* negated variables do not need to have a parent variables, and negated variables can exist in original 12795 * space 12796 */ 12797 if( SCIPvarGetStatus(*var) == SCIP_VARSTATUS_NEGATED && 12798 ((*var)->negatedvar->nparentvars == 0 || (*var)->negatedvar->parentvars[0] != *var) ) 12799 { 12800 *scalar *= -1.0; 12801 *constant -= (*var)->data.negate.constant * (*scalar); 12802 *var = (*var)->negatedvar; 12803 12804 continue; 12805 } 12806 /* if the variables does not have any parent the variables was created during solving and has no original 12807 * counterpart 12808 */ 12809 else 12810 { 12811 *var = NULL; 12812 12813 return SCIP_OKAY; 12814 } 12815 } 12816 12817 /* follow the link to the first parent variable */ 12818 parentvar = (*var)->parentvars[0]; 12819 assert(parentvar != NULL); 12820 12821 switch( SCIPvarGetStatus(parentvar) ) 12822 { 12823 case SCIP_VARSTATUS_ORIGINAL: 12824 break; 12825 12826 case SCIP_VARSTATUS_COLUMN: 12827 case SCIP_VARSTATUS_LOOSE: 12828 case SCIP_VARSTATUS_FIXED: 12829 case SCIP_VARSTATUS_MULTAGGR: 12830 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n"); 12831 return SCIP_INVALIDDATA; 12832 12833 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + b -> y = (x-b)/a, s*y + c = (s/a)*x + c-b*s/a */ 12834 assert(parentvar->data.aggregate.var == *var); 12835 assert(parentvar->data.aggregate.scalar != 0.0); 12836 *scalar /= parentvar->data.aggregate.scalar; 12837 *constant -= parentvar->data.aggregate.constant * (*scalar); 12838 break; 12839 12840 case SCIP_VARSTATUS_NEGATED: /* x = b - y -> y = b - x, s*y + c = -s*x + c+b*s */ 12841 assert(parentvar->negatedvar != NULL); 12842 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED); 12843 assert(parentvar->negatedvar->negatedvar == parentvar); 12844 *scalar *= -1.0; 12845 *constant -= parentvar->data.negate.constant * (*scalar); 12846 break; 12847 12848 default: 12849 SCIPerrorMessage("unknown variable status\n"); 12850 return SCIP_INVALIDDATA; 12851 } 12852 12853 assert( parentvar != NULL ); 12854 *var = parentvar; 12855 } 12856 12857 return SCIP_OKAY; 12858 } 12859 12860 /** returns whether the given variable is the direct counterpart of an original problem variable */ 12861 SCIP_Bool SCIPvarIsTransformedOrigvar( 12862 SCIP_VAR* var /**< problem variable */ 12863 ) 12864 { 12865 SCIP_VAR* parentvar; 12866 assert(var != NULL); 12867 12868 if( !SCIPvarIsTransformed(var) || var->nparentvars < 1 ) 12869 return FALSE; 12870 12871 assert(var->parentvars != NULL); 12872 parentvar = var->parentvars[0]; 12873 assert(parentvar != NULL); 12874 12875 /* we follow the aggregation tree to the root unless an original variable has been found - the first entries in the parentlist are candidates */ 12876 while( parentvar->nparentvars >= 1 && SCIPvarGetStatus(parentvar) != SCIP_VARSTATUS_ORIGINAL ) 12877 parentvar = parentvar->parentvars[0]; 12878 assert( parentvar != NULL ); 12879 12880 return ( SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_ORIGINAL ); 12881 } 12882 12883 /** gets objective value of variable in current SCIP_LP; the value can be different from the objective value stored in 12884 * the variable's own data due to diving, that operate only on the LP without updating the variables 12885 */ 12886 SCIP_Real SCIPvarGetObjLP( 12887 SCIP_VAR* var /**< problem variable */ 12888 ) 12889 { 12890 assert(var != NULL); 12891 12892 /* get bounds of attached variables */ 12893 switch( SCIPvarGetStatus(var) ) 12894 { 12895 case SCIP_VARSTATUS_ORIGINAL: 12896 assert(var->data.original.transvar != NULL); 12897 return SCIPvarGetObjLP(var->data.original.transvar); 12898 12899 case SCIP_VARSTATUS_COLUMN: 12900 assert(var->data.col != NULL); 12901 return SCIPcolGetObj(var->data.col); 12902 12903 case SCIP_VARSTATUS_LOOSE: 12904 case SCIP_VARSTATUS_FIXED: 12905 return var->obj; 12906 12907 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 12908 assert(var->data.aggregate.var != NULL); 12909 return var->data.aggregate.scalar * SCIPvarGetObjLP(var->data.aggregate.var); 12910 12911 case SCIP_VARSTATUS_MULTAGGR: 12912 SCIPerrorMessage("cannot get the objective value of a multiple aggregated variable\n"); 12913 SCIPABORT(); 12914 return 0.0; /*lint !e527*/ 12915 12916 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 12917 assert(var->negatedvar != NULL); 12918 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 12919 assert(var->negatedvar->negatedvar == var); 12920 return -SCIPvarGetObjLP(var->negatedvar); 12921 12922 default: 12923 SCIPerrorMessage("unknown variable status\n"); 12924 SCIPABORT(); 12925 return 0.0; /*lint !e527*/ 12926 } 12927 } 12928 12929 /** gets lower bound of variable in current SCIP_LP; the bound can be different from the bound stored in the variable's own 12930 * data due to diving or conflict analysis, that operate only on the LP without updating the variables 12931 */ 12932 SCIP_Real SCIPvarGetLbLP( 12933 SCIP_VAR* var, /**< problem variable */ 12934 SCIP_SET* set /**< global SCIP settings */ 12935 ) 12936 { 12937 assert(var != NULL); 12938 assert(set != NULL); 12939 assert(var->scip == set->scip); 12940 12941 /* get bounds of attached variables */ 12942 switch( SCIPvarGetStatus(var) ) 12943 { 12944 case SCIP_VARSTATUS_ORIGINAL: 12945 assert(var->data.original.transvar != NULL); 12946 return SCIPvarGetLbLP(var->data.original.transvar, set); 12947 12948 case SCIP_VARSTATUS_COLUMN: 12949 assert(var->data.col != NULL); 12950 return SCIPcolGetLb(var->data.col); 12951 12952 case SCIP_VARSTATUS_LOOSE: 12953 case SCIP_VARSTATUS_FIXED: 12954 return var->locdom.lb; 12955 12956 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 12957 assert(var->data.aggregate.var != NULL); 12958 if( (var->data.aggregate.scalar > 0.0 && SCIPsetIsInfinity(set, -SCIPvarGetLbLP(var->data.aggregate.var, set))) 12959 || (var->data.aggregate.scalar < 0.0 && SCIPsetIsInfinity(set, SCIPvarGetUbLP(var->data.aggregate.var, set))) ) 12960 { 12961 return -SCIPsetInfinity(set); 12962 } 12963 else if( var->data.aggregate.scalar > 0.0 ) 12964 { 12965 /* a > 0 -> get lower bound of y */ 12966 return var->data.aggregate.scalar * SCIPvarGetLbLP(var->data.aggregate.var, set) + var->data.aggregate.constant; 12967 } 12968 else if( var->data.aggregate.scalar < 0.0 ) 12969 { 12970 /* a < 0 -> get upper bound of y */ 12971 return var->data.aggregate.scalar * SCIPvarGetUbLP(var->data.aggregate.var, set) + var->data.aggregate.constant; 12972 } 12973 else 12974 { 12975 SCIPerrorMessage("scalar is zero in aggregation\n"); 12976 SCIPABORT(); 12977 return SCIP_INVALID; /*lint !e527*/ 12978 } 12979 12980 case SCIP_VARSTATUS_MULTAGGR: 12981 /**@todo get the sides of the corresponding linear constraint */ 12982 SCIPerrorMessage("getting the bounds of a multiple aggregated variable is not implemented yet\n"); 12983 SCIPABORT(); 12984 return SCIP_INVALID; /*lint !e527*/ 12985 12986 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 12987 assert(var->negatedvar != NULL); 12988 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 12989 assert(var->negatedvar->negatedvar == var); 12990 return var->data.negate.constant - SCIPvarGetUbLP(var->negatedvar, set); 12991 12992 default: 12993 SCIPerrorMessage("unknown variable status\n"); 12994 SCIPABORT(); 12995 return SCIP_INVALID; /*lint !e527*/ 12996 } 12997 } 12998 12999 /** gets upper bound of variable in current SCIP_LP; the bound can be different from the bound stored in the variable's own 13000 * data due to diving or conflict analysis, that operate only on the LP without updating the variables 13001 */ 13002 SCIP_Real SCIPvarGetUbLP( 13003 SCIP_VAR* var, /**< problem variable */ 13004 SCIP_SET* set /**< global SCIP settings */ 13005 ) 13006 { 13007 assert(var != NULL); 13008 assert(set != NULL); 13009 assert(var->scip == set->scip); 13010 13011 /* get bounds of attached variables */ 13012 switch( SCIPvarGetStatus(var) ) 13013 { 13014 case SCIP_VARSTATUS_ORIGINAL: 13015 assert(var->data.original.transvar != NULL); 13016 return SCIPvarGetUbLP(var->data.original.transvar, set); 13017 13018 case SCIP_VARSTATUS_COLUMN: 13019 assert(var->data.col != NULL); 13020 return SCIPcolGetUb(var->data.col); 13021 13022 case SCIP_VARSTATUS_LOOSE: 13023 case SCIP_VARSTATUS_FIXED: 13024 return var->locdom.ub; 13025 13026 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 13027 assert(var->data.aggregate.var != NULL); 13028 if( (var->data.aggregate.scalar > 0.0 && SCIPsetIsInfinity(set, SCIPvarGetUbLP(var->data.aggregate.var, set))) 13029 || (var->data.aggregate.scalar < 0.0 && SCIPsetIsInfinity(set, -SCIPvarGetLbLP(var->data.aggregate.var, set))) ) 13030 { 13031 return SCIPsetInfinity(set); 13032 } 13033 if( var->data.aggregate.scalar > 0.0 ) 13034 { 13035 /* a > 0 -> get upper bound of y */ 13036 return var->data.aggregate.scalar * SCIPvarGetUbLP(var->data.aggregate.var, set) + var->data.aggregate.constant; 13037 } 13038 else if( var->data.aggregate.scalar < 0.0 ) 13039 { 13040 /* a < 0 -> get lower bound of y */ 13041 return var->data.aggregate.scalar * SCIPvarGetLbLP(var->data.aggregate.var, set) + var->data.aggregate.constant; 13042 } 13043 else 13044 { 13045 SCIPerrorMessage("scalar is zero in aggregation\n"); 13046 SCIPABORT(); 13047 return SCIP_INVALID; /*lint !e527*/ 13048 } 13049 13050 case SCIP_VARSTATUS_MULTAGGR: 13051 SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n"); 13052 SCIPABORT(); 13053 return SCIP_INVALID; /*lint !e527*/ 13054 13055 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 13056 assert(var->negatedvar != NULL); 13057 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 13058 assert(var->negatedvar->negatedvar == var); 13059 return var->data.negate.constant - SCIPvarGetLbLP(var->negatedvar, set); 13060 13061 default: 13062 SCIPerrorMessage("unknown variable status\n"); 13063 SCIPABORT(); 13064 return SCIP_INVALID; /*lint !e527*/ 13065 } 13066 } 13067 13068 /** gets primal LP solution value of variable */ 13069 SCIP_Real SCIPvarGetLPSol_rec( 13070 SCIP_VAR* var /**< problem variable */ 13071 ) 13072 { 13073 assert(var != NULL); 13074 13075 switch( SCIPvarGetStatus(var) ) 13076 { 13077 case SCIP_VARSTATUS_ORIGINAL: 13078 if( var->data.original.transvar == NULL ) 13079 return SCIP_INVALID; 13080 return SCIPvarGetLPSol(var->data.original.transvar); 13081 13082 case SCIP_VARSTATUS_LOOSE: 13083 return SCIPvarGetBestBoundLocal(var); 13084 13085 case SCIP_VARSTATUS_COLUMN: 13086 assert(var->data.col != NULL); 13087 return SCIPcolGetPrimsol(var->data.col); 13088 13089 case SCIP_VARSTATUS_FIXED: 13090 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/ 13091 return var->locdom.lb; 13092 13093 case SCIP_VARSTATUS_AGGREGATED: 13094 { 13095 SCIP_Real lpsolval; 13096 13097 assert(!var->donotaggr); 13098 assert(var->data.aggregate.var != NULL); 13099 lpsolval = SCIPvarGetLPSol(var->data.aggregate.var); 13100 13101 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the 13102 * corresponding infinity value instead of performing an arithmetical transformation (compare method 13103 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is 13104 * (or is called by) a public interface method; instead, we only assert that values are finite 13105 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false 13106 * positives and negatives if the parameter <numerics/infinity> is modified by the user 13107 */ 13108 assert(lpsolval > -SCIP_DEFAULT_INFINITY); 13109 assert(lpsolval < +SCIP_DEFAULT_INFINITY); 13110 return var->data.aggregate.scalar * lpsolval + var->data.aggregate.constant; 13111 } 13112 case SCIP_VARSTATUS_MULTAGGR: 13113 { 13114 SCIP_Real primsol; 13115 int i; 13116 13117 assert(!var->donotmultaggr); 13118 assert(var->data.multaggr.vars != NULL); 13119 assert(var->data.multaggr.scalars != NULL); 13120 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct 13121 * assert(var->data.multaggr.nvars >= 2); 13122 */ 13123 primsol = var->data.multaggr.constant; 13124 for( i = 0; i < var->data.multaggr.nvars; ++i ) 13125 primsol += var->data.multaggr.scalars[i] * SCIPvarGetLPSol(var->data.multaggr.vars[i]); 13126 return primsol; 13127 } 13128 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 13129 assert(var->negatedvar != NULL); 13130 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 13131 assert(var->negatedvar->negatedvar == var); 13132 return var->data.negate.constant - SCIPvarGetLPSol(var->negatedvar); 13133 13134 default: 13135 SCIPerrorMessage("unknown variable status\n"); 13136 SCIPABORT(); 13137 return SCIP_INVALID; /*lint !e527*/ 13138 } 13139 } 13140 13141 /** gets primal NLP solution value of variable */ 13142 SCIP_Real SCIPvarGetNLPSol_rec( 13143 SCIP_VAR* var /**< problem variable */ 13144 ) 13145 { 13146 SCIP_Real solval; 13147 int i; 13148 13149 assert(var != NULL); 13150 13151 /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */ 13152 switch( SCIPvarGetStatus(var) ) 13153 { 13154 case SCIP_VARSTATUS_ORIGINAL: 13155 return SCIPvarGetNLPSol(var->data.original.transvar); 13156 13157 case SCIP_VARSTATUS_LOOSE: 13158 case SCIP_VARSTATUS_COLUMN: 13159 return var->nlpsol; 13160 13161 case SCIP_VARSTATUS_FIXED: 13162 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var)); /*lint !e777*/ 13163 assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var)); /*lint !e777*/ 13164 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var)); /*lint !e777*/ 13165 return SCIPvarGetLbGlobal(var); 13166 13167 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */ 13168 solval = SCIPvarGetNLPSol(var->data.aggregate.var); 13169 return var->data.aggregate.scalar * solval + var->data.aggregate.constant; 13170 13171 case SCIP_VARSTATUS_MULTAGGR: 13172 solval = var->data.multaggr.constant; 13173 for( i = 0; i < var->data.multaggr.nvars; ++i ) 13174 solval += var->data.multaggr.scalars[i] * SCIPvarGetNLPSol(var->data.multaggr.vars[i]); 13175 return solval; 13176 13177 case SCIP_VARSTATUS_NEGATED: 13178 solval = SCIPvarGetNLPSol(var->negatedvar); 13179 return var->data.negate.constant - solval; 13180 13181 default: 13182 SCIPerrorMessage("unknown variable status\n"); 13183 SCIPABORT(); 13184 return SCIP_INVALID; /*lint !e527*/ 13185 } 13186 } 13187 13188 /** gets pseudo solution value of variable at current node */ 13189 static 13190 SCIP_Real SCIPvarGetPseudoSol_rec( 13191 SCIP_VAR* var /**< problem variable */ 13192 ) 13193 { 13194 SCIP_Real pseudosol; 13195 int i; 13196 13197 assert(var != NULL); 13198 13199 switch( SCIPvarGetStatus(var) ) 13200 { 13201 case SCIP_VARSTATUS_ORIGINAL: 13202 if( var->data.original.transvar == NULL ) 13203 return SCIP_INVALID; 13204 return SCIPvarGetPseudoSol(var->data.original.transvar); 13205 13206 case SCIP_VARSTATUS_LOOSE: 13207 case SCIP_VARSTATUS_COLUMN: 13208 return SCIPvarGetBestBoundLocal(var); 13209 13210 case SCIP_VARSTATUS_FIXED: 13211 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/ 13212 return var->locdom.lb; 13213 13214 case SCIP_VARSTATUS_AGGREGATED: 13215 { 13216 SCIP_Real pseudosolval; 13217 assert(!var->donotaggr); 13218 assert(var->data.aggregate.var != NULL); 13219 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the 13220 * corresponding infinity value instead of performing an arithmetical transformation (compare method 13221 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is 13222 * (or is called by) a public interface method; instead, we only assert that values are finite 13223 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false 13224 * positives and negatives if the parameter <numerics/infinity> is modified by the user 13225 */ 13226 pseudosolval = SCIPvarGetPseudoSol(var->data.aggregate.var); 13227 assert(pseudosolval > -SCIP_DEFAULT_INFINITY); 13228 assert(pseudosolval < +SCIP_DEFAULT_INFINITY); 13229 return var->data.aggregate.scalar * pseudosolval + var->data.aggregate.constant; 13230 } 13231 case SCIP_VARSTATUS_MULTAGGR: 13232 assert(!var->donotmultaggr); 13233 assert(var->data.multaggr.vars != NULL); 13234 assert(var->data.multaggr.scalars != NULL); 13235 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct 13236 * assert(var->data.multaggr.nvars >= 2); 13237 */ 13238 pseudosol = var->data.multaggr.constant; 13239 for( i = 0; i < var->data.multaggr.nvars; ++i ) 13240 pseudosol += var->data.multaggr.scalars[i] * SCIPvarGetPseudoSol(var->data.multaggr.vars[i]); 13241 return pseudosol; 13242 13243 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 13244 assert(var->negatedvar != NULL); 13245 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 13246 assert(var->negatedvar->negatedvar == var); 13247 return var->data.negate.constant - SCIPvarGetPseudoSol(var->negatedvar); 13248 13249 default: 13250 SCIPerrorMessage("unknown variable status\n"); 13251 SCIPABORT(); 13252 return SCIP_INVALID; /*lint !e527*/ 13253 } 13254 } 13255 13256 /** gets current LP or pseudo solution value of variable */ 13257 SCIP_Real SCIPvarGetSol( 13258 SCIP_VAR* var, /**< problem variable */ 13259 SCIP_Bool getlpval /**< should the LP solution value be returned? */ 13260 ) 13261 { 13262 if( getlpval ) 13263 return SCIPvarGetLPSol(var); 13264 else 13265 return SCIPvarGetPseudoSol(var); 13266 } 13267 13268 /** remembers the current solution as root solution in the problem variables */ 13269 void SCIPvarStoreRootSol( 13270 SCIP_VAR* var, /**< problem variable */ 13271 SCIP_Bool roothaslp /**< is the root solution from LP? */ 13272 ) 13273 { 13274 assert(var != NULL); 13275 13276 var->rootsol = SCIPvarGetSol(var, roothaslp); 13277 } 13278 13279 /** updates the current solution as best root solution of the given variable if it is better */ 13280 void SCIPvarUpdateBestRootSol( 13281 SCIP_VAR* var, /**< problem variable */ 13282 SCIP_SET* set, /**< global SCIP settings */ 13283 SCIP_Real rootsol, /**< root solution value */ 13284 SCIP_Real rootredcost, /**< root reduced cost */ 13285 SCIP_Real rootlpobjval /**< objective value of the root LP */ 13286 ) 13287 { 13288 assert(var != NULL); 13289 assert(set != NULL); 13290 assert(var->scip == set->scip); 13291 13292 /* if reduced cost are zero nothing to update */ 13293 if( SCIPsetIsDualfeasZero(set, rootredcost) ) 13294 return; 13295 13296 /* check if we have already a best combination stored */ 13297 if( !SCIPsetIsDualfeasZero(set, var->bestrootredcost) ) 13298 { 13299 SCIP_Real currcutoffbound; 13300 SCIP_Real cutoffbound; 13301 SCIP_Real bound; 13302 13303 /* compute the cutoff bound which would improve the corresponding bound with the current stored root solution, 13304 * root reduced cost, and root LP objective value combination 13305 */ 13306 if( var->bestrootredcost > 0.0 ) 13307 bound = SCIPvarGetUbGlobal(var); 13308 else 13309 bound = SCIPvarGetLbGlobal(var); 13310 13311 currcutoffbound = (bound - var->bestrootsol) * var->bestrootredcost + var->bestrootlpobjval; 13312 13313 /* compute the cutoff bound which would improve the corresponding bound with new root solution, root reduced 13314 * cost, and root LP objective value combination 13315 */ 13316 if( rootredcost > 0.0 ) 13317 bound = SCIPvarGetUbGlobal(var); 13318 else 13319 bound = SCIPvarGetLbGlobal(var); 13320 13321 cutoffbound = (bound - rootsol) * rootredcost + rootlpobjval; 13322 13323 /* check if an improving root solution, root reduced cost, and root LP objective value is at hand */ 13324 if( cutoffbound > currcutoffbound ) 13325 { 13326 SCIPsetDebugMsg(set, "-> <%s> update potential cutoff bound <%g> -> <%g>\n", 13327 SCIPvarGetName(var), currcutoffbound, cutoffbound); 13328 13329 var->bestrootsol = rootsol; 13330 var->bestrootredcost = rootredcost; 13331 var->bestrootlpobjval = rootlpobjval; 13332 } 13333 } 13334 else 13335 { 13336 SCIPsetDebugMsg(set, "-> <%s> initialize best root reduced cost information\n", SCIPvarGetName(var)); 13337 SCIPsetDebugMsg(set, " -> rootsol <%g>\n", rootsol); 13338 SCIPsetDebugMsg(set, " -> rootredcost <%g>\n", rootredcost); 13339 SCIPsetDebugMsg(set, " -> rootlpobjval <%g>\n", rootlpobjval); 13340 13341 var->bestrootsol = rootsol; 13342 var->bestrootredcost = rootredcost; 13343 var->bestrootlpobjval = rootlpobjval; 13344 } 13345 } 13346 13347 /** returns the solution of the variable in the last root node's relaxation, if the root relaxation is not yet 13348 * completely solved, zero is returned 13349 */ 13350 SCIP_Real SCIPvarGetRootSol( 13351 SCIP_VAR* var /**< problem variable */ 13352 ) 13353 { 13354 SCIP_Real rootsol; 13355 int i; 13356 13357 assert(var != NULL); 13358 13359 switch( SCIPvarGetStatus(var) ) 13360 { 13361 case SCIP_VARSTATUS_ORIGINAL: 13362 if( var->data.original.transvar == NULL ) 13363 return 0.0; 13364 return SCIPvarGetRootSol(var->data.original.transvar); 13365 13366 case SCIP_VARSTATUS_LOOSE: 13367 case SCIP_VARSTATUS_COLUMN: 13368 return var->rootsol; 13369 13370 case SCIP_VARSTATUS_FIXED: 13371 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/ 13372 return var->locdom.lb; 13373 13374 case SCIP_VARSTATUS_AGGREGATED: 13375 assert(!var->donotaggr); 13376 assert(var->data.aggregate.var != NULL); 13377 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the 13378 * corresponding infinity value instead of performing an arithmetical transformation (compare method 13379 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is 13380 * (or is called by) a public interface method; instead, we only assert that values are finite 13381 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false 13382 * positives and negatives if the parameter <numerics/infinity> is modified by the user 13383 */ 13384 assert(SCIPvarGetRootSol(var->data.aggregate.var) > -SCIP_DEFAULT_INFINITY); 13385 assert(SCIPvarGetRootSol(var->data.aggregate.var) < +SCIP_DEFAULT_INFINITY); 13386 return var->data.aggregate.scalar * SCIPvarGetRootSol(var->data.aggregate.var) + var->data.aggregate.constant; 13387 13388 case SCIP_VARSTATUS_MULTAGGR: 13389 assert(!var->donotmultaggr); 13390 assert(var->data.multaggr.vars != NULL); 13391 assert(var->data.multaggr.scalars != NULL); 13392 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct 13393 * assert(var->data.multaggr.nvars >= 2); 13394 */ 13395 rootsol = var->data.multaggr.constant; 13396 for( i = 0; i < var->data.multaggr.nvars; ++i ) 13397 rootsol += var->data.multaggr.scalars[i] * SCIPvarGetRootSol(var->data.multaggr.vars[i]); 13398 return rootsol; 13399 13400 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 13401 assert(var->negatedvar != NULL); 13402 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 13403 assert(var->negatedvar->negatedvar == var); 13404 return var->data.negate.constant - SCIPvarGetRootSol(var->negatedvar); 13405 13406 default: 13407 SCIPerrorMessage("unknown variable status\n"); 13408 SCIPABORT(); 13409 return SCIP_INVALID; /*lint !e527*/ 13410 } 13411 } 13412 13413 /** returns for given variable the reduced cost */ 13414 static 13415 SCIP_Real getImplVarRedcost( 13416 SCIP_VAR* var, /**< problem variable */ 13417 SCIP_SET* set, /**< global SCIP settings */ 13418 SCIP_Bool varfixing, /**< FALSE if for x == 0, TRUE for x == 1 */ 13419 SCIP_STAT* stat, /**< problem statistics */ 13420 SCIP_LP* lp /**< current LP data */ 13421 ) 13422 { 13423 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 13424 { 13425 SCIP_COL* col; 13426 SCIP_Real primsol; 13427 SCIP_BASESTAT basestat; 13428 SCIP_Bool lpissolbasic; 13429 13430 col = SCIPvarGetCol(var); 13431 assert(col != NULL); 13432 13433 basestat = SCIPcolGetBasisStatus(col); 13434 lpissolbasic = SCIPlpIsSolBasic(lp); 13435 primsol = SCIPcolGetPrimsol(col); 13436 13437 if( (lpissolbasic && (basestat == SCIP_BASESTAT_LOWER || basestat == SCIP_BASESTAT_UPPER)) || 13438 (!lpissolbasic && (SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol) || SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol))) ) 13439 { 13440 SCIP_Real redcost = SCIPcolGetRedcost(col, stat, lp); 13441 13442 assert(((!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol)) || 13443 (lpissolbasic && basestat == SCIP_BASESTAT_LOWER)) ? (!SCIPsetIsDualfeasNegative(set, redcost) || 13444 SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var))) : TRUE); 13445 assert(((!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol)) || 13446 (lpissolbasic && basestat == SCIP_BASESTAT_UPPER)) ? (!SCIPsetIsDualfeasPositive(set, redcost) || 13447 SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var))) : TRUE); 13448 13449 if( (varfixing && ((lpissolbasic && basestat == SCIP_BASESTAT_LOWER) || 13450 (!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol)))) || 13451 (!varfixing && ((lpissolbasic && basestat == SCIP_BASESTAT_UPPER) || 13452 (!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol)))) ) 13453 return redcost; 13454 else 13455 return 0.0; 13456 } 13457 13458 return 0.0; 13459 } 13460 13461 return 0.0; 13462 } 13463 13464 #define MAX_CLIQUELENGTH 50 13465 /** returns for the given binary variable the reduced cost which are given by the variable itself and its implication if 13466 * the binary variable is fixed to the given value 13467 */ 13468 SCIP_Real SCIPvarGetImplRedcost( 13469 SCIP_VAR* var, /**< problem variable */ 13470 SCIP_SET* set, /**< global SCIP settings */ 13471 SCIP_Bool varfixing, /**< FALSE if for x == 0, TRUE for x == 1 */ 13472 SCIP_STAT* stat, /**< problem statistics */ 13473 SCIP_PROB* prob, /**< transformed problem, or NULL */ 13474 SCIP_LP* lp /**< current LP data */ 13475 ) 13476 { 13477 SCIP_Real implredcost; 13478 int ncliques; 13479 int nvars; 13480 13481 assert(SCIPvarIsBinary(var)); 13482 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 13483 13484 /* get reduced cost of given variable */ 13485 implredcost = getImplVarRedcost(var, set, varfixing, stat, lp); 13486 13487 #ifdef SCIP_MORE_DEBUG 13488 SCIPsetDebugMsg(set, "variable <%s> itself has reduced cost of %g\n", SCIPvarGetName(var), implredcost); 13489 #endif 13490 13491 /* the following algorithm is expensive */ 13492 ncliques = SCIPvarGetNCliques(var, varfixing); 13493 13494 if( ncliques > 0 ) 13495 { 13496 SCIP_CLIQUE** cliques; 13497 SCIP_CLIQUE* clique; 13498 SCIP_VAR** clqvars; 13499 SCIP_VAR** probvars; 13500 SCIP_VAR* clqvar; 13501 SCIP_Bool* clqvalues; 13502 int* entries; 13503 int* ids; 13504 SCIP_Real redcost; 13505 SCIP_Bool cleanedup; 13506 int nclqvars; 13507 int nentries; 13508 int nids; 13509 int id; 13510 int c; 13511 int v; 13512 13513 assert(prob != NULL); 13514 assert(SCIPprobIsTransformed(prob)); 13515 13516 nentries = SCIPprobGetNVars(prob) - SCIPprobGetNContVars(prob) + 1; 13517 13518 SCIP_CALL_ABORT( SCIPsetAllocBufferArray(set, &ids, nentries) ); 13519 nids = 0; 13520 SCIP_CALL_ABORT( SCIPsetAllocCleanBufferArray(set, &entries, nentries) ); 13521 13522 cliques = SCIPvarGetCliques(var, varfixing); 13523 assert(cliques != NULL); 13524 13525 for( c = ncliques - 1; c >= 0; --c ) 13526 { 13527 clique = cliques[c]; 13528 assert(clique != NULL); 13529 nclqvars = SCIPcliqueGetNVars(clique); 13530 assert(nclqvars > 0); 13531 13532 if( nclqvars > MAX_CLIQUELENGTH ) 13533 continue; 13534 13535 clqvars = SCIPcliqueGetVars(clique); 13536 clqvalues = SCIPcliqueGetValues(clique); 13537 assert(clqvars != NULL); 13538 assert(clqvalues != NULL); 13539 13540 cleanedup = SCIPcliqueIsCleanedUp(clique); 13541 13542 for( v = nclqvars - 1; v >= 0; --v ) 13543 { 13544 clqvar = clqvars[v]; 13545 assert(clqvar != NULL); 13546 13547 /* ignore binary variable which are fixed */ 13548 if( clqvar != var && (cleanedup || SCIPvarIsActive(clqvar)) && 13549 (SCIPvarGetLbLocal(clqvar) < 0.5 && SCIPvarGetUbLocal(clqvar) > 0.5) ) 13550 { 13551 int probindex = SCIPvarGetProbindex(clqvar) + 1; 13552 assert(0 < probindex && probindex < nentries); 13553 13554 #if 0 13555 /* check that the variable was not yet visited or does not appear with two contradicting implications, -> 13556 * can appear since there is no guarantee that all these infeasible bounds were found 13557 */ 13558 assert(!entries[probindex] || entries[probindex] == (clqvalues[v] ? probindex : -probindex)); 13559 #endif 13560 if( entries[probindex] == 0 ) 13561 { 13562 ids[nids] = probindex; 13563 ++nids; 13564 13565 /* mark variable as visited */ 13566 entries[probindex] = (clqvalues[v] ? probindex : -probindex); 13567 } 13568 } 13569 } 13570 } 13571 13572 probvars = SCIPprobGetVars(prob); 13573 assert(probvars != NULL); 13574 13575 /* add all implied reduced cost */ 13576 for( v = nids - 1; v >= 0; --v ) 13577 { 13578 id = ids[v]; 13579 assert(0 < id && id < nentries); 13580 assert(entries[id] != 0); 13581 assert(probvars[id - 1] != NULL); 13582 assert(SCIPvarIsActive(probvars[id - 1])); 13583 assert(SCIPvarIsBinary(probvars[id - 1])); 13584 assert(SCIPvarGetLbLocal(probvars[id - 1]) < 0.5 && SCIPvarGetUbLocal(probvars[id - 1]) > 0.5); 13585 13586 if( (entries[id] > 0) != varfixing ) 13587 redcost = getImplVarRedcost(probvars[id - 1], set, (entries[id] < 0), stat, lp); 13588 else 13589 redcost = -getImplVarRedcost(probvars[id - 1], set, (entries[id] < 0), stat, lp); 13590 13591 if( (varfixing && SCIPsetIsDualfeasPositive(set, redcost)) || (!varfixing && SCIPsetIsDualfeasNegative(set, redcost)) ) 13592 implredcost += redcost; 13593 13594 /* reset entries clear buffer array */ 13595 entries[id] = 0; 13596 } 13597 13598 SCIPsetFreeCleanBufferArray(set, &entries); 13599 SCIPsetFreeBufferArray(set, &ids); 13600 } 13601 13602 #ifdef SCIP_MORE_DEBUG 13603 SCIPsetDebugMsg(set, "variable <%s> incl. cliques (%d) has implied reduced cost of %g\n", SCIPvarGetName(var), ncliques, 13604 implredcost); 13605 #endif 13606 13607 /* collect non-binary implication information */ 13608 nvars = SCIPimplicsGetNImpls(var->implics, varfixing); 13609 13610 if( nvars > 0 ) 13611 { 13612 SCIP_VAR** vars; 13613 SCIP_VAR* implvar; 13614 SCIP_COL* col; 13615 SCIP_Real* bounds; 13616 SCIP_BOUNDTYPE* boundtypes; 13617 SCIP_Real redcost; 13618 SCIP_Real lb; 13619 SCIP_Real ub; 13620 SCIP_Bool lpissolbasic; 13621 int v; 13622 13623 vars = SCIPimplicsGetVars(var->implics, varfixing); 13624 boundtypes = SCIPimplicsGetTypes(var->implics, varfixing); 13625 bounds = SCIPimplicsGetBounds(var->implics, varfixing); 13626 lpissolbasic = SCIPlpIsSolBasic(lp); 13627 13628 for( v = nvars - 1; v >= 0; --v ) 13629 { 13630 implvar = vars[v]; 13631 assert(implvar != NULL); 13632 13633 lb = SCIPvarGetLbLocal(implvar); 13634 ub = SCIPvarGetUbLocal(implvar); 13635 13636 /* ignore binary variable which are fixed or not of column status */ 13637 if( SCIPvarGetStatus(implvar) != SCIP_VARSTATUS_COLUMN || SCIPsetIsFeasEQ(set, lb, ub) ) 13638 continue; 13639 13640 col = SCIPvarGetCol(implvar); 13641 assert(col != NULL); 13642 redcost = 0.0; 13643 13644 /* solved lp with basis information or not? */ 13645 if( lpissolbasic ) 13646 { 13647 SCIP_BASESTAT basestat = SCIPcolGetBasisStatus(col); 13648 13649 /* check if the implication is not not yet applied */ 13650 if( basestat == SCIP_BASESTAT_LOWER && boundtypes[v] == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, bounds[v], lb) ) 13651 { 13652 redcost = SCIPcolGetRedcost(col, stat, lp); 13653 assert(!SCIPsetIsDualfeasNegative(set, redcost)); 13654 13655 if( !varfixing ) 13656 redcost *= (lb - bounds[v]); 13657 else 13658 redcost *= (bounds[v] - lb); 13659 } 13660 else if( basestat == SCIP_BASESTAT_UPPER && boundtypes[v] == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, bounds[v], ub) ) 13661 { 13662 redcost = SCIPcolGetRedcost(col, stat, lp); 13663 assert(!SCIPsetIsDualfeasPositive(set, redcost)); 13664 13665 if( varfixing ) 13666 redcost *= (bounds[v] - ub); 13667 else 13668 redcost *= (ub - bounds[v]); 13669 } 13670 } 13671 else 13672 { 13673 SCIP_Real primsol = SCIPcolGetPrimsol(col); 13674 13675 /* check if the implication is not not yet applied */ 13676 if( boundtypes[v] == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasEQ(set, lb, primsol) && SCIPsetIsFeasGT(set, bounds[v], lb) ) 13677 { 13678 redcost = SCIPcolGetRedcost(col, stat, lp); 13679 assert(!SCIPsetIsDualfeasNegative(set, redcost)); 13680 13681 if( varfixing ) 13682 redcost *= (lb - bounds[v]); 13683 else 13684 redcost *= (bounds[v] - lb); 13685 } 13686 else if( boundtypes[v] == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasEQ(set, ub, primsol) && SCIPsetIsFeasLT(set, bounds[v], ub) ) 13687 { 13688 redcost = SCIPcolGetRedcost(col, stat, lp); 13689 assert(!SCIPsetIsDualfeasPositive(set, redcost)); 13690 13691 if( varfixing ) 13692 redcost *= (bounds[v] - ub); 13693 else 13694 redcost *= (ub - bounds[v]); 13695 } 13696 } 13697 13698 /* improve implied reduced cost */ 13699 if( (varfixing && SCIPsetIsDualfeasPositive(set, redcost)) || (!varfixing && SCIPsetIsDualfeasNegative(set, redcost)) ) 13700 implredcost += redcost; 13701 } 13702 } 13703 13704 #ifdef SCIP_MORE_DEBUG 13705 SCIPsetDebugMsg(set, "variable <%s> incl. cliques (%d) and implications (%d) has implied reduced cost of %g\n", 13706 SCIPvarGetName(var), ncliques, nvars, implredcost); 13707 #endif 13708 13709 return implredcost; 13710 } 13711 13712 /** returns the best solution (w.r.t. root reduced cost propagation) of the variable in the root node's relaxation, if 13713 * the root relaxation is not yet completely solved, zero is returned 13714 */ 13715 SCIP_Real SCIPvarGetBestRootSol( 13716 SCIP_VAR* var /**< problem variable */ 13717 ) 13718 { 13719 SCIP_Real rootsol; 13720 int i; 13721 13722 assert(var != NULL); 13723 13724 switch( SCIPvarGetStatus(var) ) 13725 { 13726 case SCIP_VARSTATUS_ORIGINAL: 13727 if( var->data.original.transvar == NULL ) 13728 return 0.0; 13729 return SCIPvarGetBestRootSol(var->data.original.transvar); 13730 13731 case SCIP_VARSTATUS_LOOSE: 13732 case SCIP_VARSTATUS_COLUMN: 13733 return var->bestrootsol; 13734 13735 case SCIP_VARSTATUS_FIXED: 13736 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/ 13737 return var->locdom.lb; 13738 13739 case SCIP_VARSTATUS_AGGREGATED: 13740 assert(!var->donotaggr); 13741 assert(var->data.aggregate.var != NULL); 13742 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the 13743 * corresponding infinity value instead of performing an arithmetical transformation (compare method 13744 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is 13745 * (or is called by) a public interface method; instead, we only assert that values are finite 13746 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false 13747 * positives and negatives if the parameter <numerics/infinity> is modified by the user 13748 */ 13749 assert(SCIPvarGetBestRootSol(var->data.aggregate.var) > -SCIP_DEFAULT_INFINITY); 13750 assert(SCIPvarGetBestRootSol(var->data.aggregate.var) < +SCIP_DEFAULT_INFINITY); 13751 return var->data.aggregate.scalar * SCIPvarGetBestRootSol(var->data.aggregate.var) + var->data.aggregate.constant; 13752 13753 case SCIP_VARSTATUS_MULTAGGR: 13754 assert(!var->donotmultaggr); 13755 assert(var->data.multaggr.vars != NULL); 13756 assert(var->data.multaggr.scalars != NULL); 13757 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct 13758 * assert(var->data.multaggr.nvars >= 2); 13759 */ 13760 rootsol = var->data.multaggr.constant; 13761 for( i = 0; i < var->data.multaggr.nvars; ++i ) 13762 rootsol += var->data.multaggr.scalars[i] * SCIPvarGetBestRootSol(var->data.multaggr.vars[i]); 13763 return rootsol; 13764 13765 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 13766 assert(var->negatedvar != NULL); 13767 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 13768 assert(var->negatedvar->negatedvar == var); 13769 return var->data.negate.constant - SCIPvarGetBestRootSol(var->negatedvar); 13770 13771 default: 13772 SCIPerrorMessage("unknown variable status\n"); 13773 SCIPABORT(); 13774 return 0.0; /*lint !e527*/ 13775 } 13776 } 13777 13778 /** returns the best reduced costs (w.r.t. root reduced cost propagation) of the variable in the root node's relaxation, 13779 * if the root relaxation is not yet completely solved, or the variable was no column of the root LP, SCIP_INVALID is 13780 * returned 13781 */ 13782 SCIP_Real SCIPvarGetBestRootRedcost( 13783 SCIP_VAR* var /**< problem variable */ 13784 ) 13785 { 13786 assert(var != NULL); 13787 13788 switch( SCIPvarGetStatus(var) ) 13789 { 13790 case SCIP_VARSTATUS_ORIGINAL: 13791 if( var->data.original.transvar == NULL ) 13792 return SCIP_INVALID; 13793 return SCIPvarGetBestRootRedcost(var->data.original.transvar); 13794 13795 case SCIP_VARSTATUS_LOOSE: 13796 case SCIP_VARSTATUS_COLUMN: 13797 return var->bestrootredcost; 13798 13799 case SCIP_VARSTATUS_FIXED: 13800 case SCIP_VARSTATUS_AGGREGATED: 13801 case SCIP_VARSTATUS_MULTAGGR: 13802 case SCIP_VARSTATUS_NEGATED: 13803 return 0.0; 13804 13805 default: 13806 SCIPerrorMessage("unknown variable status\n"); 13807 SCIPABORT(); 13808 return 0.0; /*lint !e527*/ 13809 } 13810 } 13811 13812 /** returns the best objective value (w.r.t. root reduced cost propagation) of the root LP which belongs the root 13813 * reduced cost which is accessible via SCIPvarGetRootRedcost() or the variable was no column of the root LP, 13814 * SCIP_INVALID is returned 13815 */ 13816 SCIP_Real SCIPvarGetBestRootLPObjval( 13817 SCIP_VAR* var /**< problem variable */ 13818 ) 13819 { 13820 assert(var != NULL); 13821 13822 switch( SCIPvarGetStatus(var) ) 13823 { 13824 case SCIP_VARSTATUS_ORIGINAL: 13825 if( var->data.original.transvar == NULL ) 13826 return SCIP_INVALID; 13827 return SCIPvarGetBestRootLPObjval(var->data.original.transvar); 13828 13829 case SCIP_VARSTATUS_LOOSE: 13830 case SCIP_VARSTATUS_COLUMN: 13831 return var->bestrootlpobjval; 13832 13833 case SCIP_VARSTATUS_FIXED: 13834 case SCIP_VARSTATUS_AGGREGATED: 13835 case SCIP_VARSTATUS_MULTAGGR: 13836 case SCIP_VARSTATUS_NEGATED: 13837 return SCIP_INVALID; 13838 13839 default: 13840 SCIPerrorMessage("unknown variable status\n"); 13841 SCIPABORT(); 13842 return SCIP_INVALID; /*lint !e527*/ 13843 } 13844 } 13845 13846 /** set the given solution as the best root solution w.r.t. root reduced cost propagation in the variables */ 13847 void SCIPvarSetBestRootSol( 13848 SCIP_VAR* var, /**< problem variable */ 13849 SCIP_Real rootsol, /**< root solution value */ 13850 SCIP_Real rootredcost, /**< root reduced cost */ 13851 SCIP_Real rootlpobjval /**< objective value of the root LP */ 13852 ) 13853 { 13854 assert(var != NULL); 13855 13856 var->bestrootsol = rootsol; 13857 var->bestrootredcost = rootredcost; 13858 var->bestrootlpobjval = rootlpobjval; 13859 } 13860 13861 /** stores the solution value as relaxation solution in the problem variable */ 13862 SCIP_RETCODE SCIPvarSetRelaxSol( 13863 SCIP_VAR* var, /**< problem variable */ 13864 SCIP_SET* set, /**< global SCIP settings */ 13865 SCIP_RELAXATION* relaxation, /**< global relaxation data */ 13866 SCIP_Real solval, /**< solution value in the current relaxation solution */ 13867 SCIP_Bool updateobj /**< should the objective value be updated? */ 13868 ) 13869 { 13870 assert(var != NULL); 13871 assert(relaxation != NULL); 13872 assert(set != NULL); 13873 assert(var->scip == set->scip); 13874 13875 /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */ 13876 switch( SCIPvarGetStatus(var) ) 13877 { 13878 case SCIP_VARSTATUS_ORIGINAL: 13879 SCIP_CALL( SCIPvarSetRelaxSol(var->data.original.transvar, set, relaxation, solval, updateobj) ); 13880 break; 13881 13882 case SCIP_VARSTATUS_LOOSE: 13883 case SCIP_VARSTATUS_COLUMN: 13884 if( updateobj ) 13885 SCIPrelaxationSolObjAdd(relaxation, var->obj * (solval - var->relaxsol)); 13886 var->relaxsol = solval; 13887 break; 13888 13889 case SCIP_VARSTATUS_FIXED: 13890 if( !SCIPsetIsEQ(set, solval, var->glbdom.lb) ) 13891 { 13892 SCIPerrorMessage("cannot set relaxation solution value for variable <%s> fixed to %.15g to different value %.15g\n", 13893 SCIPvarGetName(var), var->glbdom.lb, solval); 13894 return SCIP_INVALIDDATA; 13895 } 13896 break; 13897 13898 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */ 13899 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar)); 13900 SCIP_CALL( SCIPvarSetRelaxSol(var->data.aggregate.var, set, relaxation, 13901 (solval - var->data.aggregate.constant)/var->data.aggregate.scalar, updateobj) ); 13902 break; 13903 case SCIP_VARSTATUS_MULTAGGR: 13904 SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n"); 13905 return SCIP_INVALIDDATA; 13906 13907 case SCIP_VARSTATUS_NEGATED: 13908 SCIP_CALL( SCIPvarSetRelaxSol(var->negatedvar, set, relaxation, var->data.negate.constant - solval, updateobj) ); 13909 break; 13910 13911 default: 13912 SCIPerrorMessage("unknown variable status\n"); 13913 return SCIP_INVALIDDATA; 13914 } 13915 13916 return SCIP_OKAY; 13917 } 13918 13919 /** returns the solution value of the problem variable in the relaxation solution 13920 * 13921 * @todo Inline this function - similar to SCIPvarGetLPSol_rec. 13922 */ 13923 SCIP_Real SCIPvarGetRelaxSol( 13924 SCIP_VAR* var, /**< problem variable */ 13925 SCIP_SET* set /**< global SCIP settings */ 13926 ) 13927 { 13928 SCIP_Real solvalsum; 13929 SCIP_Real solval; 13930 int i; 13931 13932 assert(var != NULL); 13933 assert(set != NULL); 13934 assert(var->scip == set->scip); 13935 13936 /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */ 13937 switch( SCIPvarGetStatus(var) ) 13938 { 13939 case SCIP_VARSTATUS_ORIGINAL: 13940 return SCIPvarGetRelaxSol(var->data.original.transvar, set); 13941 13942 case SCIP_VARSTATUS_LOOSE: 13943 case SCIP_VARSTATUS_COLUMN: 13944 return var->relaxsol; 13945 13946 case SCIP_VARSTATUS_FIXED: 13947 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var)); /*lint !e777*/ 13948 assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var)); /*lint !e777*/ 13949 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var)); /*lint !e777*/ 13950 return SCIPvarGetLbGlobal(var); 13951 13952 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */ 13953 solval = SCIPvarGetRelaxSol(var->data.aggregate.var, set); 13954 if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) ) 13955 { 13956 if( var->data.aggregate.scalar * solval > 0.0 ) 13957 return SCIPsetInfinity(set); 13958 if( var->data.aggregate.scalar * solval < 0.0 ) 13959 return -SCIPsetInfinity(set); 13960 } 13961 return var->data.aggregate.scalar * solval + var->data.aggregate.constant; 13962 13963 case SCIP_VARSTATUS_MULTAGGR: 13964 solvalsum = var->data.multaggr.constant; 13965 for( i = 0; i < var->data.multaggr.nvars; ++i ) 13966 { 13967 solval = SCIPvarGetRelaxSol(var->data.multaggr.vars[i], set); 13968 if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) ) 13969 { 13970 if( var->data.multaggr.scalars[i] * solval > 0.0 ) 13971 return SCIPsetInfinity(set); 13972 if( var->data.multaggr.scalars[i] * solval < 0.0 ) 13973 return -SCIPsetInfinity(set); 13974 } 13975 solvalsum += var->data.multaggr.scalars[i] * solval; 13976 } 13977 return solvalsum; 13978 13979 case SCIP_VARSTATUS_NEGATED: 13980 solval = SCIPvarGetRelaxSol(var->negatedvar, set); 13981 if( SCIPsetIsInfinity(set, solval) ) 13982 return -SCIPsetInfinity(set); 13983 if( SCIPsetIsInfinity(set, -solval) ) 13984 return SCIPsetInfinity(set); 13985 return var->data.negate.constant - solval; 13986 13987 default: 13988 SCIPerrorMessage("unknown variable status\n"); 13989 SCIPABORT(); 13990 return SCIP_INVALID; /*lint !e527*/ 13991 } 13992 } 13993 13994 /** returns the solution value of the transformed problem variable in the relaxation solution */ 13995 SCIP_Real SCIPvarGetRelaxSolTransVar( 13996 SCIP_VAR* var /**< problem variable */ 13997 ) 13998 { 13999 assert(var != NULL); 14000 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); 14001 14002 return var->relaxsol; 14003 } 14004 14005 /** stores the solution value as NLP solution in the problem variable */ 14006 SCIP_RETCODE SCIPvarSetNLPSol( 14007 SCIP_VAR* var, /**< problem variable */ 14008 SCIP_SET* set, /**< global SCIP settings */ 14009 SCIP_Real solval /**< solution value in the current NLP solution */ 14010 ) 14011 { 14012 assert(var != NULL); 14013 assert(set != NULL); 14014 assert(var->scip == set->scip); 14015 14016 /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */ 14017 switch( SCIPvarGetStatus(var) ) 14018 { 14019 case SCIP_VARSTATUS_ORIGINAL: 14020 SCIP_CALL( SCIPvarSetNLPSol(var->data.original.transvar, set, solval) ); 14021 break; 14022 14023 case SCIP_VARSTATUS_LOOSE: 14024 case SCIP_VARSTATUS_COLUMN: 14025 var->nlpsol = solval; 14026 break; 14027 14028 case SCIP_VARSTATUS_FIXED: 14029 if( !SCIPsetIsEQ(set, solval, var->glbdom.lb) ) 14030 { 14031 SCIPerrorMessage("cannot set NLP solution value for variable <%s> fixed to %.15g to different value %.15g\n", 14032 SCIPvarGetName(var), var->glbdom.lb, solval); 14033 SCIPABORT(); 14034 return SCIP_INVALIDCALL; /*lint !e527*/ 14035 } 14036 break; 14037 14038 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */ 14039 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar)); 14040 SCIP_CALL( SCIPvarSetNLPSol(var->data.aggregate.var, set, (solval - var->data.aggregate.constant)/var->data.aggregate.scalar) ); 14041 break; 14042 14043 case SCIP_VARSTATUS_MULTAGGR: 14044 SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n"); 14045 SCIPABORT(); 14046 return SCIP_INVALIDCALL; /*lint !e527*/ 14047 14048 case SCIP_VARSTATUS_NEGATED: 14049 SCIP_CALL( SCIPvarSetNLPSol(var->negatedvar, set, var->data.negate.constant - solval) ); 14050 break; 14051 14052 default: 14053 SCIPerrorMessage("unknown variable status\n"); 14054 SCIPABORT(); 14055 return SCIP_ERROR; /*lint !e527*/ 14056 } 14057 14058 return SCIP_OKAY; 14059 } 14060 14061 /** returns a weighted average solution value of the variable in all feasible primal solutions found so far */ 14062 SCIP_Real SCIPvarGetAvgSol( 14063 SCIP_VAR* var /**< problem variable */ 14064 ) 14065 { 14066 SCIP_Real avgsol; 14067 int i; 14068 14069 assert(var != NULL); 14070 14071 switch( SCIPvarGetStatus(var) ) 14072 { 14073 case SCIP_VARSTATUS_ORIGINAL: 14074 if( var->data.original.transvar == NULL ) 14075 return 0.0; 14076 return SCIPvarGetAvgSol(var->data.original.transvar); 14077 14078 case SCIP_VARSTATUS_LOOSE: 14079 case SCIP_VARSTATUS_COLUMN: 14080 avgsol = var->primsolavg; 14081 avgsol = MAX(avgsol, var->glbdom.lb); 14082 avgsol = MIN(avgsol, var->glbdom.ub); 14083 return avgsol; 14084 14085 case SCIP_VARSTATUS_FIXED: 14086 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/ 14087 return var->locdom.lb; 14088 14089 case SCIP_VARSTATUS_AGGREGATED: 14090 assert(!var->donotaggr); 14091 assert(var->data.aggregate.var != NULL); 14092 return var->data.aggregate.scalar * SCIPvarGetAvgSol(var->data.aggregate.var) 14093 + var->data.aggregate.constant; 14094 14095 case SCIP_VARSTATUS_MULTAGGR: 14096 assert(!var->donotmultaggr); 14097 assert(var->data.multaggr.vars != NULL); 14098 assert(var->data.multaggr.scalars != NULL); 14099 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct 14100 * assert(var->data.multaggr.nvars >= 2); 14101 */ 14102 avgsol = var->data.multaggr.constant; 14103 for( i = 0; i < var->data.multaggr.nvars; ++i ) 14104 avgsol += var->data.multaggr.scalars[i] * SCIPvarGetAvgSol(var->data.multaggr.vars[i]); 14105 return avgsol; 14106 14107 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 14108 assert(var->negatedvar != NULL); 14109 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 14110 assert(var->negatedvar->negatedvar == var); 14111 return var->data.negate.constant - SCIPvarGetAvgSol(var->negatedvar); 14112 14113 default: 14114 SCIPerrorMessage("unknown variable status\n"); 14115 SCIPABORT(); 14116 return 0.0; /*lint !e527*/ 14117 } 14118 } 14119 14120 /** returns solution value and index of variable lower bound that is closest to the variable's value in the given primal solution 14121 * or current LP solution if no primal solution is given; returns an index of -1 if no variable lower bound is available 14122 */ 14123 void SCIPvarGetClosestVlb( 14124 SCIP_VAR* var, /**< active problem variable */ 14125 SCIP_SOL* sol, /**< primal solution, or NULL for LP solution */ 14126 SCIP_SET* set, /**< global SCIP settings */ 14127 SCIP_STAT* stat, /**< problem statistics */ 14128 SCIP_Real* closestvlb, /**< pointer to store the value of the closest variable lower bound */ 14129 int* closestvlbidx /**< pointer to store the index of the closest variable lower bound */ 14130 ) 14131 { 14132 int nvlbs; 14133 14134 assert(var != NULL); 14135 assert(stat != NULL); 14136 assert(set != NULL); 14137 assert(var->scip == set->scip); 14138 assert(closestvlb != NULL); 14139 assert(closestvlbidx != NULL); 14140 14141 *closestvlbidx = -1; 14142 *closestvlb = SCIP_REAL_MIN; 14143 14144 nvlbs = SCIPvarGetNVlbs(var); 14145 if( nvlbs > 0 ) 14146 { 14147 SCIP_VAR** vlbvars; 14148 SCIP_Real* vlbcoefs; 14149 SCIP_Real* vlbconsts; 14150 int i; 14151 14152 vlbvars = SCIPvarGetVlbVars(var); 14153 vlbcoefs = SCIPvarGetVlbCoefs(var); 14154 vlbconsts = SCIPvarGetVlbConstants(var); 14155 14156 /* check for cached values */ 14157 if( var->closestvblpcount == stat->lpcount && var->closestvlbidx != -1 && sol == NULL) 14158 { 14159 i = var->closestvlbidx; 14160 assert(0 <= i && i < nvlbs); 14161 assert(SCIPvarIsActive(vlbvars[i])); 14162 *closestvlbidx = i; 14163 *closestvlb = vlbcoefs[i] * SCIPvarGetLPSol(vlbvars[i]) + vlbconsts[i]; 14164 } 14165 else 14166 { 14167 /* search best VUB */ 14168 for( i = 0; i < nvlbs; i++ ) 14169 { 14170 if( SCIPvarIsActive(vlbvars[i]) ) 14171 { 14172 SCIP_Real vlbsol; 14173 14174 vlbsol = vlbcoefs[i] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[i]) : SCIPsolGetVal(sol, set, stat, vlbvars[i])) + vlbconsts[i]; 14175 if( vlbsol > *closestvlb ) 14176 { 14177 *closestvlb = vlbsol; 14178 *closestvlbidx = i; 14179 } 14180 } 14181 } 14182 14183 if( sol == NULL ) 14184 { 14185 /* update cached value */ 14186 if( var->closestvblpcount != stat->lpcount ) 14187 var->closestvubidx = -1; 14188 var->closestvlbidx = *closestvlbidx; 14189 var->closestvblpcount = stat->lpcount; 14190 } 14191 } 14192 } 14193 } 14194 14195 /** returns solution value and index of variable upper bound that is closest to the variable's value in the given primal solution; 14196 * or current LP solution if no primal solution is given; returns an index of -1 if no variable upper bound is available 14197 */ 14198 void SCIPvarGetClosestVub( 14199 SCIP_VAR* var, /**< active problem variable */ 14200 SCIP_SOL* sol, /**< primal solution, or NULL for LP solution */ 14201 SCIP_SET* set, /**< global SCIP settings */ 14202 SCIP_STAT* stat, /**< problem statistics */ 14203 SCIP_Real* closestvub, /**< pointer to store the value of the closest variable upper bound */ 14204 int* closestvubidx /**< pointer to store the index of the closest variable upper bound */ 14205 ) 14206 { 14207 int nvubs; 14208 14209 assert(var != NULL); 14210 assert(set != NULL); 14211 assert(var->scip == set->scip); 14212 assert(closestvub != NULL); 14213 assert(closestvubidx != NULL); 14214 14215 *closestvubidx = -1; 14216 *closestvub = SCIP_REAL_MAX; 14217 14218 nvubs = SCIPvarGetNVubs(var); 14219 if( nvubs > 0 ) 14220 { 14221 SCIP_VAR** vubvars; 14222 SCIP_Real* vubcoefs; 14223 SCIP_Real* vubconsts; 14224 int i; 14225 14226 vubvars = SCIPvarGetVubVars(var); 14227 vubcoefs = SCIPvarGetVubCoefs(var); 14228 vubconsts = SCIPvarGetVubConstants(var); 14229 14230 /* check for cached values */ 14231 if( var->closestvblpcount == stat->lpcount && var->closestvubidx != -1 && sol == NULL) 14232 { 14233 i = var->closestvubidx; 14234 assert(0 <= i && i < nvubs); 14235 assert(SCIPvarIsActive(vubvars[i])); 14236 *closestvubidx = i; 14237 *closestvub = vubcoefs[i] * SCIPvarGetLPSol(vubvars[i]) + vubconsts[i]; 14238 } 14239 else 14240 { 14241 /* search best VUB */ 14242 for( i = 0; i < nvubs; i++ ) 14243 { 14244 if( SCIPvarIsActive(vubvars[i]) ) 14245 { 14246 SCIP_Real vubsol; 14247 14248 vubsol = vubcoefs[i] * (sol == NULL ? SCIPvarGetLPSol(vubvars[i]) : SCIPsolGetVal(sol, set, stat, vubvars[i])) + vubconsts[i]; 14249 if( vubsol < *closestvub ) 14250 { 14251 *closestvub = vubsol; 14252 *closestvubidx = i; 14253 } 14254 } 14255 } 14256 14257 if( sol == NULL ) 14258 { 14259 /* update cached value */ 14260 if( var->closestvblpcount != stat->lpcount ) 14261 var->closestvlbidx = -1; 14262 var->closestvubidx = *closestvubidx; 14263 var->closestvblpcount = stat->lpcount; 14264 } 14265 } 14266 } 14267 } 14268 14269 /** resolves variable to columns and adds them with the coefficient to the row */ 14270 SCIP_RETCODE SCIPvarAddToRow( 14271 SCIP_VAR* var, /**< problem variable */ 14272 BMS_BLKMEM* blkmem, /**< block memory */ 14273 SCIP_SET* set, /**< global SCIP settings */ 14274 SCIP_STAT* stat, /**< problem statistics */ 14275 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 14276 SCIP_PROB* prob, /**< problem data */ 14277 SCIP_LP* lp, /**< current LP data */ 14278 SCIP_ROW* row, /**< LP row */ 14279 SCIP_Real val /**< value of coefficient */ 14280 ) 14281 { 14282 int i; 14283 14284 assert(var != NULL); 14285 assert(set != NULL); 14286 assert(var->scip == set->scip); 14287 assert(row != NULL); 14288 assert(!SCIPsetIsInfinity(set, REALABS(val))); 14289 14290 SCIPsetDebugMsg(set, "adding coefficient %g<%s> to row <%s>\n", val, var->name, row->name); 14291 14292 if ( SCIPsetIsZero(set, val) ) 14293 return SCIP_OKAY; 14294 14295 switch( SCIPvarGetStatus(var) ) 14296 { 14297 case SCIP_VARSTATUS_ORIGINAL: 14298 if( var->data.original.transvar == NULL ) 14299 { 14300 SCIPerrorMessage("cannot add untransformed original variable <%s> to LP row <%s>\n", var->name, row->name); 14301 return SCIP_INVALIDDATA; 14302 } 14303 SCIP_CALL( SCIPvarAddToRow(var->data.original.transvar, blkmem, set, stat, eventqueue, prob, lp, row, val) ); 14304 return SCIP_OKAY; 14305 14306 case SCIP_VARSTATUS_LOOSE: 14307 /* add globally fixed variables as constant */ 14308 if( SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub) ) 14309 { 14310 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, val * var->glbdom.lb) ); 14311 return SCIP_OKAY; 14312 } 14313 /* convert loose variable into column */ 14314 SCIP_CALL( SCIPvarColumn(var, blkmem, set, stat, prob, lp) ); 14315 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 14316 /*lint -fallthrough*/ 14317 14318 case SCIP_VARSTATUS_COLUMN: 14319 assert(var->data.col != NULL); 14320 assert(var->data.col->var == var); 14321 SCIP_CALL( SCIProwIncCoef(row, blkmem, set, eventqueue, lp, var->data.col, val) ); 14322 return SCIP_OKAY; 14323 14324 case SCIP_VARSTATUS_FIXED: 14325 assert(var->glbdom.lb == var->glbdom.ub); /*lint !e777*/ 14326 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/ 14327 assert(var->locdom.lb == var->glbdom.lb); /*lint !e777*/ 14328 assert(!SCIPsetIsInfinity(set, REALABS(var->locdom.lb))); 14329 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, val * var->locdom.lb) ); 14330 return SCIP_OKAY; 14331 14332 case SCIP_VARSTATUS_AGGREGATED: 14333 assert(!var->donotaggr); 14334 assert(var->data.aggregate.var != NULL); 14335 SCIP_CALL( SCIPvarAddToRow(var->data.aggregate.var, blkmem, set, stat, eventqueue, prob, lp, 14336 row, var->data.aggregate.scalar * val) ); 14337 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.aggregate.constant * val) ); 14338 return SCIP_OKAY; 14339 14340 case SCIP_VARSTATUS_MULTAGGR: 14341 assert(!var->donotmultaggr); 14342 assert(var->data.multaggr.vars != NULL); 14343 assert(var->data.multaggr.scalars != NULL); 14344 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct 14345 * assert(var->data.multaggr.nvars >= 2); 14346 */ 14347 for( i = 0; i < var->data.multaggr.nvars; ++i ) 14348 { 14349 SCIP_CALL( SCIPvarAddToRow(var->data.multaggr.vars[i], blkmem, set, stat, eventqueue, prob, lp, 14350 row, var->data.multaggr.scalars[i] * val) ); 14351 } 14352 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.multaggr.constant * val) ); 14353 return SCIP_OKAY; 14354 14355 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 14356 assert(var->negatedvar != NULL); 14357 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 14358 assert(var->negatedvar->negatedvar == var); 14359 SCIP_CALL( SCIPvarAddToRow(var->negatedvar, blkmem, set, stat, eventqueue, prob, lp, row, -val) ); 14360 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.negate.constant * val) ); 14361 return SCIP_OKAY; 14362 14363 default: 14364 SCIPerrorMessage("unknown variable status\n"); 14365 return SCIP_INVALIDDATA; 14366 } 14367 } 14368 14369 /* optionally, define this compiler flag to write complete variable histories to a file */ 14370 #ifdef SCIP_HISTORYTOFILE 14371 SCIP_Longint counter = 0l; 14372 const char* historypath="."; /* allows for user-defined path; use '.' for calling directory of SCIP */ 14373 #include "scip/scip.h" 14374 #endif 14375 14376 /** updates the pseudo costs of the given variable and the global pseudo costs after a change of 14377 * "solvaldelta" in the variable's solution value and resulting change of "objdelta" in the in the LP's objective value 14378 */ 14379 SCIP_RETCODE SCIPvarUpdatePseudocost( 14380 SCIP_VAR* var, /**< problem variable */ 14381 SCIP_SET* set, /**< global SCIP settings */ 14382 SCIP_STAT* stat, /**< problem statistics */ 14383 SCIP_Real solvaldelta, /**< difference of variable's new LP value - old LP value */ 14384 SCIP_Real objdelta, /**< difference of new LP's objective value - old LP's objective value */ 14385 SCIP_Real weight /**< weight in (0,1] of this update in pseudo cost sum */ 14386 ) 14387 { 14388 SCIP_Real oldrootpseudocosts; 14389 assert(var != NULL); 14390 assert(set != NULL); 14391 assert(var->scip == set->scip); 14392 assert(stat != NULL); 14393 14394 /* check if history statistics should be collected for a variable */ 14395 if( !stat->collectvarhistory ) 14396 return SCIP_OKAY; 14397 14398 switch( SCIPvarGetStatus(var) ) 14399 { 14400 case SCIP_VARSTATUS_ORIGINAL: 14401 if( var->data.original.transvar == NULL ) 14402 { 14403 SCIPerrorMessage("cannot update pseudo costs of original untransformed variable\n"); 14404 return SCIP_INVALIDDATA; 14405 } 14406 SCIP_CALL( SCIPvarUpdatePseudocost(var->data.original.transvar, set, stat, solvaldelta, objdelta, weight) ); 14407 return SCIP_OKAY; 14408 14409 case SCIP_VARSTATUS_LOOSE: 14410 case SCIP_VARSTATUS_COLUMN: 14411 /* store old pseudo-costs for root LP best-estimate update */ 14412 oldrootpseudocosts = SCIPvarGetMinPseudocostScore(var, stat, set, SCIPvarGetRootSol(var)); 14413 14414 /* update history */ 14415 SCIPhistoryUpdatePseudocost(var->history, set, solvaldelta, objdelta, weight); 14416 SCIPhistoryUpdatePseudocost(var->historycrun, set, solvaldelta, objdelta, weight); 14417 SCIPhistoryUpdatePseudocost(stat->glbhistory, set, solvaldelta, objdelta, weight); 14418 SCIPhistoryUpdatePseudocost(stat->glbhistorycrun, set, solvaldelta, objdelta, weight); 14419 14420 /* update root LP best-estimate */ 14421 SCIP_CALL( SCIPstatUpdateVarRootLPBestEstimate(stat, set, var, oldrootpseudocosts) ); 14422 14423 /* append history to file */ 14424 #ifdef SCIP_HISTORYTOFILE 14425 { 14426 FILE* f; 14427 char filename[256]; 14428 SCIP_NODE* currentnode; 14429 SCIP_NODE* parentnode; 14430 currentnode = SCIPgetFocusNode(set->scip); 14431 parentnode = SCIPnodeGetParent(currentnode); 14432 14433 sprintf(filename, "%s/%s.pse", historypath, SCIPgetProbName(set->scip)); 14434 f = fopen(filename, "a"); 14435 if( NULL != f ) 14436 { 14437 fprintf(f, "%lld %s \t %lld \t %lld \t %lld \t %d \t %15.9f \t %.3f\n", 14438 ++counter, 14439 SCIPvarGetName(var), 14440 SCIPnodeGetNumber(currentnode), 14441 parentnode != NULL ? SCIPnodeGetNumber(parentnode) : -1, 14442 SCIPgetNLPIterations(set->scip), 14443 SCIPgetDepth(set->scip), 14444 objdelta, 14445 solvaldelta); 14446 fclose(f); 14447 } 14448 } 14449 #endif 14450 return SCIP_OKAY; 14451 14452 case SCIP_VARSTATUS_FIXED: 14453 SCIPerrorMessage("cannot update pseudo cost values of a fixed variable\n"); 14454 return SCIP_INVALIDDATA; 14455 14456 case SCIP_VARSTATUS_AGGREGATED: 14457 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar)); 14458 SCIP_CALL( SCIPvarUpdatePseudocost(var->data.aggregate.var, set, stat, 14459 solvaldelta/var->data.aggregate.scalar, objdelta, weight) ); 14460 return SCIP_OKAY; 14461 14462 case SCIP_VARSTATUS_MULTAGGR: 14463 SCIPerrorMessage("cannot update pseudo cost values of a multi-aggregated variable\n"); 14464 return SCIP_INVALIDDATA; 14465 14466 case SCIP_VARSTATUS_NEGATED: 14467 SCIP_CALL( SCIPvarUpdatePseudocost(var->negatedvar, set, stat, -solvaldelta, objdelta, weight) ); 14468 return SCIP_OKAY; 14469 14470 default: 14471 SCIPerrorMessage("unknown variable status\n"); 14472 return SCIP_INVALIDDATA; 14473 } 14474 } 14475 14476 /** gets the variable's pseudo cost value for the given step size "solvaldelta" in the variable's LP solution value */ 14477 SCIP_Real SCIPvarGetPseudocost( 14478 SCIP_VAR* var, /**< problem variable */ 14479 SCIP_STAT* stat, /**< problem statistics */ 14480 SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */ 14481 ) 14482 { 14483 SCIP_BRANCHDIR dir; 14484 14485 assert(var != NULL); 14486 assert(stat != NULL); 14487 14488 switch( SCIPvarGetStatus(var) ) 14489 { 14490 case SCIP_VARSTATUS_ORIGINAL: 14491 if( var->data.original.transvar == NULL ) 14492 return SCIPhistoryGetPseudocost(stat->glbhistory, solvaldelta); 14493 else 14494 return SCIPvarGetPseudocost(var->data.original.transvar, stat, solvaldelta); 14495 14496 case SCIP_VARSTATUS_LOOSE: 14497 case SCIP_VARSTATUS_COLUMN: 14498 dir = (solvaldelta >= 0.0 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS); 14499 14500 return SCIPhistoryGetPseudocostCount(var->history, dir) > 0.0 14501 ? SCIPhistoryGetPseudocost(var->history, solvaldelta) 14502 : SCIPhistoryGetPseudocost(stat->glbhistory, solvaldelta); 14503 14504 case SCIP_VARSTATUS_FIXED: 14505 return 0.0; 14506 14507 case SCIP_VARSTATUS_AGGREGATED: 14508 return SCIPvarGetPseudocost(var->data.aggregate.var, stat, var->data.aggregate.scalar * solvaldelta); 14509 14510 case SCIP_VARSTATUS_MULTAGGR: 14511 return 0.0; 14512 14513 case SCIP_VARSTATUS_NEGATED: 14514 return SCIPvarGetPseudocost(var->negatedvar, stat, -solvaldelta); 14515 14516 default: 14517 SCIPerrorMessage("unknown variable status\n"); 14518 SCIPABORT(); 14519 return 0.0; /*lint !e527*/ 14520 } 14521 } 14522 14523 /** gets the variable's pseudo cost value for the given step size "solvaldelta" in the variable's LP solution value, 14524 * only using the pseudo cost information of the current run 14525 */ 14526 SCIP_Real SCIPvarGetPseudocostCurrentRun( 14527 SCIP_VAR* var, /**< problem variable */ 14528 SCIP_STAT* stat, /**< problem statistics */ 14529 SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */ 14530 ) 14531 { 14532 SCIP_BRANCHDIR dir; 14533 14534 assert(var != NULL); 14535 assert(stat != NULL); 14536 14537 switch( SCIPvarGetStatus(var) ) 14538 { 14539 case SCIP_VARSTATUS_ORIGINAL: 14540 if( var->data.original.transvar == NULL ) 14541 return SCIPhistoryGetPseudocost(stat->glbhistorycrun, solvaldelta); 14542 else 14543 return SCIPvarGetPseudocostCurrentRun(var->data.original.transvar, stat, solvaldelta); 14544 14545 case SCIP_VARSTATUS_LOOSE: 14546 case SCIP_VARSTATUS_COLUMN: 14547 dir = (solvaldelta >= 0.0 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS); 14548 14549 return SCIPhistoryGetPseudocostCount(var->historycrun, dir) > 0.0 14550 ? SCIPhistoryGetPseudocost(var->historycrun, solvaldelta) 14551 : SCIPhistoryGetPseudocost(stat->glbhistorycrun, solvaldelta); 14552 14553 case SCIP_VARSTATUS_FIXED: 14554 return 0.0; 14555 14556 case SCIP_VARSTATUS_AGGREGATED: 14557 return SCIPvarGetPseudocostCurrentRun(var->data.aggregate.var, stat, var->data.aggregate.scalar * solvaldelta); 14558 14559 case SCIP_VARSTATUS_MULTAGGR: 14560 return 0.0; 14561 14562 case SCIP_VARSTATUS_NEGATED: 14563 return SCIPvarGetPseudocostCurrentRun(var->negatedvar, stat, -solvaldelta); 14564 14565 default: 14566 SCIPerrorMessage("unknown variable status\n"); 14567 SCIPABORT(); 14568 return 0.0; /*lint !e527*/ 14569 } 14570 } 14571 14572 /** gets the variable's (possible fractional) number of pseudo cost updates for the given direction */ 14573 SCIP_Real SCIPvarGetPseudocostCount( 14574 SCIP_VAR* var, /**< problem variable */ 14575 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 14576 ) 14577 { 14578 assert(var != NULL); 14579 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 14580 14581 switch( SCIPvarGetStatus(var) ) 14582 { 14583 case SCIP_VARSTATUS_ORIGINAL: 14584 if( var->data.original.transvar == NULL ) 14585 return 0.0; 14586 else 14587 return SCIPvarGetPseudocostCount(var->data.original.transvar, dir); 14588 14589 case SCIP_VARSTATUS_LOOSE: 14590 case SCIP_VARSTATUS_COLUMN: 14591 return SCIPhistoryGetPseudocostCount(var->history, dir); 14592 14593 case SCIP_VARSTATUS_FIXED: 14594 return 0.0; 14595 14596 case SCIP_VARSTATUS_AGGREGATED: 14597 if( var->data.aggregate.scalar > 0.0 ) 14598 return SCIPvarGetPseudocostCount(var->data.aggregate.var, dir); 14599 else 14600 return SCIPvarGetPseudocostCount(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 14601 14602 case SCIP_VARSTATUS_MULTAGGR: 14603 return 0.0; 14604 14605 case SCIP_VARSTATUS_NEGATED: 14606 return SCIPvarGetPseudocostCount(var->negatedvar, SCIPbranchdirOpposite(dir)); 14607 14608 default: 14609 SCIPerrorMessage("unknown variable status\n"); 14610 SCIPABORT(); 14611 return 0.0; /*lint !e527*/ 14612 } 14613 } 14614 14615 /** gets the variable's (possible fractional) number of pseudo cost updates for the given direction, 14616 * only using the pseudo cost information of the current run 14617 */ 14618 SCIP_Real SCIPvarGetPseudocostCountCurrentRun( 14619 SCIP_VAR* var, /**< problem variable */ 14620 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 14621 ) 14622 { 14623 assert(var != NULL); 14624 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 14625 14626 switch( SCIPvarGetStatus(var) ) 14627 { 14628 case SCIP_VARSTATUS_ORIGINAL: 14629 if( var->data.original.transvar == NULL ) 14630 return 0.0; 14631 else 14632 return SCIPvarGetPseudocostCountCurrentRun(var->data.original.transvar, dir); 14633 14634 case SCIP_VARSTATUS_LOOSE: 14635 case SCIP_VARSTATUS_COLUMN: 14636 return SCIPhistoryGetPseudocostCount(var->historycrun, dir); 14637 14638 case SCIP_VARSTATUS_FIXED: 14639 return 0.0; 14640 14641 case SCIP_VARSTATUS_AGGREGATED: 14642 if( var->data.aggregate.scalar > 0.0 ) 14643 return SCIPvarGetPseudocostCountCurrentRun(var->data.aggregate.var, dir); 14644 else 14645 return SCIPvarGetPseudocostCountCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 14646 14647 case SCIP_VARSTATUS_MULTAGGR: 14648 return 0.0; 14649 14650 case SCIP_VARSTATUS_NEGATED: 14651 return SCIPvarGetPseudocostCountCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir)); 14652 14653 default: 14654 SCIPerrorMessage("unknown variable status\n"); 14655 SCIPABORT(); 14656 return 0.0; /*lint !e527*/ 14657 } 14658 } 14659 14660 /** compares both possible directions for rounding the given solution value and returns the minimum pseudo-costs of the variable */ 14661 SCIP_Real SCIPvarGetMinPseudocostScore( 14662 SCIP_VAR* var, /**< problem variable */ 14663 SCIP_STAT* stat, /**< problem statistics */ 14664 SCIP_SET* set, /**< global SCIP settings */ 14665 SCIP_Real solval /**< solution value, e.g., LP solution value */ 14666 ) 14667 { 14668 SCIP_Real upscore; 14669 SCIP_Real downscore; 14670 SCIP_Real solvaldeltaup; 14671 SCIP_Real solvaldeltadown; 14672 14673 /* LP root estimate only works for variables with fractional LP root solution */ 14674 if( SCIPsetIsFeasIntegral(set, solval) ) 14675 return 0.0; 14676 14677 /* no min pseudo-cost score is calculated as long as the variable was not initialized in a direction */ 14678 if( SCIPvarGetPseudocostCount(var, SCIP_BRANCHDIR_DOWNWARDS) < 1.0 || SCIPvarGetPseudocostCount(var, SCIP_BRANCHDIR_UPWARDS) < 1.0 ) 14679 return 0.0; 14680 14681 /* compute delta's to ceil and floor of root LP solution value */ 14682 solvaldeltaup = SCIPsetCeil(set, solval) - solval; 14683 solvaldeltadown = SCIPsetFloor(set, solval) - solval; 14684 14685 upscore = SCIPvarGetPseudocost(var, stat, solvaldeltaup); 14686 downscore = SCIPvarGetPseudocost(var, stat, solvaldeltadown); 14687 14688 return MIN(upscore, downscore); 14689 } 14690 14691 /** gets the an estimate of the variable's pseudo cost variance in direction \p dir */ 14692 SCIP_Real SCIPvarGetPseudocostVariance( 14693 SCIP_VAR* var, /**< problem variable */ 14694 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */ 14695 SCIP_Bool onlycurrentrun /**< return pseudo cost variance only for current branch and bound run */ 14696 ) 14697 { 14698 assert(var != NULL); 14699 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 14700 14701 switch( SCIPvarGetStatus(var) ) 14702 { 14703 case SCIP_VARSTATUS_ORIGINAL: 14704 if( var->data.original.transvar == NULL ) 14705 return 0.0; 14706 else 14707 return SCIPvarGetPseudocostVariance(var->data.original.transvar, dir, onlycurrentrun); 14708 14709 case SCIP_VARSTATUS_LOOSE: 14710 case SCIP_VARSTATUS_COLUMN: 14711 if( onlycurrentrun ) 14712 return SCIPhistoryGetPseudocostVariance(var->historycrun, dir); 14713 else 14714 return SCIPhistoryGetPseudocostVariance(var->history, dir); 14715 14716 case SCIP_VARSTATUS_FIXED: 14717 return 0.0; 14718 14719 case SCIP_VARSTATUS_AGGREGATED: 14720 if( var->data.aggregate.scalar > 0.0 ) 14721 return SCIPvarGetPseudocostVariance(var->data.aggregate.var, dir, onlycurrentrun); 14722 else 14723 return SCIPvarGetPseudocostVariance(var->data.aggregate.var, SCIPbranchdirOpposite(dir), onlycurrentrun); 14724 14725 case SCIP_VARSTATUS_MULTAGGR: 14726 return 0.0; 14727 14728 case SCIP_VARSTATUS_NEGATED: 14729 return SCIPvarGetPseudocostVariance(var->negatedvar, SCIPbranchdirOpposite(dir), onlycurrentrun); 14730 14731 default: 14732 SCIPerrorMessage("unknown variable status\n"); 14733 SCIPABORT(); 14734 return 0.0; /*lint !e527*/ 14735 } 14736 } 14737 14738 /** calculates a confidence bound for this variable under the assumption of normally distributed pseudo costs 14739 * 14740 * The confidence bound \f$ \theta \geq 0\f$ denotes the interval borders \f$ [X - \theta, \ X + \theta]\f$, which contains 14741 * the true pseudo costs of the variable, i.e., the expected value of the normal distribution, with a probability 14742 * of 2 * clevel - 1. 14743 * 14744 * @return value of confidence bound for this variable 14745 */ 14746 SCIP_Real SCIPvarCalcPscostConfidenceBound( 14747 SCIP_VAR* var, /**< variable in question */ 14748 SCIP_SET* set, /**< global SCIP settings */ 14749 SCIP_BRANCHDIR dir, /**< the branching direction for the confidence bound */ 14750 SCIP_Bool onlycurrentrun, /**< should only the current run be taken into account */ 14751 SCIP_CONFIDENCELEVEL clevel /**< confidence level for the interval */ 14752 ) 14753 { 14754 SCIP_Real confidencebound; 14755 14756 confidencebound = SCIPvarGetPseudocostVariance(var, dir, onlycurrentrun); 14757 if( SCIPsetIsFeasPositive(set, confidencebound) ) 14758 { 14759 SCIP_Real count; 14760 14761 if( onlycurrentrun ) 14762 count = SCIPvarGetPseudocostCountCurrentRun(var, dir); 14763 else 14764 count = SCIPvarGetPseudocostCount(var, dir); 14765 /* assertion is valid because variance is positive */ 14766 assert(count >= 1.9); 14767 14768 confidencebound /= count; /*lint !e414 division by zero can obviously not occur */ 14769 confidencebound = sqrt(confidencebound); 14770 14771 /* the actual, underlying distribution of the mean is a student-t-distribution with degrees of freedom equal to 14772 * the number of pseudo cost evaluations of this variable in the respective direction. */ 14773 confidencebound *= SCIPstudentTGetCriticalValue(clevel, (int)SCIPsetFloor(set, count) - 1); 14774 } 14775 else 14776 confidencebound = 0.0; 14777 14778 return confidencebound; 14779 } 14780 14781 /** check if the current pseudo cost relative error in a direction violates the given threshold. The Relative 14782 * Error is calculated at a specific confidence level 14783 */ 14784 SCIP_Bool SCIPvarIsPscostRelerrorReliable( 14785 SCIP_VAR* var, /**< variable in question */ 14786 SCIP_SET* set, /**< global SCIP settings */ 14787 SCIP_STAT* stat, /**< problem statistics */ 14788 SCIP_Real threshold, /**< threshold for relative errors to be considered reliable (enough) */ 14789 SCIP_CONFIDENCELEVEL clevel /**< a given confidence level */ 14790 ) 14791 { 14792 SCIP_Real downsize; 14793 SCIP_Real upsize; 14794 SCIP_Real size; 14795 SCIP_Real relerrorup; 14796 SCIP_Real relerrordown; 14797 SCIP_Real relerror; 14798 14799 /* check, if the pseudo cost score of the variable is reliable */ 14800 downsize = SCIPvarGetPseudocostCountCurrentRun(var, SCIP_BRANCHDIR_DOWNWARDS); 14801 upsize = SCIPvarGetPseudocostCountCurrentRun(var, SCIP_BRANCHDIR_UPWARDS); 14802 size = MIN(downsize, upsize); 14803 14804 /* Pseudo costs relative error can only be reliable if both directions have been tried at least twice */ 14805 if( size <= 1.9 ) 14806 return FALSE; 14807 14808 /* use the relative error between the current mean pseudo cost value of the candidate and its upper 14809 * confidence interval bound at confidence level of 95% for individual variable reliability. 14810 * this is only possible if we have at least 2 measurements and therefore a valid variance estimate. 14811 */ 14812 if( downsize >= 1.9 ) 14813 { 14814 SCIP_Real normval; 14815 14816 relerrordown = SCIPvarCalcPscostConfidenceBound(var, set, SCIP_BRANCHDIR_DOWNWARDS, TRUE, clevel); 14817 normval = SCIPvarGetPseudocostCurrentRun(var, stat, -1.0); 14818 normval = MAX(1.0, normval); 14819 14820 relerrordown /= normval; 14821 } 14822 else 14823 relerrordown = 0.0; 14824 14825 if( upsize >= 1.9 ) 14826 { 14827 SCIP_Real normval; 14828 14829 relerrorup = SCIPvarCalcPscostConfidenceBound(var, set, SCIP_BRANCHDIR_UPWARDS, TRUE, clevel); 14830 normval = SCIPvarGetPseudocostCurrentRun(var, stat, +1.0); 14831 normval = MAX(1.0, normval); 14832 relerrorup /= normval; 14833 } 14834 else 14835 relerrorup = 0.0; 14836 14837 /* consider the relative error threshold violated, if it is violated in at least one branching direction */ 14838 relerror = MAX(relerrorup, relerrordown); 14839 14840 return (relerror <= threshold); 14841 } 14842 14843 /** check if variable pseudo-costs have a significant difference in location. The significance depends on 14844 * the choice of \p clevel and on the kind of tested hypothesis. The one-sided hypothesis, which 14845 * should be rejected, is that fracy * mu_y >= fracx * mu_x, where mu_y and mu_x denote the 14846 * unknown location means of the underlying pseudo-cost distributions of x and y. 14847 * 14848 * This method is applied best if variable x has a better pseudo-cost score than y. The method hypothesizes that y were actually 14849 * better than x (despite the current information), meaning that y can be expected to yield branching 14850 * decisions as least as good as x in the long run. If the method returns TRUE, the current history information is 14851 * sufficient to safely rely on the alternative hypothesis that x yields indeed a better branching score (on average) 14852 * than y. 14853 * 14854 * @note The order of x and y matters for the one-sided hypothesis 14855 * 14856 * @note set \p onesided to FALSE if you are not sure which variable is better. The hypothesis tested then reads 14857 * fracy * mu_y == fracx * mu_x vs the alternative hypothesis fracy * mu_y != fracx * mu_x. 14858 * 14859 * @return TRUE if the hypothesis can be safely rejected at the given confidence level 14860 */ 14861 SCIP_Bool SCIPvarSignificantPscostDifference( 14862 SCIP_SET* set, /**< global SCIP settings */ 14863 SCIP_STAT* stat, /**< problem statistics */ 14864 SCIP_VAR* varx, /**< variable x */ 14865 SCIP_Real fracx, /**< the fractionality of variable x */ 14866 SCIP_VAR* vary, /**< variable y */ 14867 SCIP_Real fracy, /**< the fractionality of variable y */ 14868 SCIP_BRANCHDIR dir, /**< branching direction */ 14869 SCIP_CONFIDENCELEVEL clevel, /**< confidence level for rejecting hypothesis */ 14870 SCIP_Bool onesided /**< should a one-sided hypothesis y >= x be tested? */ 14871 ) 14872 { 14873 SCIP_Real meanx; 14874 SCIP_Real meany; 14875 SCIP_Real variancex; 14876 SCIP_Real variancey; 14877 SCIP_Real countx; 14878 SCIP_Real county; 14879 SCIP_Real tresult; 14880 SCIP_Real realdirection; 14881 14882 if( varx == vary ) 14883 return FALSE; 14884 14885 countx = SCIPvarGetPseudocostCount(varx, dir); 14886 county = SCIPvarGetPseudocostCount(vary, dir); 14887 14888 /* if not at least 2 measurements were taken, return FALSE */ 14889 if( countx <= 1.9 || county <= 1.9 ) 14890 return FALSE; 14891 14892 realdirection = (dir == SCIP_BRANCHDIR_DOWNWARDS ? -1.0 : 1.0); 14893 14894 meanx = fracx * SCIPvarGetPseudocost(varx, stat, realdirection); 14895 meany = fracy * SCIPvarGetPseudocost(vary, stat, realdirection); 14896 14897 variancex = SQR(fracx) * SCIPvarGetPseudocostVariance(varx, dir, FALSE); 14898 variancey = SQR(fracy) * SCIPvarGetPseudocostVariance(vary, dir, FALSE); 14899 14900 /* if there is no variance, the means are taken from a constant distribution */ 14901 if( SCIPsetIsFeasEQ(set, variancex + variancey, 0.0) ) 14902 return (onesided ? SCIPsetIsFeasGT(set, meanx, meany) : !SCIPsetIsFeasEQ(set, meanx, meany)); 14903 14904 tresult = SCIPcomputeTwoSampleTTestValue(meanx, meany, variancex, variancey, countx, county); 14905 14906 /* for the two-sided hypothesis, just take the absolute of t */ 14907 if( !onesided ) 14908 tresult = REALABS(tresult); 14909 14910 return (tresult >= SCIPstudentTGetCriticalValue(clevel, (int)(countx + county - 2))); 14911 } 14912 14913 /** tests at a given confidence level whether the variable pseudo-costs only have a small probability to 14914 * exceed a \p threshold. This is useful to determine if past observations provide enough evidence 14915 * to skip an expensive strong-branching step if there is already a candidate that has been proven to yield an improvement 14916 * of at least \p threshold. 14917 * 14918 * @note use \p clevel to adjust the level of confidence. For SCIP_CONFIDENCELEVEL_MIN, the method returns TRUE if 14919 * the estimated probability to exceed \p threshold is less than 25 %. 14920 * 14921 * @see SCIP_Confidencelevel for a list of available levels. The used probability limits refer to the one-sided levels 14922 * of confidence. 14923 * 14924 * @return TRUE if the variable pseudo-cost probabilistic model is likely to be smaller than \p threshold 14925 * at the given confidence level \p clevel. 14926 */ 14927 SCIP_Bool SCIPvarPscostThresholdProbabilityTest( 14928 SCIP_SET* set, /**< global SCIP settings */ 14929 SCIP_STAT* stat, /**< problem statistics */ 14930 SCIP_VAR* var, /**< variable x */ 14931 SCIP_Real frac, /**< the fractionality of variable x */ 14932 SCIP_Real threshold, /**< the threshold to test against */ 14933 SCIP_BRANCHDIR dir, /**< branching direction */ 14934 SCIP_CONFIDENCELEVEL clevel /**< confidence level for rejecting hypothesis */ 14935 ) 14936 { 14937 SCIP_Real mean; 14938 SCIP_Real variance; 14939 SCIP_Real count; 14940 SCIP_Real realdirection; 14941 SCIP_Real probability; 14942 SCIP_Real problimit; 14943 14944 count = SCIPvarGetPseudocostCount(var, dir); 14945 14946 /* if not at least 2 measurements were taken, return FALSE */ 14947 if( count <= 1.9 ) 14948 return FALSE; 14949 14950 realdirection = (dir == SCIP_BRANCHDIR_DOWNWARDS ? -1.0 : 1.0); 14951 14952 mean = frac * SCIPvarGetPseudocost(var, stat, realdirection); 14953 variance = SQR(frac) * SCIPvarGetPseudocostVariance(var, dir, FALSE); 14954 14955 /* if mean is at least threshold, it has at least a 50% probability to exceed threshold, we therefore return FALSE */ 14956 if( SCIPsetIsFeasGE(set, mean, threshold) ) 14957 return FALSE; 14958 14959 /* if there is no variance, the means are taken from a constant distribution */ 14960 if( SCIPsetIsFeasEQ(set, variance, 0.0) ) 14961 return SCIPsetIsFeasLT(set, mean, threshold); 14962 14963 /* obtain probability of a normally distributed random variable at given mean and variance to yield at most threshold */ 14964 probability = SCIPnormalCDF(mean, variance, threshold); 14965 14966 /* determine a probability limit corresponding to the given confidence level */ 14967 switch( clevel ) 14968 { 14969 case SCIP_CONFIDENCELEVEL_MIN: 14970 problimit = 0.75; 14971 break; 14972 case SCIP_CONFIDENCELEVEL_LOW: 14973 problimit = 0.875; 14974 break; 14975 case SCIP_CONFIDENCELEVEL_MEDIUM: 14976 problimit = 0.9; 14977 break; 14978 case SCIP_CONFIDENCELEVEL_HIGH: 14979 problimit = 0.95; 14980 break; 14981 case SCIP_CONFIDENCELEVEL_MAX: 14982 problimit = 0.975; 14983 break; 14984 default: 14985 problimit = -1; 14986 SCIPerrorMessage("Confidence level set to unknown value <%d>", (int)clevel); 14987 SCIPABORT(); 14988 break; 14989 } 14990 14991 return (probability >= problimit); 14992 } 14993 14994 /** find the corresponding history entry if already existing, otherwise create new entry */ 14995 static 14996 SCIP_RETCODE findValuehistoryEntry( 14997 SCIP_VAR* var, /**< problem variable */ 14998 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */ 14999 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */ 15000 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */ 15001 SCIP_HISTORY** history /**< pointer to store the value based history, or NULL */ 15002 ) 15003 { 15004 assert(var != NULL); 15005 assert(blkmem != NULL); 15006 assert(set != NULL); 15007 assert(history != NULL); 15008 15009 (*history) = NULL; 15010 15011 if( var->valuehistory == NULL ) 15012 { 15013 SCIP_CALL( SCIPvaluehistoryCreate(&var->valuehistory, blkmem) ); 15014 } 15015 15016 SCIP_CALL( SCIPvaluehistoryFind(var->valuehistory, blkmem, set, value, history) ); 15017 15018 return SCIP_OKAY; 15019 } 15020 15021 /** check if value based history should be used */ 15022 static 15023 SCIP_Bool useValuehistory( 15024 SCIP_VAR* var, /**< problem variable */ 15025 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */ 15026 SCIP_SET* set /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */ 15027 ) 15028 { 15029 /* check if the domain value is unknown (not specific) */ 15030 if( value == SCIP_UNKNOWN ) /*lint !e777*/ 15031 return FALSE; 15032 15033 assert(set != NULL); 15034 15035 /* check if value based history should be collected */ 15036 if( !set->history_valuebased ) 15037 return FALSE; 15038 15039 /* value based history is not collected for binary variable since the standard history already contains all information */ 15040 if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY ) 15041 return FALSE; 15042 15043 /* value based history is not collected for continuous variables */ 15044 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS ) 15045 return FALSE; 15046 15047 return TRUE; 15048 } 15049 15050 /** increases VSIDS of the variable by the given weight */ 15051 SCIP_RETCODE SCIPvarIncVSIDS( 15052 SCIP_VAR* var, /**< problem variable */ 15053 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */ 15054 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */ 15055 SCIP_STAT* stat, /**< problem statistics */ 15056 SCIP_BRANCHDIR dir, /**< branching direction */ 15057 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */ 15058 SCIP_Real weight /**< weight of this update in VSIDS */ 15059 ) 15060 { 15061 assert(var != NULL); 15062 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15063 15064 /* check if history statistics should be collected for a variable */ 15065 if( !stat->collectvarhistory ) 15066 return SCIP_OKAY; 15067 15068 if( SCIPsetIsZero(set, weight) ) 15069 return SCIP_OKAY; 15070 15071 switch( SCIPvarGetStatus(var) ) 15072 { 15073 case SCIP_VARSTATUS_ORIGINAL: 15074 if( var->data.original.transvar == NULL ) 15075 { 15076 SCIPerrorMessage("cannot update VSIDS of original untransformed variable\n"); 15077 return SCIP_INVALIDDATA; 15078 } 15079 SCIP_CALL( SCIPvarIncVSIDS(var->data.original.transvar, blkmem, set, stat, dir, value, weight) ); 15080 return SCIP_OKAY; 15081 15082 case SCIP_VARSTATUS_LOOSE: 15083 case SCIP_VARSTATUS_COLUMN: 15084 { 15085 SCIPhistoryIncVSIDS(var->history, dir, weight); 15086 SCIPhistoryIncVSIDS(var->historycrun, dir, weight); 15087 15088 if( useValuehistory(var, value, set) ) 15089 { 15090 SCIP_HISTORY* history; 15091 15092 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) ); 15093 assert(history != NULL); 15094 15095 SCIPhistoryIncVSIDS(history, dir, weight); 15096 SCIPsetDebugMsg(set, "variable (<%s> %s %g) + <%g> = <%g>\n", SCIPvarGetName(var), dir == SCIP_BRANCHDIR_UPWARDS ? ">=" : "<=", 15097 value, weight, SCIPhistoryGetVSIDS(history, dir)); 15098 } 15099 15100 return SCIP_OKAY; 15101 } 15102 case SCIP_VARSTATUS_FIXED: 15103 SCIPerrorMessage("cannot update VSIDS of a fixed variable\n"); 15104 return SCIP_INVALIDDATA; 15105 15106 case SCIP_VARSTATUS_AGGREGATED: 15107 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar; 15108 15109 if( var->data.aggregate.scalar > 0.0 ) 15110 { 15111 SCIP_CALL( SCIPvarIncVSIDS(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) ); 15112 } 15113 else 15114 { 15115 assert(var->data.aggregate.scalar < 0.0); 15116 SCIP_CALL( SCIPvarIncVSIDS(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) ); 15117 } 15118 return SCIP_OKAY; 15119 15120 case SCIP_VARSTATUS_MULTAGGR: 15121 SCIPerrorMessage("cannot update VSIDS of a multi-aggregated variable\n"); 15122 return SCIP_INVALIDDATA; 15123 15124 case SCIP_VARSTATUS_NEGATED: 15125 value = 1.0 - value; 15126 15127 SCIP_CALL( SCIPvarIncVSIDS(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) ); 15128 return SCIP_OKAY; 15129 15130 default: 15131 SCIPerrorMessage("unknown variable status\n"); 15132 return SCIP_INVALIDDATA; 15133 } 15134 } 15135 15136 /** scales the VSIDS of the variable by the given scalar */ 15137 SCIP_RETCODE SCIPvarScaleVSIDS( 15138 SCIP_VAR* var, /**< problem variable */ 15139 SCIP_Real scalar /**< scalar to multiply the VSIDSs with */ 15140 ) 15141 { 15142 assert(var != NULL); 15143 15144 switch( SCIPvarGetStatus(var) ) 15145 { 15146 case SCIP_VARSTATUS_ORIGINAL: 15147 if( var->data.original.transvar == NULL ) 15148 { 15149 SCIPerrorMessage("cannot update VSIDS of original untransformed variable\n"); 15150 return SCIP_INVALIDDATA; 15151 } 15152 SCIP_CALL( SCIPvarScaleVSIDS(var->data.original.transvar, scalar) ); 15153 return SCIP_OKAY; 15154 15155 case SCIP_VARSTATUS_LOOSE: 15156 case SCIP_VARSTATUS_COLUMN: 15157 { 15158 SCIPhistoryScaleVSIDS(var->history, scalar); 15159 SCIPhistoryScaleVSIDS(var->historycrun, scalar); 15160 SCIPvaluehistoryScaleVSIDS(var->valuehistory, scalar); 15161 15162 return SCIP_OKAY; 15163 } 15164 case SCIP_VARSTATUS_FIXED: 15165 SCIPerrorMessage("cannot update VSIDS of a fixed variable\n"); 15166 return SCIP_INVALIDDATA; 15167 15168 case SCIP_VARSTATUS_AGGREGATED: 15169 SCIP_CALL( SCIPvarScaleVSIDS(var->data.aggregate.var, scalar) ); 15170 return SCIP_OKAY; 15171 15172 case SCIP_VARSTATUS_MULTAGGR: 15173 SCIPerrorMessage("cannot update VSIDS of a multi-aggregated variable\n"); 15174 return SCIP_INVALIDDATA; 15175 15176 case SCIP_VARSTATUS_NEGATED: 15177 SCIP_CALL( SCIPvarScaleVSIDS(var->negatedvar, scalar) ); 15178 return SCIP_OKAY; 15179 15180 default: 15181 SCIPerrorMessage("unknown variable status\n"); 15182 return SCIP_INVALIDDATA; 15183 } 15184 } 15185 15186 /** increases the number of active conflicts by one and the overall length of the variable by the given length */ 15187 SCIP_RETCODE SCIPvarIncNActiveConflicts( 15188 SCIP_VAR* var, /**< problem variable */ 15189 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */ 15190 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */ 15191 SCIP_STAT* stat, /**< problem statistics */ 15192 SCIP_BRANCHDIR dir, /**< branching direction */ 15193 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */ 15194 SCIP_Real length /**< length of the conflict */ 15195 ) 15196 { 15197 assert(var != NULL); 15198 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15199 15200 /* check if history statistics should be collected for a variable */ 15201 if( !stat->collectvarhistory ) 15202 return SCIP_OKAY; 15203 15204 switch( SCIPvarGetStatus(var) ) 15205 { 15206 case SCIP_VARSTATUS_ORIGINAL: 15207 if( var->data.original.transvar == NULL ) 15208 { 15209 SCIPerrorMessage("cannot update conflict score of original untransformed variable\n"); 15210 return SCIP_INVALIDDATA; 15211 } 15212 SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.original.transvar, blkmem, set, stat, dir, value, length) ); 15213 return SCIP_OKAY; 15214 15215 case SCIP_VARSTATUS_LOOSE: 15216 case SCIP_VARSTATUS_COLUMN: 15217 { 15218 SCIPhistoryIncNActiveConflicts(var->history, dir, length); 15219 SCIPhistoryIncNActiveConflicts(var->historycrun, dir, length); 15220 15221 if( useValuehistory(var, value, set) ) 15222 { 15223 SCIP_HISTORY* history; 15224 15225 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) ); 15226 assert(history != NULL); 15227 15228 SCIPhistoryIncNActiveConflicts(history, dir, length); 15229 } 15230 15231 return SCIP_OKAY; 15232 } 15233 case SCIP_VARSTATUS_FIXED: 15234 SCIPerrorMessage("cannot update conflict score of a fixed variable\n"); 15235 return SCIP_INVALIDDATA; 15236 15237 case SCIP_VARSTATUS_AGGREGATED: 15238 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar; 15239 15240 if( var->data.aggregate.scalar > 0.0 ) 15241 { 15242 SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.aggregate.var, blkmem, set, stat, dir, value, length) ); 15243 } 15244 else 15245 { 15246 assert(var->data.aggregate.scalar < 0.0); 15247 SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, length) ); 15248 } 15249 return SCIP_OKAY; 15250 15251 case SCIP_VARSTATUS_MULTAGGR: 15252 SCIPerrorMessage("cannot update conflict score of a multi-aggregated variable\n"); 15253 return SCIP_INVALIDDATA; 15254 15255 case SCIP_VARSTATUS_NEGATED: 15256 value = 1.0 - value; 15257 15258 SCIP_CALL( SCIPvarIncNActiveConflicts(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, length) ); 15259 return SCIP_OKAY; 15260 15261 default: 15262 SCIPerrorMessage("unknown variable status\n"); 15263 return SCIP_INVALIDDATA; 15264 } 15265 } 15266 15267 /** gets the number of active conflicts containing this variable in given direction */ 15268 SCIP_Longint SCIPvarGetNActiveConflicts( 15269 SCIP_VAR* var, /**< problem variable */ 15270 SCIP_STAT* stat, /**< problem statistics */ 15271 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15272 ) 15273 { 15274 assert(var != NULL); 15275 assert(stat != NULL); 15276 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15277 15278 switch( SCIPvarGetStatus(var) ) 15279 { 15280 case SCIP_VARSTATUS_ORIGINAL: 15281 if( var->data.original.transvar == NULL ) 15282 return 0; 15283 else 15284 return SCIPvarGetNActiveConflicts(var->data.original.transvar, stat, dir); 15285 15286 case SCIP_VARSTATUS_LOOSE: 15287 case SCIP_VARSTATUS_COLUMN: 15288 return SCIPhistoryGetNActiveConflicts(var->history, dir); 15289 15290 case SCIP_VARSTATUS_FIXED: 15291 return 0; 15292 15293 case SCIP_VARSTATUS_AGGREGATED: 15294 if( var->data.aggregate.scalar > 0.0 ) 15295 return SCIPvarGetNActiveConflicts(var->data.aggregate.var, stat, dir); 15296 else 15297 return SCIPvarGetNActiveConflicts(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir)); 15298 15299 case SCIP_VARSTATUS_MULTAGGR: 15300 return 0; 15301 15302 case SCIP_VARSTATUS_NEGATED: 15303 return SCIPvarGetNActiveConflicts(var->negatedvar, stat, SCIPbranchdirOpposite(dir)); 15304 15305 default: 15306 SCIPerrorMessage("unknown variable status\n"); 15307 SCIPABORT(); 15308 return 0; /*lint !e527*/ 15309 } 15310 } 15311 15312 /** gets the number of active conflicts containing this variable in given direction 15313 * in the current run 15314 */ 15315 SCIP_Longint SCIPvarGetNActiveConflictsCurrentRun( 15316 SCIP_VAR* var, /**< problem variable */ 15317 SCIP_STAT* stat, /**< problem statistics */ 15318 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15319 ) 15320 { 15321 assert(var != NULL); 15322 assert(stat != NULL); 15323 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15324 15325 switch( SCIPvarGetStatus(var) ) 15326 { 15327 case SCIP_VARSTATUS_ORIGINAL: 15328 if( var->data.original.transvar == NULL ) 15329 return 0; 15330 else 15331 return SCIPvarGetNActiveConflictsCurrentRun(var->data.original.transvar, stat, dir); 15332 15333 case SCIP_VARSTATUS_LOOSE: 15334 case SCIP_VARSTATUS_COLUMN: 15335 return SCIPhistoryGetNActiveConflicts(var->historycrun, dir); 15336 15337 case SCIP_VARSTATUS_FIXED: 15338 return 0; 15339 15340 case SCIP_VARSTATUS_AGGREGATED: 15341 if( var->data.aggregate.scalar > 0.0 ) 15342 return SCIPvarGetNActiveConflictsCurrentRun(var->data.aggregate.var, stat, dir); 15343 else 15344 return SCIPvarGetNActiveConflictsCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir)); 15345 15346 case SCIP_VARSTATUS_MULTAGGR: 15347 return 0; 15348 15349 case SCIP_VARSTATUS_NEGATED: 15350 return SCIPvarGetNActiveConflictsCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir)); 15351 15352 default: 15353 SCIPerrorMessage("unknown variable status\n"); 15354 SCIPABORT(); 15355 return 0; /*lint !e527*/ 15356 } 15357 } 15358 15359 /** gets the average conflict length in given direction due to branching on the variable */ 15360 SCIP_Real SCIPvarGetAvgConflictlength( 15361 SCIP_VAR* var, /**< problem variable */ 15362 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15363 ) 15364 { 15365 assert(var != NULL); 15366 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15367 15368 switch( SCIPvarGetStatus(var) ) 15369 { 15370 case SCIP_VARSTATUS_ORIGINAL: 15371 if( var->data.original.transvar == NULL ) 15372 return 0.0; 15373 else 15374 return SCIPvarGetAvgConflictlength(var->data.original.transvar, dir); 15375 15376 case SCIP_VARSTATUS_LOOSE: 15377 case SCIP_VARSTATUS_COLUMN: 15378 return SCIPhistoryGetAvgConflictlength(var->history, dir); 15379 case SCIP_VARSTATUS_FIXED: 15380 return 0.0; 15381 15382 case SCIP_VARSTATUS_AGGREGATED: 15383 if( var->data.aggregate.scalar > 0.0 ) 15384 return SCIPvarGetAvgConflictlength(var->data.aggregate.var, dir); 15385 else 15386 return SCIPvarGetAvgConflictlength(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 15387 15388 case SCIP_VARSTATUS_MULTAGGR: 15389 return 0.0; 15390 15391 case SCIP_VARSTATUS_NEGATED: 15392 return SCIPvarGetAvgConflictlength(var->negatedvar, SCIPbranchdirOpposite(dir)); 15393 15394 default: 15395 SCIPerrorMessage("unknown variable status\n"); 15396 SCIPABORT(); 15397 return 0.0; /*lint !e527*/ 15398 } 15399 } 15400 15401 /** gets the average conflict length in given direction due to branching on the variable 15402 * in the current run 15403 */ 15404 SCIP_Real SCIPvarGetAvgConflictlengthCurrentRun( 15405 SCIP_VAR* var, /**< problem variable */ 15406 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15407 ) 15408 { 15409 assert(var != NULL); 15410 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15411 15412 switch( SCIPvarGetStatus(var) ) 15413 { 15414 case SCIP_VARSTATUS_ORIGINAL: 15415 if( var->data.original.transvar == NULL ) 15416 return 0.0; 15417 else 15418 return SCIPvarGetAvgConflictlengthCurrentRun(var->data.original.transvar, dir); 15419 15420 case SCIP_VARSTATUS_LOOSE: 15421 case SCIP_VARSTATUS_COLUMN: 15422 return SCIPhistoryGetAvgConflictlength(var->historycrun, dir); 15423 15424 case SCIP_VARSTATUS_FIXED: 15425 return 0.0; 15426 15427 case SCIP_VARSTATUS_AGGREGATED: 15428 if( var->data.aggregate.scalar > 0.0 ) 15429 return SCIPvarGetAvgConflictlengthCurrentRun(var->data.aggregate.var, dir); 15430 else 15431 return SCIPvarGetAvgConflictlengthCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 15432 15433 case SCIP_VARSTATUS_MULTAGGR: 15434 return 0.0; 15435 15436 case SCIP_VARSTATUS_NEGATED: 15437 return SCIPvarGetAvgConflictlengthCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir)); 15438 15439 default: 15440 SCIPerrorMessage("unknown variable status\n"); 15441 SCIPABORT(); 15442 return 0.0; /*lint !e527*/ 15443 } 15444 } 15445 15446 /** increases the number of branchings counter of the variable */ 15447 SCIP_RETCODE SCIPvarIncNBranchings( 15448 SCIP_VAR* var, /**< problem variable */ 15449 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */ 15450 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */ 15451 SCIP_STAT* stat, /**< problem statistics */ 15452 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */ 15453 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */ 15454 int depth /**< depth at which the bound change took place */ 15455 ) 15456 { 15457 assert(var != NULL); 15458 assert(stat != NULL); 15459 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15460 15461 /* check if history statistics should be collected for a variable */ 15462 if( !stat->collectvarhistory ) 15463 return SCIP_OKAY; 15464 15465 switch( SCIPvarGetStatus(var) ) 15466 { 15467 case SCIP_VARSTATUS_ORIGINAL: 15468 if( var->data.original.transvar == NULL ) 15469 { 15470 SCIPerrorMessage("cannot update branching counter of original untransformed variable\n"); 15471 return SCIP_INVALIDDATA; 15472 } 15473 SCIP_CALL( SCIPvarIncNBranchings(var->data.original.transvar, blkmem, set, stat, dir, value, depth) ); 15474 return SCIP_OKAY; 15475 15476 case SCIP_VARSTATUS_LOOSE: 15477 case SCIP_VARSTATUS_COLUMN: 15478 { 15479 SCIPhistoryIncNBranchings(var->history, dir, depth); 15480 SCIPhistoryIncNBranchings(var->historycrun, dir, depth); 15481 SCIPhistoryIncNBranchings(stat->glbhistory, dir, depth); 15482 SCIPhistoryIncNBranchings(stat->glbhistorycrun, dir, depth); 15483 15484 if( useValuehistory(var, value, set) ) 15485 { 15486 SCIP_HISTORY* history; 15487 15488 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) ); 15489 assert(history != NULL); 15490 15491 SCIPhistoryIncNBranchings(history, dir, depth); 15492 } 15493 15494 return SCIP_OKAY; 15495 } 15496 case SCIP_VARSTATUS_FIXED: 15497 SCIPerrorMessage("cannot update branching counter of a fixed variable\n"); 15498 return SCIP_INVALIDDATA; 15499 15500 case SCIP_VARSTATUS_AGGREGATED: 15501 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar; 15502 15503 if( var->data.aggregate.scalar > 0.0 ) 15504 { 15505 SCIP_CALL( SCIPvarIncNBranchings(var->data.aggregate.var, blkmem, set, stat, dir, value, depth) ); 15506 } 15507 else 15508 { 15509 assert(var->data.aggregate.scalar < 0.0); 15510 SCIP_CALL( SCIPvarIncNBranchings(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, depth) ); 15511 } 15512 return SCIP_OKAY; 15513 15514 case SCIP_VARSTATUS_MULTAGGR: 15515 SCIPerrorMessage("cannot update branching counter of a multi-aggregated variable\n"); 15516 return SCIP_INVALIDDATA; 15517 15518 case SCIP_VARSTATUS_NEGATED: 15519 value = 1.0 - value; 15520 15521 SCIP_CALL( SCIPvarIncNBranchings(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, depth) ); 15522 return SCIP_OKAY; 15523 15524 default: 15525 SCIPerrorMessage("unknown variable status\n"); 15526 return SCIP_INVALIDDATA; 15527 } 15528 } 15529 15530 /** increases the inference sum of the variable by the given weight */ 15531 SCIP_RETCODE SCIPvarIncInferenceSum( 15532 SCIP_VAR* var, /**< problem variable */ 15533 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */ 15534 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */ 15535 SCIP_STAT* stat, /**< problem statistics */ 15536 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */ 15537 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */ 15538 SCIP_Real weight /**< weight of this update in inference score */ 15539 ) 15540 { 15541 assert(var != NULL); 15542 assert(stat != NULL); 15543 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15544 15545 /* check if history statistics should be collected for a variable */ 15546 if( !stat->collectvarhistory ) 15547 return SCIP_OKAY; 15548 15549 switch( SCIPvarGetStatus(var) ) 15550 { 15551 case SCIP_VARSTATUS_ORIGINAL: 15552 if( var->data.original.transvar == NULL ) 15553 { 15554 SCIPerrorMessage("cannot update inference counter of original untransformed variable\n"); 15555 return SCIP_INVALIDDATA; 15556 } 15557 SCIP_CALL( SCIPvarIncInferenceSum(var->data.original.transvar, blkmem, set, stat, dir, value, weight) ); 15558 return SCIP_OKAY; 15559 15560 case SCIP_VARSTATUS_LOOSE: 15561 case SCIP_VARSTATUS_COLUMN: 15562 { 15563 SCIPhistoryIncInferenceSum(var->history, dir, weight); 15564 SCIPhistoryIncInferenceSum(var->historycrun, dir, weight); 15565 SCIPhistoryIncInferenceSum(stat->glbhistory, dir, weight); 15566 SCIPhistoryIncInferenceSum(stat->glbhistorycrun, dir, weight); 15567 15568 if( useValuehistory(var, value, set) ) 15569 { 15570 SCIP_HISTORY* history; 15571 15572 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) ); 15573 assert(history != NULL); 15574 15575 SCIPhistoryIncInferenceSum(history, dir, weight); 15576 } 15577 15578 return SCIP_OKAY; 15579 } 15580 case SCIP_VARSTATUS_FIXED: 15581 SCIPerrorMessage("cannot update inference counter of a fixed variable\n"); 15582 return SCIP_INVALIDDATA; 15583 15584 case SCIP_VARSTATUS_AGGREGATED: 15585 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar; 15586 15587 if( var->data.aggregate.scalar > 0.0 ) 15588 { 15589 SCIP_CALL( SCIPvarIncInferenceSum(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) ); 15590 } 15591 else 15592 { 15593 assert(var->data.aggregate.scalar < 0.0); 15594 SCIP_CALL( SCIPvarIncInferenceSum(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) ); 15595 } 15596 return SCIP_OKAY; 15597 15598 case SCIP_VARSTATUS_MULTAGGR: 15599 SCIPerrorMessage("cannot update inference counter of a multi-aggregated variable\n"); 15600 return SCIP_INVALIDDATA; 15601 15602 case SCIP_VARSTATUS_NEGATED: 15603 value = 1.0 - value; 15604 15605 SCIP_CALL( SCIPvarIncInferenceSum(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) ); 15606 return SCIP_OKAY; 15607 15608 default: 15609 SCIPerrorMessage("unknown variable status\n"); 15610 return SCIP_INVALIDDATA; 15611 } 15612 } 15613 15614 /** increases the cutoff sum of the variable by the given weight */ 15615 SCIP_RETCODE SCIPvarIncCutoffSum( 15616 SCIP_VAR* var, /**< problem variable */ 15617 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */ 15618 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */ 15619 SCIP_STAT* stat, /**< problem statistics */ 15620 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */ 15621 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */ 15622 SCIP_Real weight /**< weight of this update in cutoff score */ 15623 ) 15624 { 15625 assert(var != NULL); 15626 assert(stat != NULL); 15627 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15628 15629 /* check if history statistics should be collected for a variable */ 15630 if( !stat->collectvarhistory ) 15631 return SCIP_OKAY; 15632 15633 switch( SCIPvarGetStatus(var) ) 15634 { 15635 case SCIP_VARSTATUS_ORIGINAL: 15636 if( var->data.original.transvar == NULL ) 15637 { 15638 SCIPerrorMessage("cannot update cutoff sum of original untransformed variable\n"); 15639 return SCIP_INVALIDDATA; 15640 } 15641 SCIP_CALL( SCIPvarIncCutoffSum(var->data.original.transvar, blkmem, set, stat, dir, value, weight) ); 15642 return SCIP_OKAY; 15643 15644 case SCIP_VARSTATUS_LOOSE: 15645 case SCIP_VARSTATUS_COLUMN: 15646 { 15647 SCIPhistoryIncCutoffSum(var->history, dir, weight); 15648 SCIPhistoryIncCutoffSum(var->historycrun, dir, weight); 15649 SCIPhistoryIncCutoffSum(stat->glbhistory, dir, weight); 15650 SCIPhistoryIncCutoffSum(stat->glbhistorycrun, dir, weight); 15651 15652 if( useValuehistory(var, value, set) ) 15653 { 15654 SCIP_HISTORY* history; 15655 15656 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) ); 15657 assert(history != NULL); 15658 15659 SCIPhistoryIncCutoffSum(history, dir, weight); 15660 } 15661 15662 return SCIP_OKAY; 15663 } 15664 case SCIP_VARSTATUS_FIXED: 15665 SCIPerrorMessage("cannot update cutoff sum of a fixed variable\n"); 15666 return SCIP_INVALIDDATA; 15667 15668 case SCIP_VARSTATUS_AGGREGATED: 15669 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar; 15670 15671 if( var->data.aggregate.scalar > 0.0 ) 15672 { 15673 SCIP_CALL( SCIPvarIncCutoffSum(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) ); 15674 } 15675 else 15676 { 15677 assert(var->data.aggregate.scalar < 0.0); 15678 SCIP_CALL( SCIPvarIncCutoffSum(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) ); 15679 } 15680 return SCIP_OKAY; 15681 15682 case SCIP_VARSTATUS_MULTAGGR: 15683 SCIPerrorMessage("cannot update cutoff sum of a multi-aggregated variable\n"); 15684 return SCIP_INVALIDDATA; 15685 15686 case SCIP_VARSTATUS_NEGATED: 15687 value = 1.0 - value; 15688 15689 SCIP_CALL( SCIPvarIncCutoffSum(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) ); 15690 return SCIP_OKAY; 15691 15692 default: 15693 SCIPerrorMessage("unknown variable status\n"); 15694 return SCIP_INVALIDDATA; 15695 } 15696 } 15697 15698 /** returns the number of times, a bound of the variable was changed in given direction due to branching */ 15699 SCIP_Longint SCIPvarGetNBranchings( 15700 SCIP_VAR* var, /**< problem variable */ 15701 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15702 ) 15703 { 15704 assert(var != NULL); 15705 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15706 15707 switch( SCIPvarGetStatus(var) ) 15708 { 15709 case SCIP_VARSTATUS_ORIGINAL: 15710 if( var->data.original.transvar == NULL ) 15711 return 0; 15712 else 15713 return SCIPvarGetNBranchings(var->data.original.transvar, dir); 15714 15715 case SCIP_VARSTATUS_LOOSE: 15716 case SCIP_VARSTATUS_COLUMN: 15717 return SCIPhistoryGetNBranchings(var->history, dir); 15718 15719 case SCIP_VARSTATUS_FIXED: 15720 return 0; 15721 15722 case SCIP_VARSTATUS_AGGREGATED: 15723 if( var->data.aggregate.scalar > 0.0 ) 15724 return SCIPvarGetNBranchings(var->data.aggregate.var, dir); 15725 else 15726 return SCIPvarGetNBranchings(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 15727 15728 case SCIP_VARSTATUS_MULTAGGR: 15729 return 0; 15730 15731 case SCIP_VARSTATUS_NEGATED: 15732 return SCIPvarGetNBranchings(var->negatedvar, SCIPbranchdirOpposite(dir)); 15733 15734 default: 15735 SCIPerrorMessage("unknown variable status\n"); 15736 SCIPABORT(); 15737 return 0; /*lint !e527*/ 15738 } 15739 } 15740 15741 /** returns the number of times, a bound of the variable was changed in given direction due to branching 15742 * in the current run 15743 */ 15744 SCIP_Longint SCIPvarGetNBranchingsCurrentRun( 15745 SCIP_VAR* var, /**< problem variable */ 15746 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15747 ) 15748 { 15749 assert(var != NULL); 15750 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15751 15752 switch( SCIPvarGetStatus(var) ) 15753 { 15754 case SCIP_VARSTATUS_ORIGINAL: 15755 if( var->data.original.transvar == NULL ) 15756 return 0; 15757 else 15758 return SCIPvarGetNBranchingsCurrentRun(var->data.original.transvar, dir); 15759 15760 case SCIP_VARSTATUS_LOOSE: 15761 case SCIP_VARSTATUS_COLUMN: 15762 return SCIPhistoryGetNBranchings(var->historycrun, dir); 15763 15764 case SCIP_VARSTATUS_FIXED: 15765 return 0; 15766 15767 case SCIP_VARSTATUS_AGGREGATED: 15768 if( var->data.aggregate.scalar > 0.0 ) 15769 return SCIPvarGetNBranchingsCurrentRun(var->data.aggregate.var, dir); 15770 else 15771 return SCIPvarGetNBranchingsCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 15772 15773 case SCIP_VARSTATUS_MULTAGGR: 15774 return 0; 15775 15776 case SCIP_VARSTATUS_NEGATED: 15777 return SCIPvarGetNBranchingsCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir)); 15778 15779 default: 15780 SCIPerrorMessage("unknown variable status\n"); 15781 SCIPABORT(); 15782 return 0; /*lint !e527*/ 15783 } 15784 } 15785 15786 /** returns the average depth of bound changes in given direction due to branching on the variable */ 15787 SCIP_Real SCIPvarGetAvgBranchdepth( 15788 SCIP_VAR* var, /**< problem variable */ 15789 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15790 ) 15791 { 15792 assert(var != NULL); 15793 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15794 15795 switch( SCIPvarGetStatus(var) ) 15796 { 15797 case SCIP_VARSTATUS_ORIGINAL: 15798 if( var->data.original.transvar == NULL ) 15799 return 0.0; 15800 else 15801 return SCIPvarGetAvgBranchdepth(var->data.original.transvar, dir); 15802 15803 case SCIP_VARSTATUS_LOOSE: 15804 case SCIP_VARSTATUS_COLUMN: 15805 return SCIPhistoryGetAvgBranchdepth(var->history, dir); 15806 15807 case SCIP_VARSTATUS_FIXED: 15808 return 0.0; 15809 15810 case SCIP_VARSTATUS_AGGREGATED: 15811 if( var->data.aggregate.scalar > 0.0 ) 15812 return SCIPvarGetAvgBranchdepth(var->data.aggregate.var, dir); 15813 else 15814 return SCIPvarGetAvgBranchdepth(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 15815 15816 case SCIP_VARSTATUS_MULTAGGR: 15817 return 0.0; 15818 15819 case SCIP_VARSTATUS_NEGATED: 15820 return SCIPvarGetAvgBranchdepth(var->negatedvar, SCIPbranchdirOpposite(dir)); 15821 15822 default: 15823 SCIPerrorMessage("unknown variable status\n"); 15824 SCIPABORT(); 15825 return 0.0; /*lint !e527*/ 15826 } 15827 } 15828 15829 /** returns the average depth of bound changes in given direction due to branching on the variable 15830 * in the current run 15831 */ 15832 SCIP_Real SCIPvarGetAvgBranchdepthCurrentRun( 15833 SCIP_VAR* var, /**< problem variable */ 15834 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15835 ) 15836 { 15837 assert(var != NULL); 15838 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15839 15840 switch( SCIPvarGetStatus(var) ) 15841 { 15842 case SCIP_VARSTATUS_ORIGINAL: 15843 if( var->data.original.transvar == NULL ) 15844 return 0.0; 15845 else 15846 return SCIPvarGetAvgBranchdepthCurrentRun(var->data.original.transvar, dir); 15847 15848 case SCIP_VARSTATUS_LOOSE: 15849 case SCIP_VARSTATUS_COLUMN: 15850 return SCIPhistoryGetAvgBranchdepth(var->historycrun, dir); 15851 15852 case SCIP_VARSTATUS_FIXED: 15853 return 0.0; 15854 15855 case SCIP_VARSTATUS_AGGREGATED: 15856 if( var->data.aggregate.scalar > 0.0 ) 15857 return SCIPvarGetAvgBranchdepthCurrentRun(var->data.aggregate.var, dir); 15858 else 15859 return SCIPvarGetAvgBranchdepthCurrentRun(var->data.aggregate.var, 15860 dir == SCIP_BRANCHDIR_DOWNWARDS ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS); 15861 15862 case SCIP_VARSTATUS_MULTAGGR: 15863 return 0.0; 15864 15865 case SCIP_VARSTATUS_NEGATED: 15866 return SCIPvarGetAvgBranchdepthCurrentRun(var->negatedvar, 15867 dir == SCIP_BRANCHDIR_DOWNWARDS ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS); 15868 15869 default: 15870 SCIPerrorMessage("unknown variable status\n"); 15871 SCIPABORT(); 15872 return 0.0; /*lint !e527*/ 15873 } 15874 } 15875 15876 /** returns the variable's VSIDS score */ 15877 SCIP_Real SCIPvarGetVSIDS_rec( 15878 SCIP_VAR* var, /**< problem variable */ 15879 SCIP_STAT* stat, /**< problem statistics */ 15880 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15881 ) 15882 { 15883 assert(var != NULL); 15884 assert(stat != NULL); 15885 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15886 15887 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 15888 return SCIPvarGetVSIDS(var->data.original.transvar, stat, dir); 15889 15890 switch( SCIPvarGetStatus(var) ) 15891 { 15892 case SCIP_VARSTATUS_ORIGINAL: 15893 if( var->data.original.transvar == NULL ) 15894 return 0.0; 15895 else 15896 return SCIPvarGetVSIDS(var->data.original.transvar, stat, dir); 15897 15898 case SCIP_VARSTATUS_LOOSE: 15899 case SCIP_VARSTATUS_COLUMN: 15900 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); /* column case already handled in if condition above */ 15901 return SCIPhistoryGetVSIDS(var->history, dir)/stat->vsidsweight; 15902 15903 case SCIP_VARSTATUS_FIXED: 15904 return 0.0; 15905 15906 case SCIP_VARSTATUS_AGGREGATED: 15907 if( var->data.aggregate.scalar > 0.0 ) 15908 return SCIPvarGetVSIDS(var->data.aggregate.var, stat, dir); 15909 else 15910 /* coverity[overrun-local] */ 15911 return SCIPvarGetVSIDS(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir)); 15912 15913 case SCIP_VARSTATUS_MULTAGGR: 15914 return 0.0; 15915 15916 case SCIP_VARSTATUS_NEGATED: 15917 /* coverity[overrun-local] */ 15918 return SCIPvarGetVSIDS(var->negatedvar, stat, SCIPbranchdirOpposite(dir)); 15919 15920 default: 15921 SCIPerrorMessage("unknown variable status\n"); 15922 SCIPABORT(); 15923 return 0.0; /*lint !e527*/ 15924 } 15925 } 15926 15927 /** returns the variable's VSIDS score only using conflicts of the current run */ 15928 SCIP_Real SCIPvarGetVSIDSCurrentRun( 15929 SCIP_VAR* var, /**< problem variable */ 15930 SCIP_STAT* stat, /**< problem statistics */ 15931 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15932 ) 15933 { 15934 assert(var != NULL); 15935 assert(stat != NULL); 15936 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15937 15938 if( dir != SCIP_BRANCHDIR_DOWNWARDS && dir != SCIP_BRANCHDIR_UPWARDS ) 15939 { 15940 SCIPerrorMessage("invalid branching direction %d when asking for VSIDS value\n", dir); 15941 return SCIP_INVALID; 15942 } 15943 15944 switch( SCIPvarGetStatus(var) ) 15945 { 15946 case SCIP_VARSTATUS_ORIGINAL: 15947 if( var->data.original.transvar == NULL ) 15948 return 0.0; 15949 else 15950 return SCIPvarGetVSIDSCurrentRun(var->data.original.transvar, stat, dir); 15951 15952 case SCIP_VARSTATUS_LOOSE: 15953 case SCIP_VARSTATUS_COLUMN: 15954 return SCIPhistoryGetVSIDS(var->historycrun, dir)/stat->vsidsweight; 15955 15956 case SCIP_VARSTATUS_FIXED: 15957 return 0.0; 15958 15959 case SCIP_VARSTATUS_AGGREGATED: 15960 if( var->data.aggregate.scalar > 0.0 ) 15961 return SCIPvarGetVSIDSCurrentRun(var->data.aggregate.var, stat, dir); 15962 else 15963 return SCIPvarGetVSIDSCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir)); 15964 15965 case SCIP_VARSTATUS_MULTAGGR: 15966 return 0.0; 15967 15968 case SCIP_VARSTATUS_NEGATED: 15969 return SCIPvarGetVSIDSCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir)); 15970 15971 default: 15972 SCIPerrorMessage("unknown variable status\n"); 15973 SCIPABORT(); 15974 return 0.0; /*lint !e527*/ 15975 } 15976 } 15977 15978 /** returns the number of inferences branching on this variable in given direction triggered */ 15979 SCIP_Real SCIPvarGetInferenceSum( 15980 SCIP_VAR* var, /**< problem variable */ 15981 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 15982 ) 15983 { 15984 assert(var != NULL); 15985 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 15986 15987 switch( SCIPvarGetStatus(var) ) 15988 { 15989 case SCIP_VARSTATUS_ORIGINAL: 15990 if( var->data.original.transvar == NULL ) 15991 return 0.0; 15992 else 15993 return SCIPvarGetInferenceSum(var->data.original.transvar, dir); 15994 15995 case SCIP_VARSTATUS_LOOSE: 15996 case SCIP_VARSTATUS_COLUMN: 15997 return SCIPhistoryGetInferenceSum(var->history, dir); 15998 15999 case SCIP_VARSTATUS_FIXED: 16000 return 0.0; 16001 16002 case SCIP_VARSTATUS_AGGREGATED: 16003 if( var->data.aggregate.scalar > 0.0 ) 16004 return SCIPvarGetInferenceSum(var->data.aggregate.var, dir); 16005 else 16006 return SCIPvarGetInferenceSum(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 16007 16008 case SCIP_VARSTATUS_MULTAGGR: 16009 return 0.0; 16010 16011 case SCIP_VARSTATUS_NEGATED: 16012 return SCIPvarGetInferenceSum(var->negatedvar, SCIPbranchdirOpposite(dir)); 16013 16014 default: 16015 SCIPerrorMessage("unknown variable status\n"); 16016 SCIPABORT(); 16017 return 0.0; /*lint !e527*/ 16018 } 16019 } 16020 16021 /** returns the number of inferences branching on this variable in given direction triggered 16022 * in the current run 16023 */ 16024 SCIP_Real SCIPvarGetInferenceSumCurrentRun( 16025 SCIP_VAR* var, /**< problem variable */ 16026 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 16027 ) 16028 { 16029 assert(var != NULL); 16030 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 16031 16032 switch( SCIPvarGetStatus(var) ) 16033 { 16034 case SCIP_VARSTATUS_ORIGINAL: 16035 if( var->data.original.transvar == NULL ) 16036 return 0.0; 16037 else 16038 return SCIPvarGetInferenceSumCurrentRun(var->data.original.transvar, dir); 16039 16040 case SCIP_VARSTATUS_LOOSE: 16041 case SCIP_VARSTATUS_COLUMN: 16042 return SCIPhistoryGetInferenceSum(var->historycrun, dir); 16043 16044 case SCIP_VARSTATUS_FIXED: 16045 return 0.0; 16046 16047 case SCIP_VARSTATUS_AGGREGATED: 16048 if( var->data.aggregate.scalar > 0.0 ) 16049 return SCIPvarGetInferenceSumCurrentRun(var->data.aggregate.var, dir); 16050 else 16051 return SCIPvarGetInferenceSumCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 16052 16053 case SCIP_VARSTATUS_MULTAGGR: 16054 return 0.0; 16055 16056 case SCIP_VARSTATUS_NEGATED: 16057 return SCIPvarGetInferenceSumCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir)); 16058 16059 default: 16060 SCIPerrorMessage("unknown variable status\n"); 16061 SCIPABORT(); 16062 return 0.0; /*lint !e527*/ 16063 } 16064 } 16065 16066 /** returns the average number of inferences found after branching on the variable in given direction */ 16067 SCIP_Real SCIPvarGetAvgInferences( 16068 SCIP_VAR* var, /**< problem variable */ 16069 SCIP_STAT* stat, /**< problem statistics */ 16070 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 16071 ) 16072 { 16073 assert(var != NULL); 16074 assert(stat != NULL); 16075 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 16076 16077 switch( SCIPvarGetStatus(var) ) 16078 { 16079 case SCIP_VARSTATUS_ORIGINAL: 16080 if( var->data.original.transvar == NULL ) 16081 return SCIPhistoryGetAvgInferences(stat->glbhistory, dir); 16082 else 16083 return SCIPvarGetAvgInferences(var->data.original.transvar, stat, dir); 16084 16085 case SCIP_VARSTATUS_LOOSE: 16086 case SCIP_VARSTATUS_COLUMN: 16087 if( SCIPhistoryGetNBranchings(var->history, dir) > 0 ) 16088 return SCIPhistoryGetAvgInferences(var->history, dir); 16089 else 16090 { 16091 int nimpls; 16092 int ncliques; 16093 16094 nimpls = SCIPvarGetNImpls(var, dir == SCIP_BRANCHDIR_UPWARDS); 16095 ncliques = SCIPvarGetNCliques(var, dir == SCIP_BRANCHDIR_UPWARDS); 16096 return nimpls + ncliques > 0 ? (SCIP_Real)(nimpls + 2*ncliques) : SCIPhistoryGetAvgInferences(stat->glbhistory, dir); /*lint !e790*/ 16097 } 16098 16099 case SCIP_VARSTATUS_FIXED: 16100 return 0.0; 16101 16102 case SCIP_VARSTATUS_AGGREGATED: 16103 if( var->data.aggregate.scalar > 0.0 ) 16104 return SCIPvarGetAvgInferences(var->data.aggregate.var, stat, dir); 16105 else 16106 return SCIPvarGetAvgInferences(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir)); 16107 16108 case SCIP_VARSTATUS_MULTAGGR: 16109 return 0.0; 16110 16111 case SCIP_VARSTATUS_NEGATED: 16112 return SCIPvarGetAvgInferences(var->negatedvar, stat, SCIPbranchdirOpposite(dir)); 16113 16114 default: 16115 SCIPerrorMessage("unknown variable status\n"); 16116 SCIPABORT(); 16117 return 0.0; /*lint !e527*/ 16118 } 16119 } 16120 16121 /** returns the average number of inferences found after branching on the variable in given direction 16122 * in the current run 16123 */ 16124 SCIP_Real SCIPvarGetAvgInferencesCurrentRun( 16125 SCIP_VAR* var, /**< problem variable */ 16126 SCIP_STAT* stat, /**< problem statistics */ 16127 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 16128 ) 16129 { 16130 assert(var != NULL); 16131 assert(stat != NULL); 16132 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 16133 16134 switch( SCIPvarGetStatus(var) ) 16135 { 16136 case SCIP_VARSTATUS_ORIGINAL: 16137 if( var->data.original.transvar == NULL ) 16138 return SCIPhistoryGetAvgInferences(stat->glbhistorycrun, dir); 16139 else 16140 return SCIPvarGetAvgInferencesCurrentRun(var->data.original.transvar, stat, dir); 16141 16142 case SCIP_VARSTATUS_LOOSE: 16143 case SCIP_VARSTATUS_COLUMN: 16144 if( SCIPhistoryGetNBranchings(var->historycrun, dir) > 0 ) 16145 return SCIPhistoryGetAvgInferences(var->historycrun, dir); 16146 else 16147 { 16148 int nimpls; 16149 int ncliques; 16150 16151 nimpls = SCIPvarGetNImpls(var, dir == SCIP_BRANCHDIR_UPWARDS); 16152 ncliques = SCIPvarGetNCliques(var, dir == SCIP_BRANCHDIR_UPWARDS); 16153 return nimpls + ncliques > 0 ? (SCIP_Real)(nimpls + 2*ncliques) : SCIPhistoryGetAvgInferences(stat->glbhistorycrun, dir); /*lint !e790*/ 16154 } 16155 16156 case SCIP_VARSTATUS_FIXED: 16157 return 0.0; 16158 16159 case SCIP_VARSTATUS_AGGREGATED: 16160 if( var->data.aggregate.scalar > 0.0 ) 16161 return SCIPvarGetAvgInferencesCurrentRun(var->data.aggregate.var, stat, dir); 16162 else 16163 return SCIPvarGetAvgInferencesCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir)); 16164 16165 case SCIP_VARSTATUS_MULTAGGR: 16166 return 0.0; 16167 16168 case SCIP_VARSTATUS_NEGATED: 16169 return SCIPvarGetAvgInferencesCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir)); 16170 16171 default: 16172 SCIPerrorMessage("unknown variable status\n"); 16173 SCIPABORT(); 16174 return 0.0; /*lint !e527*/ 16175 } 16176 } 16177 16178 /** returns the number of cutoffs branching on this variable in given direction produced */ 16179 SCIP_Real SCIPvarGetCutoffSum( 16180 SCIP_VAR* var, /**< problem variable */ 16181 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 16182 ) 16183 { 16184 assert(var != NULL); 16185 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 16186 16187 switch( SCIPvarGetStatus(var) ) 16188 { 16189 case SCIP_VARSTATUS_ORIGINAL: 16190 if( var->data.original.transvar == NULL ) 16191 return 0; 16192 else 16193 return SCIPvarGetCutoffSum(var->data.original.transvar, dir); 16194 16195 case SCIP_VARSTATUS_LOOSE: 16196 case SCIP_VARSTATUS_COLUMN: 16197 return SCIPhistoryGetCutoffSum(var->history, dir); 16198 16199 case SCIP_VARSTATUS_FIXED: 16200 return 0; 16201 16202 case SCIP_VARSTATUS_AGGREGATED: 16203 if( var->data.aggregate.scalar > 0.0 ) 16204 return SCIPvarGetCutoffSum(var->data.aggregate.var, dir); 16205 else 16206 return SCIPvarGetCutoffSum(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 16207 16208 case SCIP_VARSTATUS_MULTAGGR: 16209 return 0; 16210 16211 case SCIP_VARSTATUS_NEGATED: 16212 return SCIPvarGetCutoffSum(var->negatedvar, SCIPbranchdirOpposite(dir)); 16213 16214 default: 16215 SCIPerrorMessage("unknown variable status\n"); 16216 SCIPABORT(); 16217 return 0; /*lint !e527*/ 16218 } 16219 } 16220 16221 /** returns the number of cutoffs branching on this variable in given direction produced in the current run */ 16222 SCIP_Real SCIPvarGetCutoffSumCurrentRun( 16223 SCIP_VAR* var, /**< problem variable */ 16224 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 16225 ) 16226 { 16227 assert(var != NULL); 16228 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 16229 16230 switch( SCIPvarGetStatus(var) ) 16231 { 16232 case SCIP_VARSTATUS_ORIGINAL: 16233 if( var->data.original.transvar == NULL ) 16234 return 0; 16235 else 16236 return SCIPvarGetCutoffSumCurrentRun(var->data.original.transvar, dir); 16237 16238 case SCIP_VARSTATUS_LOOSE: 16239 case SCIP_VARSTATUS_COLUMN: 16240 return SCIPhistoryGetCutoffSum(var->historycrun, dir); 16241 16242 case SCIP_VARSTATUS_FIXED: 16243 return 0; 16244 16245 case SCIP_VARSTATUS_AGGREGATED: 16246 if( var->data.aggregate.scalar > 0.0 ) 16247 return SCIPvarGetCutoffSumCurrentRun(var->data.aggregate.var, dir); 16248 else 16249 return SCIPvarGetCutoffSumCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir)); 16250 16251 case SCIP_VARSTATUS_MULTAGGR: 16252 return 0; 16253 16254 case SCIP_VARSTATUS_NEGATED: 16255 return SCIPvarGetCutoffSumCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir)); 16256 16257 default: 16258 SCIPerrorMessage("unknown variable status\n"); 16259 SCIPABORT(); 16260 return 0; /*lint !e527*/ 16261 } 16262 } 16263 16264 /** returns the average number of cutoffs found after branching on the variable in given direction */ 16265 SCIP_Real SCIPvarGetAvgCutoffs( 16266 SCIP_VAR* var, /**< problem variable */ 16267 SCIP_STAT* stat, /**< problem statistics */ 16268 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 16269 ) 16270 { 16271 assert(var != NULL); 16272 assert(stat != NULL); 16273 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 16274 16275 switch( SCIPvarGetStatus(var) ) 16276 { 16277 case SCIP_VARSTATUS_ORIGINAL: 16278 if( var->data.original.transvar == NULL ) 16279 return SCIPhistoryGetAvgCutoffs(stat->glbhistory, dir); 16280 else 16281 return SCIPvarGetAvgCutoffs(var->data.original.transvar, stat, dir); 16282 16283 case SCIP_VARSTATUS_LOOSE: 16284 case SCIP_VARSTATUS_COLUMN: 16285 return SCIPhistoryGetNBranchings(var->history, dir) > 0 16286 ? SCIPhistoryGetAvgCutoffs(var->history, dir) 16287 : SCIPhistoryGetAvgCutoffs(stat->glbhistory, dir); 16288 16289 case SCIP_VARSTATUS_FIXED: 16290 return 0.0; 16291 16292 case SCIP_VARSTATUS_AGGREGATED: 16293 if( var->data.aggregate.scalar > 0.0 ) 16294 return SCIPvarGetAvgCutoffs(var->data.aggregate.var, stat, dir); 16295 else 16296 return SCIPvarGetAvgCutoffs(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir)); 16297 16298 case SCIP_VARSTATUS_MULTAGGR: 16299 return 0.0; 16300 16301 case SCIP_VARSTATUS_NEGATED: 16302 return SCIPvarGetAvgCutoffs(var->negatedvar, stat, SCIPbranchdirOpposite(dir)); 16303 16304 default: 16305 SCIPerrorMessage("unknown variable status\n"); 16306 SCIPABORT(); 16307 return 0.0; /*lint !e527*/ 16308 } 16309 } 16310 16311 /** returns the average number of cutoffs found after branching on the variable in given direction in the current run */ 16312 SCIP_Real SCIPvarGetAvgCutoffsCurrentRun( 16313 SCIP_VAR* var, /**< problem variable */ 16314 SCIP_STAT* stat, /**< problem statistics */ 16315 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 16316 ) 16317 { 16318 assert(var != NULL); 16319 assert(stat != NULL); 16320 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS); 16321 16322 switch( SCIPvarGetStatus(var) ) 16323 { 16324 case SCIP_VARSTATUS_ORIGINAL: 16325 if( var->data.original.transvar == NULL ) 16326 return SCIPhistoryGetAvgCutoffs(stat->glbhistorycrun, dir); 16327 else 16328 return SCIPvarGetAvgCutoffsCurrentRun(var->data.original.transvar, stat, dir); 16329 16330 case SCIP_VARSTATUS_LOOSE: 16331 case SCIP_VARSTATUS_COLUMN: 16332 return SCIPhistoryGetNBranchings(var->historycrun, dir) > 0 16333 ? SCIPhistoryGetAvgCutoffs(var->historycrun, dir) 16334 : SCIPhistoryGetAvgCutoffs(stat->glbhistorycrun, dir); 16335 16336 case SCIP_VARSTATUS_FIXED: 16337 return 0.0; 16338 16339 case SCIP_VARSTATUS_AGGREGATED: 16340 if( var->data.aggregate.scalar > 0.0 ) 16341 return SCIPvarGetAvgCutoffsCurrentRun(var->data.aggregate.var, stat, dir); 16342 else 16343 return SCIPvarGetAvgCutoffsCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir)); 16344 16345 case SCIP_VARSTATUS_MULTAGGR: 16346 return 0.0; 16347 16348 case SCIP_VARSTATUS_NEGATED: 16349 return SCIPvarGetAvgCutoffsCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir)); 16350 16351 default: 16352 SCIPerrorMessage("unknown variable status\n"); 16353 SCIPABORT(); 16354 return 0.0; /*lint !e527*/ 16355 } 16356 } 16357 16358 /** returns the variable's average GMI efficacy score value generated from simplex tableau rows of this variable */ 16359 SCIP_Real SCIPvarGetAvgGMIScore( 16360 SCIP_VAR* var, /**< problem variable */ 16361 SCIP_STAT* stat /**< problem statistics */ 16362 ) 16363 { 16364 assert(var != NULL); 16365 assert(stat != NULL); 16366 16367 switch( SCIPvarGetStatus(var) ) 16368 { 16369 case SCIP_VARSTATUS_ORIGINAL: 16370 if( var->data.original.transvar == NULL ) 16371 return 0.0; 16372 else 16373 return SCIPvarGetAvgGMIScore(var->data.original.transvar, stat); 16374 16375 case SCIP_VARSTATUS_LOOSE: 16376 case SCIP_VARSTATUS_COLUMN: 16377 return SCIPhistoryGetAvgGMIeff(var->history); 16378 16379 case SCIP_VARSTATUS_FIXED: 16380 return 0.0; 16381 16382 case SCIP_VARSTATUS_AGGREGATED: 16383 return SCIPvarGetAvgGMIScore(var->data.aggregate.var, stat); 16384 16385 case SCIP_VARSTATUS_MULTAGGR: 16386 return 0.0; 16387 16388 case SCIP_VARSTATUS_NEGATED: 16389 return SCIPvarGetAvgGMIScore(var->negatedvar, stat); 16390 16391 default: 16392 SCIPerrorMessage("unknown variable status\n"); 16393 SCIPABORT(); 16394 return 0.0; /*lint !e527*/ 16395 } 16396 } 16397 16398 /** increase the variable's GMI efficacy scores generated from simplex tableau rows of this variable */ 16399 SCIP_RETCODE SCIPvarIncGMIeffSum( 16400 SCIP_VAR* var, /**< problem variable */ 16401 SCIP_STAT* stat, /**< problem statistics */ 16402 SCIP_Real gmieff /**< efficacy of last GMI cut produced when variable was frac and basic */ 16403 ) 16404 { 16405 assert(var != NULL); 16406 assert(stat != NULL); 16407 assert(gmieff >= 0); 16408 16409 switch( SCIPvarGetStatus(var) ) 16410 { 16411 case SCIP_VARSTATUS_ORIGINAL: 16412 if( var->data.original.transvar != NULL ) 16413 SCIP_CALL( SCIPvarIncGMIeffSum(var->data.original.transvar, stat, gmieff) ); 16414 return SCIP_OKAY; 16415 16416 case SCIP_VARSTATUS_LOOSE: 16417 case SCIP_VARSTATUS_COLUMN: 16418 SCIPhistoryIncGMIeffSum(var->history, gmieff); 16419 return SCIP_OKAY; 16420 16421 case SCIP_VARSTATUS_FIXED: 16422 return SCIP_INVALIDDATA; 16423 16424 case SCIP_VARSTATUS_AGGREGATED: 16425 SCIP_CALL( SCIPvarIncGMIeffSum(var->data.aggregate.var, stat, gmieff) ); 16426 return SCIP_OKAY; 16427 16428 case SCIP_VARSTATUS_NEGATED: 16429 SCIP_CALL( SCIPvarIncGMIeffSum(var->negatedvar, stat, gmieff) ); 16430 return SCIP_OKAY; 16431 16432 case SCIP_VARSTATUS_MULTAGGR: 16433 return SCIP_INVALIDDATA; 16434 16435 default: 16436 SCIPerrorMessage("unknown variable status\n"); 16437 SCIPABORT(); 16438 return SCIP_INVALIDDATA; /*lint !e527*/ 16439 } 16440 } 16441 16442 /** returns the variable's last GMI efficacy score value generated from a simplex tableau row of this variable */ 16443 SCIP_Real SCIPvarGetLastGMIScore( 16444 SCIP_VAR* var, /**< problem variable */ 16445 SCIP_STAT* stat /**< problem statistics */ 16446 ) 16447 { 16448 assert(var != NULL); 16449 assert(stat != NULL); 16450 16451 switch( SCIPvarGetStatus(var) ) 16452 { 16453 case SCIP_VARSTATUS_ORIGINAL: 16454 if( var->data.original.transvar != NULL ) 16455 return SCIPvarGetLastGMIScore(var->data.original.transvar, stat); 16456 return 0.0; 16457 16458 case SCIP_VARSTATUS_LOOSE: 16459 case SCIP_VARSTATUS_COLUMN: 16460 return SCIPhistoryGetLastGMIeff(var->history); 16461 16462 case SCIP_VARSTATUS_FIXED: 16463 return 0.0; 16464 16465 case SCIP_VARSTATUS_AGGREGATED: 16466 return SCIPvarGetLastGMIScore(var->data.aggregate.var, stat); 16467 16468 case SCIP_VARSTATUS_MULTAGGR: 16469 return 0.0; 16470 16471 case SCIP_VARSTATUS_NEGATED: 16472 return SCIPvarGetLastGMIScore(var->negatedvar, stat); 16473 16474 default: 16475 SCIPerrorMessage("unknown variable status\n"); 16476 SCIPABORT(); 16477 return 0.0; /*lint !e527*/ 16478 } 16479 } 16480 16481 16482 /** sets the variable's last GMI efficacy score value generated from a simplex tableau row of this variable */ 16483 SCIP_RETCODE SCIPvarSetLastGMIScore( 16484 SCIP_VAR* var, /**< problem variable */ 16485 SCIP_STAT* stat, /**< problem statistics */ 16486 SCIP_Real gmieff /**< efficacy of last GMI cut produced when variable was frac and basic */ 16487 ) 16488 { 16489 assert(var != NULL); 16490 assert(stat != NULL); 16491 assert(gmieff >= 0); 16492 16493 switch( SCIPvarGetStatus(var) ) 16494 { 16495 case SCIP_VARSTATUS_ORIGINAL: 16496 if( var->data.original.transvar != NULL ) 16497 SCIP_CALL( SCIPvarSetLastGMIScore(var->data.original.transvar, stat, gmieff) ); 16498 return SCIP_OKAY; 16499 16500 case SCIP_VARSTATUS_LOOSE: 16501 case SCIP_VARSTATUS_COLUMN: 16502 SCIPhistorySetLastGMIeff(var->history, gmieff); 16503 return SCIP_OKAY; 16504 16505 case SCIP_VARSTATUS_FIXED: 16506 return SCIP_INVALIDDATA; 16507 16508 case SCIP_VARSTATUS_AGGREGATED: 16509 SCIP_CALL( SCIPvarSetLastGMIScore(var->data.aggregate.var, stat, gmieff) ); 16510 return SCIP_OKAY; 16511 16512 case SCIP_VARSTATUS_NEGATED: 16513 SCIP_CALL( SCIPvarSetLastGMIScore(var->negatedvar, stat, gmieff) ); 16514 return SCIP_OKAY; 16515 16516 case SCIP_VARSTATUS_MULTAGGR: 16517 return SCIP_INVALIDDATA; 16518 16519 default: 16520 SCIPerrorMessage("unknown variable status\n"); 16521 SCIPABORT(); 16522 return SCIP_INVALIDDATA; /*lint !e527*/ 16523 } 16524 } 16525 16526 16527 16528 /* 16529 * information methods for bound changes 16530 */ 16531 16532 /** creates an artificial bound change information object with depth = INT_MAX and pos = -1 */ 16533 SCIP_RETCODE SCIPbdchginfoCreate( 16534 SCIP_BDCHGINFO** bdchginfo, /**< pointer to store bound change information */ 16535 BMS_BLKMEM* blkmem, /**< block memory */ 16536 SCIP_VAR* var, /**< active variable that changed the bounds */ 16537 SCIP_BOUNDTYPE boundtype, /**< type of bound for var: lower or upper bound */ 16538 SCIP_Real oldbound, /**< old value for bound */ 16539 SCIP_Real newbound /**< new value for bound */ 16540 ) 16541 { 16542 assert(bdchginfo != NULL); 16543 16544 SCIP_ALLOC( BMSallocBlockMemory(blkmem, bdchginfo) ); 16545 (*bdchginfo)->oldbound = oldbound; 16546 (*bdchginfo)->newbound = newbound; 16547 (*bdchginfo)->var = var; 16548 (*bdchginfo)->inferencedata.var = var; 16549 (*bdchginfo)->inferencedata.reason.prop = NULL; 16550 (*bdchginfo)->inferencedata.info = 0; 16551 (*bdchginfo)->bdchgidx.depth = INT_MAX; 16552 (*bdchginfo)->bdchgidx.pos = -1; 16553 (*bdchginfo)->pos = 0; 16554 (*bdchginfo)->boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/ 16555 (*bdchginfo)->boundtype = boundtype; /*lint !e641*/ 16556 (*bdchginfo)->inferboundtype = boundtype; /*lint !e641*/ 16557 (*bdchginfo)->redundant = FALSE; 16558 16559 return SCIP_OKAY; 16560 } 16561 16562 /** frees a bound change information object */ 16563 void SCIPbdchginfoFree( 16564 SCIP_BDCHGINFO** bdchginfo, /**< pointer to store bound change information */ 16565 BMS_BLKMEM* blkmem /**< block memory */ 16566 ) 16567 { 16568 assert(bdchginfo != NULL); 16569 16570 BMSfreeBlockMemory(blkmem, bdchginfo); 16571 } 16572 16573 /** returns the bound change information for the last lower bound change on given active problem variable before or 16574 * after the bound change with the given index was applied; 16575 * returns NULL, if no change to the lower bound was applied up to this point of time 16576 */ 16577 SCIP_BDCHGINFO* SCIPvarGetLbchgInfo( 16578 SCIP_VAR* var, /**< active problem variable */ 16579 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */ 16580 SCIP_Bool after /**< should the bound change with given index be included? */ 16581 ) 16582 { 16583 int i; 16584 16585 assert(var != NULL); 16586 assert(SCIPvarIsActive(var)); 16587 16588 /* search the correct bound change information for the given bound change index */ 16589 if( after ) 16590 { 16591 for( i = var->nlbchginfos-1; i >= 0; --i ) 16592 { 16593 assert(var->lbchginfos[i].var == var); 16594 assert((SCIP_BOUNDTYPE)var->lbchginfos[i].boundtype == SCIP_BOUNDTYPE_LOWER); 16595 assert(var->lbchginfos[i].pos == i); 16596 16597 /* if we reached the (due to global bounds) redundant bound changes, return NULL */ 16598 if( var->lbchginfos[i].redundant ) 16599 return NULL; 16600 assert(var->lbchginfos[i].oldbound < var->lbchginfos[i].newbound); 16601 16602 /* if we reached the bound change index, return the current bound change info */ 16603 if( !SCIPbdchgidxIsEarlier(bdchgidx, &var->lbchginfos[i].bdchgidx) ) 16604 return &var->lbchginfos[i]; 16605 } 16606 } 16607 else 16608 { 16609 for( i = var->nlbchginfos-1; i >= 0; --i ) 16610 { 16611 assert(var->lbchginfos[i].var == var); 16612 assert((SCIP_BOUNDTYPE)var->lbchginfos[i].boundtype == SCIP_BOUNDTYPE_LOWER); 16613 assert(var->lbchginfos[i].pos == i); 16614 16615 /* if we reached the (due to global bounds) redundant bound changes, return NULL */ 16616 if( var->lbchginfos[i].redundant ) 16617 return NULL; 16618 assert(var->lbchginfos[i].oldbound < var->lbchginfos[i].newbound); 16619 16620 /* if we reached the bound change index, return the current bound change info */ 16621 if( SCIPbdchgidxIsEarlier(&var->lbchginfos[i].bdchgidx, bdchgidx) ) 16622 return &var->lbchginfos[i]; 16623 } 16624 } 16625 16626 return NULL; 16627 } 16628 16629 /** returns the bound change information for the last upper bound change on given active problem variable before or 16630 * after the bound change with the given index was applied; 16631 * returns NULL, if no change to the upper bound was applied up to this point of time 16632 */ 16633 SCIP_BDCHGINFO* SCIPvarGetUbchgInfo( 16634 SCIP_VAR* var, /**< active problem variable */ 16635 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */ 16636 SCIP_Bool after /**< should the bound change with given index be included? */ 16637 ) 16638 { 16639 int i; 16640 16641 assert(var != NULL); 16642 assert(SCIPvarIsActive(var)); 16643 16644 /* search the correct bound change information for the given bound change index */ 16645 if( after ) 16646 { 16647 for( i = var->nubchginfos-1; i >= 0; --i ) 16648 { 16649 assert(var->ubchginfos[i].var == var); 16650 assert((SCIP_BOUNDTYPE)var->ubchginfos[i].boundtype == SCIP_BOUNDTYPE_UPPER); 16651 assert(var->ubchginfos[i].pos == i); 16652 16653 /* if we reached the (due to global bounds) redundant bound changes, return NULL */ 16654 if( var->ubchginfos[i].redundant ) 16655 return NULL; 16656 assert(var->ubchginfos[i].oldbound > var->ubchginfos[i].newbound); 16657 16658 /* if we reached the bound change index, return the current bound change info */ 16659 if( !SCIPbdchgidxIsEarlier(bdchgidx, &var->ubchginfos[i].bdchgidx) ) 16660 return &var->ubchginfos[i]; 16661 } 16662 } 16663 else 16664 { 16665 for( i = var->nubchginfos-1; i >= 0; --i ) 16666 { 16667 assert(var->ubchginfos[i].var == var); 16668 assert((SCIP_BOUNDTYPE)var->ubchginfos[i].boundtype == SCIP_BOUNDTYPE_UPPER); 16669 assert(var->ubchginfos[i].pos == i); 16670 16671 /* if we reached the (due to global bounds) redundant bound changes, return NULL */ 16672 if( var->ubchginfos[i].redundant ) 16673 return NULL; 16674 assert(var->ubchginfos[i].oldbound > var->ubchginfos[i].newbound); 16675 16676 /* if we reached the bound change index, return the current bound change info */ 16677 if( SCIPbdchgidxIsEarlier(&var->ubchginfos[i].bdchgidx, bdchgidx) ) 16678 return &var->ubchginfos[i]; 16679 } 16680 } 16681 16682 return NULL; 16683 } 16684 16685 /** returns the bound change information for the last lower or upper bound change on given active problem variable 16686 * before or after the bound change with the given index was applied; 16687 * returns NULL, if no change to the lower/upper bound was applied up to this point of time 16688 */ 16689 SCIP_BDCHGINFO* SCIPvarGetBdchgInfo( 16690 SCIP_VAR* var, /**< active problem variable */ 16691 SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */ 16692 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */ 16693 SCIP_Bool after /**< should the bound change with given index be included? */ 16694 ) 16695 { 16696 if( boundtype == SCIP_BOUNDTYPE_LOWER ) 16697 return SCIPvarGetLbchgInfo(var, bdchgidx, after); 16698 else 16699 { 16700 assert(boundtype == SCIP_BOUNDTYPE_UPPER); 16701 return SCIPvarGetUbchgInfo(var, bdchgidx, after); 16702 } 16703 } 16704 16705 /** returns lower bound of variable directly before or after the bound change given by the bound change index 16706 * was applied 16707 * 16708 * @deprecated Please use SCIPgetVarLbAtIndex() 16709 */ 16710 SCIP_Real SCIPvarGetLbAtIndex( 16711 SCIP_VAR* var, /**< problem variable */ 16712 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */ 16713 SCIP_Bool after /**< should the bound change with given index be included? */ 16714 ) 16715 { 16716 SCIP_VARSTATUS varstatus; 16717 assert(var != NULL); 16718 16719 varstatus = SCIPvarGetStatus(var); 16720 16721 /* get bounds of attached variables */ 16722 switch( varstatus ) 16723 { 16724 case SCIP_VARSTATUS_ORIGINAL: 16725 assert(var->data.original.transvar != NULL); 16726 return SCIPvarGetLbAtIndex(var->data.original.transvar, bdchgidx, after); 16727 16728 case SCIP_VARSTATUS_LOOSE: 16729 case SCIP_VARSTATUS_COLUMN: 16730 if( bdchgidx == NULL ) 16731 return SCIPvarGetLbLocal(var); 16732 else 16733 { 16734 SCIP_BDCHGINFO* bdchginfo; 16735 16736 bdchginfo = SCIPvarGetLbchgInfo(var, bdchgidx, after); 16737 if( bdchginfo != NULL ) 16738 return SCIPbdchginfoGetNewbound(bdchginfo); 16739 else 16740 return var->glbdom.lb; 16741 } 16742 case SCIP_VARSTATUS_FIXED: 16743 return var->glbdom.lb; 16744 16745 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 16746 assert(var->data.aggregate.var != NULL); 16747 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the 16748 * corresponding infinity value instead of performing an arithmetical transformation (compare method 16749 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is 16750 * (or is called by) a public interface method; instead, we only assert that values are finite 16751 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false 16752 * positives and negatives if the parameter <numerics/infinity> is modified by the user 16753 */ 16754 if( var->data.aggregate.scalar > 0.0 ) 16755 { 16756 /* a > 0 -> get lower bound of y */ 16757 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY); 16758 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY); 16759 return var->data.aggregate.scalar * SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) 16760 + var->data.aggregate.constant; 16761 } 16762 else if( var->data.aggregate.scalar < 0.0 ) 16763 { 16764 /* a < 0 -> get upper bound of y */ 16765 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY); 16766 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY); 16767 return var->data.aggregate.scalar * SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) 16768 + var->data.aggregate.constant; 16769 } 16770 else 16771 { 16772 SCIPerrorMessage("scalar is zero in aggregation\n"); 16773 SCIPABORT(); 16774 return SCIP_INVALID; /*lint !e527*/ 16775 } 16776 16777 case SCIP_VARSTATUS_MULTAGGR: 16778 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */ 16779 if ( var->data.multaggr.nvars == 1 ) 16780 { 16781 assert(var->data.multaggr.vars != NULL); 16782 assert(var->data.multaggr.scalars != NULL); 16783 assert(var->data.multaggr.vars[0] != NULL); 16784 16785 if( var->data.multaggr.scalars[0] > 0.0 ) 16786 { 16787 /* a > 0 -> get lower bound of y */ 16788 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY); 16789 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY); 16790 return var->data.multaggr.scalars[0] * SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) 16791 + var->data.multaggr.constant; 16792 } 16793 else if( var->data.multaggr.scalars[0] < 0.0 ) 16794 { 16795 /* a < 0 -> get upper bound of y */ 16796 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY); 16797 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY); 16798 return var->data.multaggr.scalars[0] * SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) 16799 + var->data.multaggr.constant; 16800 } 16801 else 16802 { 16803 SCIPerrorMessage("scalar is zero in multi-aggregation\n"); 16804 SCIPABORT(); 16805 return SCIP_INVALID; /*lint !e527*/ 16806 } 16807 } 16808 SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n"); 16809 SCIPABORT(); 16810 return SCIP_INVALID; /*lint !e527*/ 16811 16812 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 16813 assert(var->negatedvar != NULL); 16814 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 16815 assert(var->negatedvar->negatedvar == var); 16816 return var->data.negate.constant - SCIPvarGetUbAtIndex(var->negatedvar, bdchgidx, after); 16817 default: 16818 SCIPerrorMessage("unknown variable status\n"); 16819 SCIPABORT(); 16820 return SCIP_INVALID; /*lint !e527*/ 16821 } 16822 } 16823 16824 /** returns upper bound of variable directly before or after the bound change given by the bound change index 16825 * was applied 16826 * 16827 * @deprecated Please use SCIPgetVarUbAtIndex() 16828 */ 16829 SCIP_Real SCIPvarGetUbAtIndex( 16830 SCIP_VAR* var, /**< problem variable */ 16831 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */ 16832 SCIP_Bool after /**< should the bound change with given index be included? */ 16833 ) 16834 { 16835 SCIP_VARSTATUS varstatus; 16836 assert(var != NULL); 16837 16838 varstatus = SCIPvarGetStatus(var); 16839 16840 /* get bounds of attached variables */ 16841 switch( varstatus ) 16842 { 16843 case SCIP_VARSTATUS_ORIGINAL: 16844 assert(var->data.original.transvar != NULL); 16845 return SCIPvarGetUbAtIndex(var->data.original.transvar, bdchgidx, after); 16846 16847 case SCIP_VARSTATUS_COLUMN: 16848 case SCIP_VARSTATUS_LOOSE: 16849 if( bdchgidx == NULL ) 16850 return SCIPvarGetUbLocal(var); 16851 else 16852 { 16853 SCIP_BDCHGINFO* bdchginfo; 16854 16855 bdchginfo = SCIPvarGetUbchgInfo(var, bdchgidx, after); 16856 if( bdchginfo != NULL ) 16857 return SCIPbdchginfoGetNewbound(bdchginfo); 16858 else 16859 return var->glbdom.ub; 16860 } 16861 16862 case SCIP_VARSTATUS_FIXED: 16863 return var->glbdom.ub; 16864 16865 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */ 16866 assert(var->data.aggregate.var != NULL); 16867 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the 16868 * corresponding infinity value instead of performing an arithmetical transformation (compare method 16869 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is 16870 * (or is called by) a public interface method; instead, we only assert that values are finite 16871 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false 16872 * positives and negatives if the parameter <numerics/infinity> is modified by the user 16873 */ 16874 if( var->data.aggregate.scalar > 0.0 ) 16875 { 16876 /* a > 0 -> get lower bound of y */ 16877 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY); 16878 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY); 16879 return var->data.aggregate.scalar * SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) 16880 + var->data.aggregate.constant; 16881 } 16882 else if( var->data.aggregate.scalar < 0.0 ) 16883 { 16884 /* a < 0 -> get upper bound of y */ 16885 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY); 16886 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY); 16887 return var->data.aggregate.scalar * SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) 16888 + var->data.aggregate.constant; 16889 } 16890 else 16891 { 16892 SCIPerrorMessage("scalar is zero in aggregation\n"); 16893 SCIPABORT(); 16894 return SCIP_INVALID; /*lint !e527*/ 16895 } 16896 16897 case SCIP_VARSTATUS_MULTAGGR: 16898 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */ 16899 if ( var->data.multaggr.nvars == 1 ) 16900 { 16901 assert(var->data.multaggr.vars != NULL); 16902 assert(var->data.multaggr.scalars != NULL); 16903 assert(var->data.multaggr.vars[0] != NULL); 16904 16905 if( var->data.multaggr.scalars[0] > 0.0 ) 16906 { 16907 /* a > 0 -> get lower bound of y */ 16908 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY); 16909 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY); 16910 return var->data.multaggr.scalars[0] * SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) 16911 + var->data.multaggr.constant; 16912 } 16913 else if( var->data.multaggr.scalars[0] < 0.0 ) 16914 { 16915 /* a < 0 -> get upper bound of y */ 16916 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY); 16917 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY); 16918 return var->data.multaggr.scalars[0] * SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) 16919 + var->data.multaggr.constant; 16920 } 16921 else 16922 { 16923 SCIPerrorMessage("scalar is zero in multi-aggregation\n"); 16924 SCIPABORT(); 16925 return SCIP_INVALID; /*lint !e527*/ 16926 } 16927 } 16928 SCIPerrorMessage("cannot get the bounds of a multiple aggregated variable.\n"); 16929 SCIPABORT(); 16930 return SCIP_INVALID; /*lint !e527*/ 16931 16932 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */ 16933 assert(var->negatedvar != NULL); 16934 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED); 16935 assert(var->negatedvar->negatedvar == var); 16936 return var->data.negate.constant - SCIPvarGetLbAtIndex(var->negatedvar, bdchgidx, after); 16937 16938 default: 16939 SCIPerrorMessage("unknown variable status\n"); 16940 SCIPABORT(); 16941 return SCIP_INVALID; /*lint !e527*/ 16942 } 16943 } 16944 16945 /** returns lower or upper bound of variable directly before or after the bound change given by the bound change index 16946 * was applied 16947 * 16948 * @deprecated Please use SCIPgetVarBdAtIndex() 16949 */ 16950 SCIP_Real SCIPvarGetBdAtIndex( 16951 SCIP_VAR* var, /**< problem variable */ 16952 SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */ 16953 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */ 16954 SCIP_Bool after /**< should the bound change with given index be included? */ 16955 ) 16956 { 16957 if( boundtype == SCIP_BOUNDTYPE_LOWER ) 16958 return SCIPvarGetLbAtIndex(var, bdchgidx, after); 16959 else 16960 { 16961 assert(boundtype == SCIP_BOUNDTYPE_UPPER); 16962 return SCIPvarGetUbAtIndex(var, bdchgidx, after); 16963 } 16964 } 16965 16966 /** returns whether the binary variable was fixed at the time given by the bound change index 16967 * 16968 * @deprecated Please use SCIPgetVarWasFixedAtIndex() 16969 */ 16970 SCIP_Bool SCIPvarWasFixedAtIndex( 16971 SCIP_VAR* var, /**< problem variable */ 16972 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */ 16973 SCIP_Bool after /**< should the bound change with given index be included? */ 16974 ) 16975 { 16976 assert(var != NULL); 16977 assert(SCIPvarIsBinary(var)); 16978 16979 /* check the current bounds first in order to decide at which bound change information we have to look 16980 * (which is expensive because we have to follow the aggregation tree to the active variable) 16981 */ 16982 return ((SCIPvarGetLbLocal(var) > 0.5 && SCIPvarGetLbAtIndex(var, bdchgidx, after) > 0.5) 16983 || (SCIPvarGetUbLocal(var) < 0.5 && SCIPvarGetUbAtIndex(var, bdchgidx, after) < 0.5)); 16984 } 16985 16986 /** bound change index representing the initial time before any bound changes took place */ 16987 static SCIP_BDCHGIDX initbdchgidx = {-2, 0}; 16988 16989 /** bound change index representing the presolving stage */ 16990 static SCIP_BDCHGIDX presolvebdchgidx = {-1, 0}; 16991 16992 /** returns the last bound change index, at which the bounds of the given variable were tightened */ 16993 SCIP_BDCHGIDX* SCIPvarGetLastBdchgIndex( 16994 SCIP_VAR* var /**< problem variable */ 16995 ) 16996 { 16997 SCIP_BDCHGIDX* lbchgidx; 16998 SCIP_BDCHGIDX* ubchgidx; 16999 17000 assert(var != NULL); 17001 17002 var = SCIPvarGetProbvar(var); 17003 17004 /* check, if variable is original without transformed variable */ 17005 if( var == NULL ) 17006 return &initbdchgidx; 17007 17008 /* check, if variable was fixed in presolving */ 17009 if( !SCIPvarIsActive(var) ) 17010 return &presolvebdchgidx; 17011 17012 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 17013 17014 /* get depths of last bound change information for the lower and upper bound */ 17015 lbchgidx = (var->nlbchginfos > 0 && !var->lbchginfos[var->nlbchginfos-1].redundant 17016 ? &var->lbchginfos[var->nlbchginfos-1].bdchgidx : &initbdchgidx); 17017 ubchgidx = (var->nubchginfos > 0 && !var->ubchginfos[var->nubchginfos-1].redundant 17018 ? &var->ubchginfos[var->nubchginfos-1].bdchgidx : &initbdchgidx); 17019 17020 if( SCIPbdchgidxIsEarlierNonNull(lbchgidx, ubchgidx) ) 17021 return ubchgidx; 17022 else 17023 return lbchgidx; 17024 } 17025 17026 /** returns the last depth level, at which the bounds of the given variable were tightened; 17027 * returns -2, if the variable's bounds are still the global bounds 17028 * returns -1, if the variable was fixed in presolving 17029 */ 17030 int SCIPvarGetLastBdchgDepth( 17031 SCIP_VAR* var /**< problem variable */ 17032 ) 17033 { 17034 SCIP_BDCHGIDX* bdchgidx; 17035 17036 bdchgidx = SCIPvarGetLastBdchgIndex(var); 17037 assert(bdchgidx != NULL); 17038 17039 return bdchgidx->depth; 17040 } 17041 17042 /** returns at which depth in the tree a bound change was applied to the variable that conflicts with the 17043 * given bound; returns -1 if the bound does not conflict with the current local bounds of the variable 17044 */ 17045 int SCIPvarGetConflictingBdchgDepth( 17046 SCIP_VAR* var, /**< problem variable */ 17047 SCIP_SET* set, /**< global SCIP settings */ 17048 SCIP_BOUNDTYPE boundtype, /**< bound type of the conflicting bound */ 17049 SCIP_Real bound /**< conflicting bound */ 17050 ) 17051 { 17052 int i; 17053 17054 assert(var != NULL); 17055 assert(set != NULL); 17056 assert(var->scip == set->scip); 17057 17058 if( boundtype == SCIP_BOUNDTYPE_LOWER ) 17059 { 17060 /* check if the bound is in conflict with the current local bounds */ 17061 if( SCIPsetIsLE(set, bound, var->locdom.ub) ) 17062 return -1; 17063 17064 /* check if the bound is in conflict with the global bound */ 17065 if( SCIPsetIsGT(set, bound, var->glbdom.ub) ) 17066 return 0; 17067 17068 /* local bounds are in conflict with the given bound -> there must be at least one conflicting change! */ 17069 assert(var->nubchginfos > 0); 17070 assert(SCIPsetIsGT(set, bound, var->ubchginfos[var->nubchginfos-1].newbound)); 17071 17072 /* search for the first conflicting bound change */ 17073 for( i = var->nubchginfos-1; i > 0 && SCIPsetIsGT(set, bound, var->ubchginfos[i-1].newbound); --i ) 17074 { 17075 assert(var->ubchginfos[i].var == var); /* perform sanity check on the search for the first conflicting bound */ 17076 assert((SCIP_BOUNDTYPE)var->ubchginfos[i].boundtype == SCIP_BOUNDTYPE_UPPER); 17077 } 17078 assert(SCIPsetIsGT(set, bound, var->ubchginfos[i].newbound)); /* bound change i is conflicting */ 17079 assert(i == 0 || SCIPsetIsLE(set, bound, var->ubchginfos[i-1].newbound)); /* bound change i-1 is not conflicting */ 17080 17081 /* return the depth at which the first conflicting bound change took place */ 17082 return var->ubchginfos[i].bdchgidx.depth; 17083 } 17084 else 17085 { 17086 assert(boundtype == SCIP_BOUNDTYPE_UPPER); 17087 17088 /* check if the bound is in conflict with the current local bounds */ 17089 if( SCIPsetIsGE(set, bound, var->locdom.lb) ) 17090 return -1; 17091 17092 /* check if the bound is in conflict with the global bound */ 17093 if( SCIPsetIsLT(set, bound, var->glbdom.lb) ) 17094 return 0; 17095 17096 /* local bounds are in conflict with the given bound -> there must be at least one conflicting change! */ 17097 assert(var->nlbchginfos > 0); 17098 assert(SCIPsetIsLT(set, bound, var->lbchginfos[var->nlbchginfos-1].newbound)); 17099 17100 /* search for the first conflicting bound change */ 17101 for( i = var->nlbchginfos-1; i > 0 && SCIPsetIsLT(set, bound, var->lbchginfos[i-1].newbound); --i ) 17102 { 17103 assert(var->lbchginfos[i].var == var); /* perform sanity check on the search for the first conflicting bound */ 17104 assert((SCIP_BOUNDTYPE)var->lbchginfos[i].boundtype == SCIP_BOUNDTYPE_LOWER); 17105 } 17106 assert(SCIPsetIsLT(set, bound, var->lbchginfos[i].newbound)); /* bound change i is conflicting */ 17107 assert(i == 0 || SCIPsetIsGE(set, bound, var->lbchginfos[i-1].newbound)); /* bound change i-1 is not conflicting */ 17108 17109 /* return the depth at which the first conflicting bound change took place */ 17110 return var->lbchginfos[i].bdchgidx.depth; 17111 } 17112 } 17113 17114 /** returns whether the first binary variable was fixed earlier than the second one; 17115 * returns FALSE, if the first variable is not fixed, and returns TRUE, if the first variable is fixed, but the 17116 * second one is not fixed 17117 */ 17118 SCIP_Bool SCIPvarWasFixedEarlier( 17119 SCIP_VAR* var1, /**< first binary variable */ 17120 SCIP_VAR* var2 /**< second binary variable */ 17121 ) 17122 { 17123 SCIP_BDCHGIDX* bdchgidx1; 17124 SCIP_BDCHGIDX* bdchgidx2; 17125 17126 assert(var1 != NULL); 17127 assert(var2 != NULL); 17128 assert(SCIPvarIsBinary(var1)); 17129 assert(SCIPvarIsBinary(var2)); 17130 17131 var1 = SCIPvarGetProbvar(var1); 17132 var2 = SCIPvarGetProbvar(var2); 17133 assert(var1 != NULL); 17134 assert(var2 != NULL); 17135 17136 /* check, if variables are globally fixed */ 17137 if( !SCIPvarIsActive(var2) || var2->glbdom.lb > 0.5 || var2->glbdom.ub < 0.5 ) 17138 return FALSE; 17139 if( !SCIPvarIsActive(var1) || var1->glbdom.lb > 0.5 || var1->glbdom.ub < 0.5 ) 17140 return TRUE; 17141 17142 assert(SCIPvarGetStatus(var1) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_COLUMN); 17143 assert(SCIPvarGetStatus(var2) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_COLUMN); 17144 assert(SCIPvarIsBinary(var1)); 17145 assert(SCIPvarIsBinary(var2)); 17146 assert(var1->nlbchginfos + var1->nubchginfos <= 1); 17147 assert(var2->nlbchginfos + var2->nubchginfos <= 1); 17148 assert(var1->nlbchginfos == 0 || !var1->lbchginfos[0].redundant); /* otherwise, var would be globally fixed */ 17149 assert(var1->nubchginfos == 0 || !var1->ubchginfos[0].redundant); /* otherwise, var would be globally fixed */ 17150 assert(var2->nlbchginfos == 0 || !var2->lbchginfos[0].redundant); /* otherwise, var would be globally fixed */ 17151 assert(var2->nubchginfos == 0 || !var2->ubchginfos[0].redundant); /* otherwise, var would be globally fixed */ 17152 17153 if( var1->nlbchginfos == 1 ) 17154 bdchgidx1 = &var1->lbchginfos[0].bdchgidx; 17155 else if( var1->nubchginfos == 1 ) 17156 bdchgidx1 = &var1->ubchginfos[0].bdchgidx; 17157 else 17158 bdchgidx1 = NULL; 17159 17160 if( var2->nlbchginfos == 1 ) 17161 bdchgidx2 = &var2->lbchginfos[0].bdchgidx; 17162 else if( var2->nubchginfos == 1 ) 17163 bdchgidx2 = &var2->ubchginfos[0].bdchgidx; 17164 else 17165 bdchgidx2 = NULL; 17166 17167 return SCIPbdchgidxIsEarlier(bdchgidx1, bdchgidx2); 17168 } 17169 17170 17171 17172 /* 17173 * Hash functions 17174 */ 17175 17176 /** gets the key (i.e. the name) of the given variable */ 17177 SCIP_DECL_HASHGETKEY(SCIPhashGetKeyVar) 17178 { /*lint --e{715}*/ 17179 SCIP_VAR* var = (SCIP_VAR*)elem; 17180 17181 assert(var != NULL); 17182 return var->name; 17183 } 17184 17185 17186 17187 17188 /* 17189 * simple functions implemented as defines 17190 */ 17191 17192 /* In debug mode, the following methods are implemented as function calls to ensure 17193 * type validity. 17194 * In optimized mode, the methods are implemented as defines to improve performance. 17195 * However, we want to have them in the library anyways, so we have to undef the defines. 17196 */ 17197 17198 #undef SCIPboundchgGetNewbound 17199 #undef SCIPboundchgGetVar 17200 #undef SCIPboundchgGetBoundchgtype 17201 #undef SCIPboundchgGetBoundtype 17202 #undef SCIPboundchgIsRedundant 17203 #undef SCIPdomchgGetNBoundchgs 17204 #undef SCIPdomchgGetBoundchg 17205 #undef SCIPholelistGetLeft 17206 #undef SCIPholelistGetRight 17207 #undef SCIPholelistGetNext 17208 #undef SCIPvarGetName 17209 #undef SCIPvarGetNUses 17210 #undef SCIPvarGetData 17211 #undef SCIPvarSetData 17212 #undef SCIPvarSetDelorigData 17213 #undef SCIPvarSetTransData 17214 #undef SCIPvarSetDeltransData 17215 #undef SCIPvarGetStatus 17216 #undef SCIPvarIsOriginal 17217 #undef SCIPvarIsTransformed 17218 #undef SCIPvarIsNegated 17219 #undef SCIPvarGetType 17220 #undef SCIPvarIsBinary 17221 #undef SCIPvarIsIntegral 17222 #undef SCIPvarIsInitial 17223 #undef SCIPvarIsRemovable 17224 #undef SCIPvarIsDeleted 17225 #undef SCIPvarIsDeletable 17226 #undef SCIPvarMarkDeletable 17227 #undef SCIPvarMarkNotDeletable 17228 #undef SCIPvarIsActive 17229 #undef SCIPvarGetIndex 17230 #undef SCIPvarGetProbindex 17231 #undef SCIPvarGetTransVar 17232 #undef SCIPvarGetCol 17233 #undef SCIPvarIsInLP 17234 #undef SCIPvarGetAggrVar 17235 #undef SCIPvarGetAggrScalar 17236 #undef SCIPvarGetAggrConstant 17237 #undef SCIPvarGetMultaggrNVars 17238 #undef SCIPvarGetMultaggrVars 17239 #undef SCIPvarGetMultaggrScalars 17240 #undef SCIPvarGetMultaggrConstant 17241 #undef SCIPvarGetNegatedVar 17242 #undef SCIPvarGetNegationVar 17243 #undef SCIPvarGetNegationConstant 17244 #undef SCIPvarGetObj 17245 #undef SCIPvarGetLbOriginal 17246 #undef SCIPvarGetUbOriginal 17247 #undef SCIPvarGetHolelistOriginal 17248 #undef SCIPvarGetLbGlobal 17249 #undef SCIPvarGetUbGlobal 17250 #undef SCIPvarGetHolelistGlobal 17251 #undef SCIPvarGetBestBoundGlobal 17252 #undef SCIPvarGetWorstBoundGlobal 17253 #undef SCIPvarGetLbLocal 17254 #undef SCIPvarGetUbLocal 17255 #undef SCIPvarGetHolelistLocal 17256 #undef SCIPvarGetBestBoundLocal 17257 #undef SCIPvarGetWorstBoundLocal 17258 #undef SCIPvarGetBestBoundType 17259 #undef SCIPvarGetWorstBoundType 17260 #undef SCIPvarGetLbLazy 17261 #undef SCIPvarGetUbLazy 17262 #undef SCIPvarGetBranchFactor 17263 #undef SCIPvarGetBranchPriority 17264 #undef SCIPvarGetBranchDirection 17265 #undef SCIPvarGetNVlbs 17266 #undef SCIPvarGetVlbVars 17267 #undef SCIPvarGetVlbCoefs 17268 #undef SCIPvarGetVlbConstants 17269 #undef SCIPvarGetNVubs 17270 #undef SCIPvarGetVubVars 17271 #undef SCIPvarGetVubCoefs 17272 #undef SCIPvarGetVubConstants 17273 #undef SCIPvarGetNImpls 17274 #undef SCIPvarGetImplVars 17275 #undef SCIPvarGetImplTypes 17276 #undef SCIPvarGetImplBounds 17277 #undef SCIPvarGetImplIds 17278 #undef SCIPvarGetNCliques 17279 #undef SCIPvarGetCliques 17280 #undef SCIPvarGetLPSol 17281 #undef SCIPvarGetNLPSol 17282 #undef SCIPvarGetBdchgInfoLb 17283 #undef SCIPvarGetNBdchgInfosLb 17284 #undef SCIPvarGetBdchgInfoUb 17285 #undef SCIPvarGetNBdchgInfosUb 17286 #undef SCIPvarGetValuehistory 17287 #undef SCIPvarGetPseudoSol 17288 #undef SCIPvarCatchEvent 17289 #undef SCIPvarDropEvent 17290 #undef SCIPvarGetVSIDS 17291 #undef SCIPvarGetCliqueComponentIdx 17292 #undef SCIPvarIsRelaxationOnly 17293 #undef SCIPvarMarkRelaxationOnly 17294 #undef SCIPbdchgidxGetPos 17295 #undef SCIPbdchgidxIsEarlierNonNull 17296 #undef SCIPbdchgidxIsEarlier 17297 #undef SCIPbdchginfoGetOldbound 17298 #undef SCIPbdchginfoGetNewbound 17299 #undef SCIPbdchginfoGetVar 17300 #undef SCIPbdchginfoGetChgtype 17301 #undef SCIPbdchginfoGetBoundtype 17302 #undef SCIPbdchginfoGetDepth 17303 #undef SCIPbdchginfoGetPos 17304 #undef SCIPbdchginfoGetIdx 17305 #undef SCIPbdchginfoGetInferVar 17306 #undef SCIPbdchginfoGetInferCons 17307 #undef SCIPbdchginfoGetInferProp 17308 #undef SCIPbdchginfoGetInferInfo 17309 #undef SCIPbdchginfoGetInferBoundtype 17310 #undef SCIPbdchginfoIsRedundant 17311 #undef SCIPbdchginfoHasInferenceReason 17312 #undef SCIPbdchginfoIsTighter 17313 17314 17315 /** returns the new value of the bound in the bound change data */ 17316 SCIP_Real SCIPboundchgGetNewbound( 17317 SCIP_BOUNDCHG* boundchg /**< bound change data */ 17318 ) 17319 { 17320 assert(boundchg != NULL); 17321 17322 return boundchg->newbound; 17323 } 17324 17325 /** returns the variable of the bound change in the bound change data */ 17326 SCIP_VAR* SCIPboundchgGetVar( 17327 SCIP_BOUNDCHG* boundchg /**< bound change data */ 17328 ) 17329 { 17330 assert(boundchg != NULL); 17331 17332 return boundchg->var; 17333 } 17334 17335 /** returns the bound change type of the bound change in the bound change data */ 17336 SCIP_BOUNDCHGTYPE SCIPboundchgGetBoundchgtype( 17337 SCIP_BOUNDCHG* boundchg /**< bound change data */ 17338 ) 17339 { 17340 assert(boundchg != NULL); 17341 17342 return (SCIP_BOUNDCHGTYPE)(boundchg->boundchgtype); 17343 } 17344 17345 /** returns the bound type of the bound change in the bound change data */ 17346 SCIP_BOUNDTYPE SCIPboundchgGetBoundtype( 17347 SCIP_BOUNDCHG* boundchg /**< bound change data */ 17348 ) 17349 { 17350 assert(boundchg != NULL); 17351 17352 return (SCIP_BOUNDTYPE)(boundchg->boundtype); 17353 } 17354 17355 /** returns whether the bound change is redundant due to a more global bound that is at least as strong */ 17356 SCIP_Bool SCIPboundchgIsRedundant( 17357 SCIP_BOUNDCHG* boundchg /**< bound change data */ 17358 ) 17359 { 17360 assert(boundchg != NULL); 17361 17362 return boundchg->redundant; 17363 } 17364 17365 /** returns the number of bound changes in the domain change data */ 17366 int SCIPdomchgGetNBoundchgs( 17367 SCIP_DOMCHG* domchg /**< domain change data */ 17368 ) 17369 { 17370 return domchg != NULL ? domchg->domchgbound.nboundchgs : 0; 17371 } 17372 17373 /** returns a particular bound change in the domain change data */ 17374 SCIP_BOUNDCHG* SCIPdomchgGetBoundchg( 17375 SCIP_DOMCHG* domchg, /**< domain change data */ 17376 int pos /**< position of the bound change in the domain change data */ 17377 ) 17378 { 17379 assert(domchg != NULL); 17380 assert(0 <= pos && pos < (int)domchg->domchgbound.nboundchgs); 17381 17382 return &domchg->domchgbound.boundchgs[pos]; 17383 } 17384 17385 /** returns left bound of open interval in hole */ 17386 SCIP_Real SCIPholelistGetLeft( 17387 SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */ 17388 ) 17389 { 17390 assert(holelist != NULL); 17391 17392 return holelist->hole.left; 17393 } 17394 17395 /** returns right bound of open interval in hole */ 17396 SCIP_Real SCIPholelistGetRight( 17397 SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */ 17398 ) 17399 { 17400 assert(holelist != NULL); 17401 17402 return holelist->hole.right; 17403 } 17404 17405 /** returns next hole in list */ 17406 SCIP_HOLELIST* SCIPholelistGetNext( 17407 SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */ 17408 ) 17409 { 17410 assert(holelist != NULL); 17411 17412 return holelist->next; 17413 } 17414 17415 /** returns the name of the variable 17416 * 17417 * @note to change the name of a variable, use SCIPchgVarName() from scip.h 17418 */ 17419 const char* SCIPvarGetName( 17420 SCIP_VAR* var /**< problem variable */ 17421 ) 17422 { 17423 assert(var != NULL); 17424 17425 return var->name; 17426 } 17427 17428 /** gets number of times, the variable is currently captured */ 17429 int SCIPvarGetNUses( 17430 SCIP_VAR* var /**< problem variable */ 17431 ) 17432 { 17433 assert(var != NULL); 17434 17435 return var->nuses; 17436 } 17437 17438 /** returns the user data of the variable */ 17439 SCIP_VARDATA* SCIPvarGetData( 17440 SCIP_VAR* var /**< problem variable */ 17441 ) 17442 { 17443 assert(var != NULL); 17444 17445 return var->vardata; 17446 } 17447 17448 /** sets the user data for the variable */ 17449 void SCIPvarSetData( 17450 SCIP_VAR* var, /**< problem variable */ 17451 SCIP_VARDATA* vardata /**< user variable data */ 17452 ) 17453 { 17454 assert(var != NULL); 17455 17456 var->vardata = vardata; 17457 } 17458 17459 /** sets method to free user data for the original variable */ 17460 void SCIPvarSetDelorigData( 17461 SCIP_VAR* var, /**< problem variable */ 17462 SCIP_DECL_VARDELORIG ((*vardelorig)) /**< frees user data of original variable */ 17463 ) 17464 { 17465 assert(var != NULL); 17466 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL); 17467 17468 var->vardelorig = vardelorig; 17469 } 17470 17471 /** sets method to transform user data of the variable */ 17472 void SCIPvarSetTransData( 17473 SCIP_VAR* var, /**< problem variable */ 17474 SCIP_DECL_VARTRANS ((*vartrans)) /**< creates transformed user data by transforming original user data */ 17475 ) 17476 { 17477 assert(var != NULL); 17478 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL); 17479 17480 var->vartrans = vartrans; 17481 } 17482 17483 /** sets method to free transformed user data for the variable */ 17484 void SCIPvarSetDeltransData( 17485 SCIP_VAR* var, /**< problem variable */ 17486 SCIP_DECL_VARDELTRANS ((*vardeltrans)) /**< frees user data of transformed variable */ 17487 ) 17488 { 17489 assert(var != NULL); 17490 17491 var->vardeltrans = vardeltrans; 17492 } 17493 17494 /** sets method to copy this variable into sub-SCIPs */ 17495 void SCIPvarSetCopyData( 17496 SCIP_VAR* var, /**< problem variable */ 17497 SCIP_DECL_VARCOPY ((*varcopy)) /**< copy method of the variable */ 17498 ) 17499 { 17500 assert(var != NULL); 17501 17502 var->varcopy = varcopy; 17503 } 17504 17505 /** sets the initial flag of a variable; only possible for original or loose variables */ 17506 SCIP_RETCODE SCIPvarSetInitial( 17507 SCIP_VAR* var, /**< problem variable */ 17508 SCIP_Bool initial /**< initial flag */ 17509 ) 17510 { 17511 assert(var != NULL); 17512 17513 if( (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_ORIGINAL && (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_LOOSE ) 17514 return SCIP_INVALIDCALL; 17515 17516 var->initial = initial; 17517 17518 return SCIP_OKAY; 17519 } 17520 17521 /** sets the removable flag of a variable; only possible for original or loose variables */ 17522 SCIP_RETCODE SCIPvarSetRemovable( 17523 SCIP_VAR* var, /**< problem variable */ 17524 SCIP_Bool removable /**< removable flag */ 17525 ) 17526 { 17527 assert(var != NULL); 17528 17529 if( (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_ORIGINAL && (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_LOOSE ) 17530 return SCIP_INVALIDCALL; 17531 17532 var->removable = removable; 17533 17534 return SCIP_OKAY; 17535 } 17536 17537 /** gets status of variable */ 17538 SCIP_VARSTATUS SCIPvarGetStatus( 17539 SCIP_VAR* var /**< problem variable */ 17540 ) 17541 { 17542 assert(var != NULL); 17543 17544 return (SCIP_VARSTATUS)(var->varstatus); 17545 } 17546 17547 /** returns whether the variable belongs to the original problem */ 17548 SCIP_Bool SCIPvarIsOriginal( 17549 SCIP_VAR* var /**< problem variable */ 17550 ) 17551 { 17552 assert(var != NULL); 17553 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED || var->negatedvar != NULL); 17554 17555 return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL 17556 || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED 17557 && SCIPvarGetStatus(var->negatedvar) == SCIP_VARSTATUS_ORIGINAL)); 17558 } 17559 17560 /** returns whether the variable belongs to the transformed problem */ 17561 SCIP_Bool SCIPvarIsTransformed( 17562 SCIP_VAR* var /**< problem variable */ 17563 ) 17564 { 17565 assert(var != NULL); 17566 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED || var->negatedvar != NULL); 17567 17568 return (SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL 17569 && (SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED 17570 || SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_ORIGINAL)); 17571 } 17572 17573 /** returns whether the variable was created by negation of a different variable */ 17574 SCIP_Bool SCIPvarIsNegated( 17575 SCIP_VAR* var /**< problem variable */ 17576 ) 17577 { 17578 assert(var != NULL); 17579 17580 return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED); 17581 } 17582 17583 /** gets type of variable */ 17584 SCIP_VARTYPE SCIPvarGetType( 17585 SCIP_VAR* var /**< problem variable */ 17586 ) 17587 { 17588 assert(var != NULL); 17589 17590 return (SCIP_VARTYPE)(var->vartype); 17591 } 17592 17593 /** returns TRUE if the variable is of binary type; this is the case if: 17594 * (1) variable type is binary 17595 * (2) variable type is integer or implicit integer and 17596 * (i) the global lower bound is greater than or equal to zero 17597 * (ii) the global upper bound is less than or equal to one 17598 */ 17599 SCIP_Bool SCIPvarIsBinary( 17600 SCIP_VAR* var /**< problem variable */ 17601 ) 17602 { 17603 assert(var != NULL); 17604 17605 return (SCIPvarGetType(var) == SCIP_VARTYPE_BINARY || 17606 (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && var->glbdom.lb >= 0.0 && var->glbdom.ub <= 1.0)); 17607 } 17608 17609 /** returns whether variable is of integral type (binary, integer, or implicit integer) */ 17610 SCIP_Bool SCIPvarIsIntegral( 17611 SCIP_VAR* var /**< problem variable */ 17612 ) 17613 { 17614 assert(var != NULL); 17615 17616 return (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS); 17617 } 17618 17619 /** returns whether variable's column should be present in the initial root LP */ 17620 SCIP_Bool SCIPvarIsInitial( 17621 SCIP_VAR* var /**< problem variable */ 17622 ) 17623 { 17624 assert(var != NULL); 17625 17626 return var->initial; 17627 } 17628 17629 /** returns whether variable's column is removable from the LP (due to aging or cleanup) */ 17630 SCIP_Bool SCIPvarIsRemovable( 17631 SCIP_VAR* var /**< problem variable */ 17632 ) 17633 { 17634 assert(var != NULL); 17635 17636 return var->removable; 17637 } 17638 17639 /** returns whether the variable was deleted from the problem */ 17640 SCIP_Bool SCIPvarIsDeleted( 17641 SCIP_VAR* var /**< problem variable */ 17642 ) 17643 { 17644 assert(var != NULL); 17645 17646 return var->deleted; 17647 } 17648 17649 /** marks the variable to be deletable, i.e., it may be deleted completely from the problem; 17650 * method can only be called before the variable is added to the problem by SCIPaddVar() or SCIPaddPricedVar() 17651 */ 17652 void SCIPvarMarkDeletable( 17653 SCIP_VAR* var /**< problem variable */ 17654 ) 17655 { 17656 assert(var != NULL); 17657 assert(var->probindex == -1); 17658 17659 var->deletable = TRUE; 17660 } 17661 17662 /** marks the variable to be not deletable from the problem */ 17663 void SCIPvarMarkNotDeletable( 17664 SCIP_VAR* var 17665 ) 17666 { 17667 assert(var != NULL); 17668 17669 var->deletable = FALSE; 17670 } 17671 17672 /** marks variable to be deleted from global structures (cliques etc.) when cleaning up 17673 * 17674 * @note: this is not equivalent to marking the variable itself for deletion, this is done by using SCIPvarMarkDeletable() 17675 */ 17676 void SCIPvarMarkDeleteGlobalStructures( 17677 SCIP_VAR* var /**< problem variable */ 17678 ) 17679 { 17680 assert(var != NULL); 17681 17682 var->delglobalstructs = TRUE; 17683 } 17684 17685 /** returns whether the variable was flagged for deletion from global structures (cliques etc.) */ 17686 SCIP_Bool SCIPvarIsMarkedDeleteGlobalStructures( 17687 SCIP_VAR* var /**< problem variable */ 17688 ) 17689 { 17690 assert(var != NULL); 17691 17692 return var->delglobalstructs; 17693 } 17694 17695 /** returns whether a variable has been introduced to define a relaxation 17696 * 17697 * These variables are only valid for the current SCIP solve round, 17698 * they are not contained in any (checked) constraints, but may be used 17699 * in cutting planes, for example. 17700 * Relaxation-only variables are not copied by SCIPcopyVars and cuts 17701 * that contain these variables are not added as linear constraints when 17702 * restarting or transferring information from a copied SCIP to a SCIP. 17703 * Also conflicts with relaxation-only variables are not generated at 17704 * the moment. 17705 */ 17706 SCIP_Bool SCIPvarIsRelaxationOnly( 17707 SCIP_VAR* var /**< problem variable */ 17708 ) 17709 { 17710 assert(var != NULL); 17711 17712 return var->relaxationonly; 17713 } 17714 17715 /** marks that this variable has only been introduced to define a relaxation 17716 * 17717 * The variable must not have a coefficient in the objective and must be deletable. 17718 * If it is not marked deletable, it will be marked as deletable, which is only possible 17719 * before the variable is added to a problem. 17720 * 17721 * @see SCIPvarIsRelaxationOnly 17722 * @see SCIPvarMarkDeletable 17723 */ 17724 void SCIPvarMarkRelaxationOnly( 17725 SCIP_VAR* var /**< problem variable */ 17726 ) 17727 { 17728 assert(var != NULL); 17729 assert(SCIPvarGetObj(var) == 0.0); 17730 17731 if( !SCIPvarIsDeletable(var) ) 17732 SCIPvarMarkDeletable(var); 17733 17734 var->relaxationonly = TRUE; 17735 } 17736 17737 /** returns whether variable is allowed to be deleted completely from the problem */ 17738 SCIP_Bool SCIPvarIsDeletable( 17739 SCIP_VAR* var 17740 ) 17741 { 17742 assert(var != NULL); 17743 17744 return var->deletable; 17745 } 17746 17747 /** returns whether variable is an active (neither fixed nor aggregated) variable */ 17748 SCIP_Bool SCIPvarIsActive( 17749 SCIP_VAR* var /**< problem variable */ 17750 ) 17751 { 17752 assert(var != NULL); 17753 17754 return (var->probindex >= 0); 17755 } 17756 17757 /** gets unique index of variable */ 17758 int SCIPvarGetIndex( 17759 SCIP_VAR* var /**< problem variable */ 17760 ) 17761 { 17762 assert(var != NULL); 17763 17764 return var->index; 17765 } 17766 17767 /** gets position of variable in problem, or -1 if variable is not active */ 17768 int SCIPvarGetProbindex( 17769 SCIP_VAR* var /**< problem variable */ 17770 ) 17771 { 17772 assert(var != NULL); 17773 17774 return var->probindex; 17775 } 17776 17777 /** gets transformed variable of ORIGINAL variable */ 17778 SCIP_VAR* SCIPvarGetTransVar( 17779 SCIP_VAR* var /**< problem variable */ 17780 ) 17781 { 17782 assert(var != NULL); 17783 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL); 17784 17785 return var->data.original.transvar; 17786 } 17787 17788 /** gets column of COLUMN variable */ 17789 SCIP_COL* SCIPvarGetCol( 17790 SCIP_VAR* var /**< problem variable */ 17791 ) 17792 { 17793 assert(var != NULL); 17794 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 17795 17796 return var->data.col; 17797 } 17798 17799 /** returns whether the variable is a COLUMN variable that is member of the current LP */ 17800 SCIP_Bool SCIPvarIsInLP( 17801 SCIP_VAR* var /**< problem variable */ 17802 ) 17803 { 17804 assert(var != NULL); 17805 17806 return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN && SCIPcolIsInLP(var->data.col)); 17807 } 17808 17809 /** gets aggregation variable y of an aggregated variable x = a*y + c */ 17810 SCIP_VAR* SCIPvarGetAggrVar( 17811 SCIP_VAR* var /**< problem variable */ 17812 ) 17813 { 17814 assert(var != NULL); 17815 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED); 17816 assert(!var->donotaggr); 17817 17818 return var->data.aggregate.var; 17819 } 17820 17821 /** gets aggregation scalar a of an aggregated variable x = a*y + c */ 17822 SCIP_Real SCIPvarGetAggrScalar( 17823 SCIP_VAR* var /**< problem variable */ 17824 ) 17825 { 17826 assert(var != NULL); 17827 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED); 17828 assert(!var->donotaggr); 17829 17830 return var->data.aggregate.scalar; 17831 } 17832 17833 /** gets aggregation constant c of an aggregated variable x = a*y + c */ 17834 SCIP_Real SCIPvarGetAggrConstant( 17835 SCIP_VAR* var /**< problem variable */ 17836 ) 17837 { 17838 assert(var != NULL); 17839 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED); 17840 assert(!var->donotaggr); 17841 17842 return var->data.aggregate.constant; 17843 } 17844 17845 /** gets number n of aggregation variables of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */ 17846 int SCIPvarGetMultaggrNVars( 17847 SCIP_VAR* var /**< problem variable */ 17848 ) 17849 { 17850 assert(var != NULL); 17851 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); 17852 assert(!var->donotmultaggr); 17853 17854 return var->data.multaggr.nvars; 17855 } 17856 17857 /** gets vector of aggregation variables y of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */ 17858 SCIP_VAR** SCIPvarGetMultaggrVars( 17859 SCIP_VAR* var /**< problem variable */ 17860 ) 17861 { 17862 assert(var != NULL); 17863 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); 17864 assert(!var->donotmultaggr); 17865 17866 return var->data.multaggr.vars; 17867 } 17868 17869 /** gets vector of aggregation scalars a of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */ 17870 SCIP_Real* SCIPvarGetMultaggrScalars( 17871 SCIP_VAR* var /**< problem variable */ 17872 ) 17873 { 17874 assert(var != NULL); 17875 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); 17876 assert(!var->donotmultaggr); 17877 17878 return var->data.multaggr.scalars; 17879 } 17880 17881 /** gets aggregation constant c of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */ 17882 SCIP_Real SCIPvarGetMultaggrConstant( 17883 SCIP_VAR* var /**< problem variable */ 17884 ) 17885 { 17886 assert(var != NULL); 17887 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); 17888 assert(!var->donotmultaggr); 17889 17890 return var->data.multaggr.constant; 17891 } 17892 17893 /** gets the negation of the given variable; may return NULL, if no negation is existing yet */ 17894 SCIP_VAR* SCIPvarGetNegatedVar( 17895 SCIP_VAR* var /**< negated problem variable */ 17896 ) 17897 { 17898 assert(var != NULL); 17899 17900 return var->negatedvar; 17901 } 17902 17903 /** gets the negation variable x of a negated variable x' = offset - x */ 17904 SCIP_VAR* SCIPvarGetNegationVar( 17905 SCIP_VAR* var /**< negated problem variable */ 17906 ) 17907 { 17908 assert(var != NULL); 17909 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED); 17910 17911 return var->negatedvar; 17912 } 17913 17914 /** gets the negation offset of a negated variable x' = offset - x */ 17915 SCIP_Real SCIPvarGetNegationConstant( 17916 SCIP_VAR* var /**< negated problem variable */ 17917 ) 17918 { 17919 assert(var != NULL); 17920 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED); 17921 17922 return var->data.negate.constant; 17923 } 17924 17925 /** gets objective function value of variable */ 17926 SCIP_Real SCIPvarGetObj( 17927 SCIP_VAR* var /**< problem variable */ 17928 ) 17929 { 17930 assert(var != NULL); 17931 17932 return var->obj; 17933 } 17934 17935 /** gets the unchanged objective function value of a variable (ignoring temproray changes performed in probing mode) */ 17936 SCIP_Real SCIPvarGetUnchangedObj( 17937 SCIP_VAR* var /**< problem variable */ 17938 ) 17939 { 17940 assert(var != NULL); 17941 17942 return var->unchangedobj; 17943 } 17944 17945 /** gets corresponding objective value of active, fixed, or multi-aggregated problem variable of given variable 17946 * e.g. obj(x) = 1 this method returns for ~x the value -1 17947 */ 17948 SCIP_RETCODE SCIPvarGetAggregatedObj( 17949 SCIP_VAR* var, /**< problem variable */ 17950 SCIP_Real* aggrobj /**< pointer to store the aggregated objective value */ 17951 ) 17952 { 17953 SCIP_VAR* probvar = var; 17954 SCIP_Real mult = 1.0; 17955 17956 assert(probvar != NULL); 17957 assert(aggrobj != NULL); 17958 17959 while( probvar != NULL ) 17960 { 17961 switch( SCIPvarGetStatus(probvar) ) 17962 { 17963 case SCIP_VARSTATUS_ORIGINAL: 17964 case SCIP_VARSTATUS_LOOSE: 17965 case SCIP_VARSTATUS_COLUMN: 17966 (*aggrobj) = mult * SCIPvarGetObj(probvar); 17967 return SCIP_OKAY; 17968 17969 case SCIP_VARSTATUS_FIXED: 17970 assert(SCIPvarGetObj(probvar) == 0.0); 17971 (*aggrobj) = 0.0; 17972 return SCIP_OKAY; 17973 17974 case SCIP_VARSTATUS_MULTAGGR: 17975 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */ 17976 if ( probvar->data.multaggr.nvars == 1 ) 17977 { 17978 assert( probvar->data.multaggr.vars != NULL ); 17979 assert( probvar->data.multaggr.scalars != NULL ); 17980 assert( probvar->data.multaggr.vars[0] != NULL ); 17981 mult *= probvar->data.multaggr.scalars[0]; 17982 probvar = probvar->data.multaggr.vars[0]; 17983 break; 17984 } 17985 else 17986 { 17987 SCIP_Real tmpobj; 17988 int v; 17989 17990 (*aggrobj) = 0.0; 17991 17992 for( v = probvar->data.multaggr.nvars - 1; v >= 0; --v ) 17993 { 17994 SCIP_CALL( SCIPvarGetAggregatedObj(probvar->data.multaggr.vars[v], &tmpobj) ); 17995 (*aggrobj) += probvar->data.multaggr.scalars[v] * tmpobj; 17996 } 17997 return SCIP_OKAY; 17998 } 17999 18000 case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */ 18001 assert(probvar->data.aggregate.var != NULL); 18002 mult *= probvar->data.aggregate.scalar; 18003 probvar = probvar->data.aggregate.var; 18004 break; 18005 18006 case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */ 18007 assert(probvar->negatedvar != NULL); 18008 assert(SCIPvarGetStatus(probvar->negatedvar) != SCIP_VARSTATUS_NEGATED); 18009 assert(probvar->negatedvar->negatedvar == probvar); 18010 mult *= -1.0; 18011 probvar = probvar->negatedvar; 18012 break; 18013 18014 default: 18015 SCIPABORT(); 18016 return SCIP_INVALIDDATA; /*lint !e527*/ 18017 } 18018 } 18019 18020 return SCIP_INVALIDDATA; 18021 } 18022 18023 /** gets original lower bound of original problem variable (i.e. the bound set in problem creation) */ 18024 SCIP_Real SCIPvarGetLbOriginal( 18025 SCIP_VAR* var /**< original problem variable */ 18026 ) 18027 { 18028 assert(var != NULL); 18029 assert(SCIPvarIsOriginal(var)); 18030 18031 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL ) 18032 return var->data.original.origdom.lb; 18033 else 18034 { 18035 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED); 18036 assert(var->negatedvar != NULL); 18037 assert(SCIPvarGetStatus(var->negatedvar) == SCIP_VARSTATUS_ORIGINAL); 18038 18039 return var->data.negate.constant - var->negatedvar->data.original.origdom.ub; 18040 } 18041 } 18042 18043 /** gets original upper bound of original problem variable (i.e. the bound set in problem creation) */ 18044 SCIP_Real SCIPvarGetUbOriginal( 18045 SCIP_VAR* var /**< original problem variable */ 18046 ) 18047 { 18048 assert(var != NULL); 18049 assert(SCIPvarIsOriginal(var)); 18050 18051 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL ) 18052 return var->data.original.origdom.ub; 18053 else 18054 { 18055 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED); 18056 assert(var->negatedvar != NULL); 18057 assert(SCIPvarGetStatus(var->negatedvar) == SCIP_VARSTATUS_ORIGINAL); 18058 18059 return var->data.negate.constant - var->negatedvar->data.original.origdom.lb; 18060 } 18061 } 18062 18063 /** gets the original hole list of an original variable */ 18064 SCIP_HOLELIST* SCIPvarGetHolelistOriginal( 18065 SCIP_VAR* var /**< problem variable */ 18066 ) 18067 { 18068 assert(var != NULL); 18069 assert(SCIPvarIsOriginal(var)); 18070 18071 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL ) 18072 return var->data.original.origdom.holelist; 18073 18074 return NULL; 18075 } 18076 18077 /** gets global lower bound of variable */ 18078 SCIP_Real SCIPvarGetLbGlobal( 18079 SCIP_VAR* var /**< problem variable */ 18080 ) 18081 { 18082 assert(var != NULL); 18083 18084 return var->glbdom.lb; 18085 } 18086 18087 /** gets global upper bound of variable */ 18088 SCIP_Real SCIPvarGetUbGlobal( 18089 SCIP_VAR* var /**< problem variable */ 18090 ) 18091 { 18092 assert(var != NULL); 18093 18094 return var->glbdom.ub; 18095 } 18096 18097 /** gets the global hole list of an active variable */ 18098 SCIP_HOLELIST* SCIPvarGetHolelistGlobal( 18099 SCIP_VAR* var /**< problem variable */ 18100 ) 18101 { 18102 assert(var != NULL); 18103 18104 return var->glbdom.holelist; 18105 } 18106 18107 /** gets best global bound of variable with respect to the objective function */ 18108 SCIP_Real SCIPvarGetBestBoundGlobal( 18109 SCIP_VAR* var /**< problem variable */ 18110 ) 18111 { 18112 assert(var != NULL); 18113 18114 if( var->obj >= 0.0 ) 18115 return var->glbdom.lb; 18116 else 18117 return var->glbdom.ub; 18118 } 18119 18120 /** gets worst global bound of variable with respect to the objective function */ 18121 SCIP_Real SCIPvarGetWorstBoundGlobal( 18122 SCIP_VAR* var /**< problem variable */ 18123 ) 18124 { 18125 assert(var != NULL); 18126 18127 if( var->obj >= 0.0 ) 18128 return var->glbdom.ub; 18129 else 18130 return var->glbdom.lb; 18131 } 18132 18133 /** gets current lower bound of variable */ 18134 SCIP_Real SCIPvarGetLbLocal( 18135 SCIP_VAR* var /**< problem variable */ 18136 ) 18137 { 18138 assert(var != NULL); 18139 18140 return var->locdom.lb; 18141 } 18142 18143 /** gets current upper bound of variable */ 18144 SCIP_Real SCIPvarGetUbLocal( 18145 SCIP_VAR* var /**< problem variable */ 18146 ) 18147 { 18148 assert(var != NULL); 18149 18150 return var->locdom.ub; 18151 } 18152 18153 /** gets the current hole list of an active variable */ 18154 SCIP_HOLELIST* SCIPvarGetHolelistLocal( 18155 SCIP_VAR* var /**< problem variable */ 18156 ) 18157 { 18158 assert(var != NULL); 18159 18160 return var->locdom.holelist; 18161 } 18162 18163 /** gets best local bound of variable with respect to the objective function */ 18164 SCIP_Real SCIPvarGetBestBoundLocal( 18165 SCIP_VAR* var /**< problem variable */ 18166 ) 18167 { 18168 assert(var != NULL); 18169 18170 if( var->obj >= 0.0 ) 18171 return var->locdom.lb; 18172 else 18173 return var->locdom.ub; 18174 } 18175 18176 /** gets worst local bound of variable with respect to the objective function */ 18177 SCIP_Real SCIPvarGetWorstBoundLocal( 18178 SCIP_VAR* var /**< problem variable */ 18179 ) 18180 { 18181 assert(var != NULL); 18182 18183 if( var->obj >= 0.0 ) 18184 return var->locdom.ub; 18185 else 18186 return var->locdom.lb; 18187 } 18188 18189 /** gets type (lower or upper) of best bound of variable with respect to the objective function */ 18190 SCIP_BOUNDTYPE SCIPvarGetBestBoundType( 18191 SCIP_VAR* var /**< problem variable */ 18192 ) 18193 { 18194 assert(var != NULL); 18195 18196 if( var->obj >= 0.0 ) 18197 return SCIP_BOUNDTYPE_LOWER; 18198 else 18199 return SCIP_BOUNDTYPE_UPPER; 18200 } 18201 18202 /** gets type (lower or upper) of worst bound of variable with respect to the objective function */ 18203 SCIP_BOUNDTYPE SCIPvarGetWorstBoundType( 18204 SCIP_VAR* var /**< problem variable */ 18205 ) 18206 { 18207 assert(var != NULL); 18208 18209 if( var->obj >= 0.0 ) 18210 return SCIP_BOUNDTYPE_UPPER; 18211 else 18212 return SCIP_BOUNDTYPE_LOWER; 18213 } 18214 18215 /** gets lazy lower bound of variable, returns -infinity if the variable has no lazy lower bound */ 18216 SCIP_Real SCIPvarGetLbLazy( 18217 SCIP_VAR* var /**< problem variable */ 18218 ) 18219 { 18220 assert(var != NULL); 18221 18222 return var->lazylb; 18223 } 18224 18225 /** gets lazy upper bound of variable, returns infinity if the variable has no lazy upper bound */ 18226 SCIP_Real SCIPvarGetUbLazy( 18227 SCIP_VAR* var /**< problem variable */ 18228 ) 18229 { 18230 assert(var != NULL); 18231 18232 return var->lazyub; 18233 } 18234 18235 /** gets the branch factor of the variable; this value can be used in the branching methods to scale the score 18236 * values of the variables; higher factor leads to a higher probability that this variable is chosen for branching 18237 */ 18238 SCIP_Real SCIPvarGetBranchFactor( 18239 SCIP_VAR* var /**< problem variable */ 18240 ) 18241 { 18242 assert(var != NULL); 18243 18244 return var->branchfactor; 18245 } 18246 18247 /** gets the branch priority of the variable; variables with higher priority should always be preferred to variables 18248 * with lower priority 18249 */ 18250 int SCIPvarGetBranchPriority( 18251 SCIP_VAR* var /**< problem variable */ 18252 ) 18253 { 18254 assert(var != NULL); 18255 18256 return var->branchpriority; 18257 } 18258 18259 /** gets the preferred branch direction of the variable (downwards, upwards, or auto) */ 18260 SCIP_BRANCHDIR SCIPvarGetBranchDirection( 18261 SCIP_VAR* var /**< problem variable */ 18262 ) 18263 { 18264 assert(var != NULL); 18265 18266 return (SCIP_BRANCHDIR)var->branchdirection; 18267 } 18268 18269 /** gets number of variable lower bounds x >= b_i*z_i + d_i of given variable x */ 18270 int SCIPvarGetNVlbs( 18271 SCIP_VAR* var /**< problem variable */ 18272 ) 18273 { 18274 assert(var != NULL); 18275 18276 return SCIPvboundsGetNVbds(var->vlbs); 18277 } 18278 18279 /** gets array with bounding variables z_i in variable lower bounds x >= b_i*z_i + d_i of given variable x; 18280 * the variable bounds are sorted by increasing variable index of the bounding variable z_i (see SCIPvarGetIndex()) 18281 */ 18282 SCIP_VAR** SCIPvarGetVlbVars( 18283 SCIP_VAR* var /**< problem variable */ 18284 ) 18285 { 18286 assert(var != NULL); 18287 18288 return SCIPvboundsGetVars(var->vlbs); 18289 } 18290 18291 /** gets array with bounding coefficients b_i in variable lower bounds x >= b_i*z_i + d_i of given variable x */ 18292 SCIP_Real* SCIPvarGetVlbCoefs( 18293 SCIP_VAR* var /**< problem variable */ 18294 ) 18295 { 18296 assert(var != NULL); 18297 18298 return SCIPvboundsGetCoefs(var->vlbs); 18299 } 18300 18301 /** gets array with bounding constants d_i in variable lower bounds x >= b_i*z_i + d_i of given variable x */ 18302 SCIP_Real* SCIPvarGetVlbConstants( 18303 SCIP_VAR* var /**< problem variable */ 18304 ) 18305 { 18306 assert(var != NULL); 18307 18308 return SCIPvboundsGetConstants(var->vlbs); 18309 } 18310 18311 /** gets number of variable upper bounds x <= b_i*z_i + d_i of given variable x */ 18312 int SCIPvarGetNVubs( 18313 SCIP_VAR* var /**< problem variable */ 18314 ) 18315 { 18316 assert(var != NULL); 18317 18318 return SCIPvboundsGetNVbds(var->vubs); 18319 } 18320 18321 /** gets array with bounding variables z_i in variable upper bounds x <= b_i*z_i + d_i of given variable x; 18322 * the variable bounds are sorted by increasing variable index of the bounding variable z_i (see SCIPvarGetIndex()) 18323 */ 18324 SCIP_VAR** SCIPvarGetVubVars( 18325 SCIP_VAR* var /**< problem variable */ 18326 ) 18327 { 18328 assert(var != NULL); 18329 18330 return SCIPvboundsGetVars(var->vubs); 18331 } 18332 18333 /** gets array with bounding coefficients b_i in variable upper bounds x <= b_i*z_i + d_i of given variable x */ 18334 SCIP_Real* SCIPvarGetVubCoefs( 18335 SCIP_VAR* var /**< problem variable */ 18336 ) 18337 { 18338 assert(var != NULL); 18339 18340 return SCIPvboundsGetCoefs(var->vubs); 18341 } 18342 18343 /** gets array with bounding constants d_i in variable upper bounds x <= b_i*z_i + d_i of given variable x */ 18344 SCIP_Real* SCIPvarGetVubConstants( 18345 SCIP_VAR* var /**< problem variable */ 18346 ) 18347 { 18348 assert(var != NULL); 18349 18350 return SCIPvboundsGetConstants(var->vubs); 18351 } 18352 18353 /** gets number of implications y <= b or y >= b for x == 0 or x == 1 of given active problem variable x, 18354 * there are no implications for nonbinary variable x 18355 */ 18356 int SCIPvarGetNImpls( 18357 SCIP_VAR* var, /**< active problem variable */ 18358 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */ 18359 ) 18360 { 18361 assert(var != NULL); 18362 assert(SCIPvarIsActive(var)); 18363 18364 return SCIPimplicsGetNImpls(var->implics, varfixing); 18365 } 18366 18367 /** gets array with implication variables y of implications y <= b or y >= b for x == 0 or x == 1 of given active 18368 * problem variable x, there are no implications for nonbinary variable x; 18369 * the implications are sorted such that implications with binary implied variables precede the ones with non-binary 18370 * implied variables, and as a second criteria, the implied variables are sorted by increasing variable index 18371 * (see SCIPvarGetIndex()) 18372 */ 18373 SCIP_VAR** SCIPvarGetImplVars( 18374 SCIP_VAR* var, /**< active problem variable */ 18375 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */ 18376 ) 18377 { 18378 assert(var != NULL); 18379 assert(SCIPvarIsActive(var)); 18380 18381 return SCIPimplicsGetVars(var->implics, varfixing); 18382 } 18383 18384 /** gets array with implication types of implications y <= b or y >= b for x == 0 or x == 1 of given active problem 18385 * variable x (SCIP_BOUNDTYPE_UPPER if y <= b, SCIP_BOUNDTYPE_LOWER if y >= b), 18386 * there are no implications for nonbinary variable x 18387 */ 18388 SCIP_BOUNDTYPE* SCIPvarGetImplTypes( 18389 SCIP_VAR* var, /**< active problem variable */ 18390 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */ 18391 ) 18392 { 18393 assert(var != NULL); 18394 assert(SCIPvarIsActive(var)); 18395 18396 return SCIPimplicsGetTypes(var->implics, varfixing); 18397 } 18398 18399 /** gets array with implication bounds b of implications y <= b or y >= b for x == 0 or x == 1 of given active problem 18400 * variable x, there are no implications for nonbinary variable x 18401 */ 18402 SCIP_Real* SCIPvarGetImplBounds( 18403 SCIP_VAR* var, /**< active problem variable */ 18404 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */ 18405 ) 18406 { 18407 assert(var != NULL); 18408 assert(SCIPvarIsActive(var)); 18409 18410 return SCIPimplicsGetBounds(var->implics, varfixing); 18411 } 18412 18413 /** Gets array with unique ids of implications y <= b or y >= b for x == 0 or x == 1 of given active problem variable x, 18414 * there are no implications for nonbinary variable x. 18415 * If an implication is a shortcut, i.e., it was added as part of the transitive closure of another implication, 18416 * its id is negative, otherwise it is nonnegative. 18417 */ 18418 int* SCIPvarGetImplIds( 18419 SCIP_VAR* var, /**< active problem variable */ 18420 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */ 18421 ) 18422 { 18423 assert(var != NULL); 18424 assert(SCIPvarIsActive(var)); 18425 18426 return SCIPimplicsGetIds(var->implics, varfixing); 18427 } 18428 18429 /** gets number of cliques, the active variable is contained in */ 18430 int SCIPvarGetNCliques( 18431 SCIP_VAR* var, /**< active problem variable */ 18432 SCIP_Bool varfixing /**< FALSE for cliques containing x == 0, TRUE for x == 1 */ 18433 ) 18434 { 18435 assert(var != NULL); 18436 18437 return SCIPcliquelistGetNCliques(var->cliquelist, varfixing); 18438 } 18439 18440 /** gets array of cliques, the active variable is contained in */ 18441 SCIP_CLIQUE** SCIPvarGetCliques( 18442 SCIP_VAR* var, /**< active problem variable */ 18443 SCIP_Bool varfixing /**< FALSE for cliques containing x == 0, TRUE for x == 1 */ 18444 ) 18445 { 18446 assert(var != NULL); 18447 18448 return SCIPcliquelistGetCliques(var->cliquelist, varfixing); 18449 } 18450 18451 /** gets primal LP solution value of variable */ 18452 SCIP_Real SCIPvarGetLPSol( 18453 SCIP_VAR* var /**< problem variable */ 18454 ) 18455 { 18456 assert(var != NULL); 18457 18458 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 18459 return SCIPcolGetPrimsol(var->data.col); 18460 else 18461 return SCIPvarGetLPSol_rec(var); 18462 } 18463 18464 /** gets primal NLP solution value of variable */ 18465 SCIP_Real SCIPvarGetNLPSol( 18466 SCIP_VAR* var /**< problem variable */ 18467 ) 18468 { 18469 assert(var != NULL); 18470 18471 if( (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE) ) 18472 return var->nlpsol; 18473 else 18474 return SCIPvarGetNLPSol_rec(var); 18475 } 18476 18477 /** return lower bound change info at requested position */ 18478 SCIP_BDCHGINFO* SCIPvarGetBdchgInfoLb( 18479 SCIP_VAR* var, /**< problem variable */ 18480 int pos /**< requested position */ 18481 ) 18482 { 18483 assert(pos >= 0); 18484 assert(pos < var->nlbchginfos); 18485 18486 return &var->lbchginfos[pos]; 18487 } 18488 18489 /** gets the number of lower bound change info array */ 18490 int SCIPvarGetNBdchgInfosLb( 18491 SCIP_VAR* var /**< problem variable */ 18492 ) 18493 { 18494 return var->nlbchginfos; 18495 } 18496 18497 /** return upper bound change info at requested position */ 18498 SCIP_BDCHGINFO* SCIPvarGetBdchgInfoUb( 18499 SCIP_VAR* var, /**< problem variable */ 18500 int pos /**< requested position */ 18501 ) 18502 { 18503 assert(pos >= 0); 18504 assert(pos < var->nubchginfos); 18505 18506 return &var->ubchginfos[pos]; 18507 } 18508 18509 /** gets the number upper bound change info array */ 18510 int SCIPvarGetNBdchgInfosUb( 18511 SCIP_VAR* var /**< problem variable */ 18512 ) 18513 { 18514 assert(var != NULL); 18515 18516 return var->nubchginfos; 18517 } 18518 18519 /** returns the value based history for the variable */ 18520 SCIP_VALUEHISTORY* SCIPvarGetValuehistory( 18521 SCIP_VAR* var /**< problem variable */ 18522 ) 18523 { 18524 assert(var != NULL); 18525 18526 return var->valuehistory; 18527 } 18528 18529 /** gets pseudo solution value of variable */ 18530 SCIP_Real SCIPvarGetPseudoSol( 18531 SCIP_VAR* var /**< problem variable */ 18532 ) 18533 { 18534 assert(var != NULL); 18535 18536 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 18537 return SCIPvarGetBestBoundLocal(var); 18538 else 18539 return SCIPvarGetPseudoSol_rec(var); 18540 } 18541 18542 /** returns the variable's VSIDS score */ 18543 SCIP_Real SCIPvarGetVSIDS( 18544 SCIP_VAR* var, /**< problem variable */ 18545 SCIP_STAT* stat, /**< problem statistics */ 18546 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */ 18547 ) 18548 { 18549 assert(var != NULL); 18550 18551 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 18552 return SCIPhistoryGetVSIDS(var->history, dir)/stat->vsidsweight; 18553 else 18554 return SCIPvarGetVSIDS_rec(var, stat, dir); 18555 } 18556 18557 /** includes event handler with given data in variable's event filter */ 18558 SCIP_RETCODE SCIPvarCatchEvent( 18559 SCIP_VAR* var, /**< problem variable */ 18560 BMS_BLKMEM* blkmem, /**< block memory */ 18561 SCIP_SET* set, /**< global SCIP settings */ 18562 SCIP_EVENTTYPE eventtype, /**< event type to catch */ 18563 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */ 18564 SCIP_EVENTDATA* eventdata, /**< event data to pass to the event handler for the event processing */ 18565 int* filterpos /**< pointer to store position of event filter entry, or NULL */ 18566 ) 18567 { 18568 assert(var != NULL); 18569 assert(set != NULL); 18570 assert(var->scip == set->scip); 18571 assert(var->eventfilter != NULL); 18572 assert((eventtype & ~SCIP_EVENTTYPE_VARCHANGED) == 0); 18573 assert((eventtype & SCIP_EVENTTYPE_VARCHANGED) != 0); 18574 assert(SCIPvarIsTransformed(var)); 18575 18576 SCIPsetDebugMsg(set, "catch event of type 0x%" SCIP_EVENTTYPE_FORMAT " of variable <%s> with handler %p and data %p\n", 18577 eventtype, var->name, (void*)eventhdlr, (void*)eventdata); 18578 18579 SCIP_CALL( SCIPeventfilterAdd(var->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) ); 18580 18581 return SCIP_OKAY; 18582 } 18583 18584 /** deletes event handler with given data from variable's event filter */ 18585 SCIP_RETCODE SCIPvarDropEvent( 18586 SCIP_VAR* var, /**< problem variable */ 18587 BMS_BLKMEM* blkmem, /**< block memory */ 18588 SCIP_SET* set, /**< global SCIP settings */ 18589 SCIP_EVENTTYPE eventtype, /**< event type mask of dropped event */ 18590 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */ 18591 SCIP_EVENTDATA* eventdata, /**< event data to pass to the event handler for the event processing */ 18592 int filterpos /**< position of event filter entry returned by SCIPvarCatchEvent(), or -1 */ 18593 ) 18594 { 18595 assert(var != NULL); 18596 assert(set != NULL); 18597 assert(var->scip == set->scip); 18598 assert(var->eventfilter != NULL); 18599 assert(SCIPvarIsTransformed(var)); 18600 18601 SCIPsetDebugMsg(set, "drop event of variable <%s> with handler %p and data %p\n", var->name, (void*)eventhdlr, 18602 (void*)eventdata); 18603 18604 SCIP_CALL( SCIPeventfilterDel(var->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) ); 18605 18606 return SCIP_OKAY; 18607 } 18608 18609 /** returns the position of the bound change index */ 18610 int SCIPbdchgidxGetPos( 18611 SCIP_BDCHGIDX* bdchgidx /**< bound change index */ 18612 ) 18613 { 18614 assert(bdchgidx != NULL); 18615 18616 return bdchgidx->pos; 18617 } 18618 18619 /** returns whether first bound change index belongs to an earlier applied bound change than second one */ 18620 SCIP_Bool SCIPbdchgidxIsEarlierNonNull( 18621 SCIP_BDCHGIDX* bdchgidx1, /**< first bound change index */ 18622 SCIP_BDCHGIDX* bdchgidx2 /**< second bound change index */ 18623 ) 18624 { 18625 assert(bdchgidx1 != NULL); 18626 assert(bdchgidx1->depth >= -2); 18627 assert(bdchgidx1->pos >= 0); 18628 assert(bdchgidx2 != NULL); 18629 assert(bdchgidx2->depth >= -2); 18630 assert(bdchgidx2->pos >= 0); 18631 18632 return (bdchgidx1->depth < bdchgidx2->depth) 18633 || (bdchgidx1->depth == bdchgidx2->depth && (bdchgidx1->pos < bdchgidx2->pos)); 18634 } 18635 18636 /** returns whether first bound change index belongs to an earlier applied bound change than second one; 18637 * if a bound change index is NULL, the bound change index represents the current time, i.e. the time after the 18638 * last bound change was applied to the current node 18639 */ 18640 SCIP_Bool SCIPbdchgidxIsEarlier( 18641 SCIP_BDCHGIDX* bdchgidx1, /**< first bound change index, or NULL */ 18642 SCIP_BDCHGIDX* bdchgidx2 /**< second bound change index, or NULL */ 18643 ) 18644 { 18645 assert(bdchgidx1 == NULL || bdchgidx1->depth >= -2); 18646 assert(bdchgidx1 == NULL || bdchgidx1->pos >= 0); 18647 assert(bdchgidx2 == NULL || bdchgidx2->depth >= -2); 18648 assert(bdchgidx2 == NULL || bdchgidx2->pos >= 0); 18649 18650 if( bdchgidx1 == NULL ) 18651 return FALSE; 18652 else if( bdchgidx2 == NULL ) 18653 return TRUE; 18654 else 18655 return (bdchgidx1->depth < bdchgidx2->depth) 18656 || (bdchgidx1->depth == bdchgidx2->depth && (bdchgidx1->pos < bdchgidx2->pos)); 18657 } 18658 18659 /** returns old bound that was overwritten for given bound change information */ 18660 SCIP_Real SCIPbdchginfoGetOldbound( 18661 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18662 ) 18663 { 18664 assert(bdchginfo != NULL); 18665 18666 return bdchginfo->oldbound; 18667 } 18668 18669 /** returns new bound installed for given bound change information */ 18670 SCIP_Real SCIPbdchginfoGetNewbound( 18671 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18672 ) 18673 { 18674 assert(bdchginfo != NULL); 18675 18676 return bdchginfo->newbound; 18677 } 18678 18679 /** returns variable that belongs to the given bound change information */ 18680 SCIP_VAR* SCIPbdchginfoGetVar( 18681 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18682 ) 18683 { 18684 assert(bdchginfo != NULL); 18685 18686 return bdchginfo->var; 18687 } 18688 18689 /** returns whether the bound change information belongs to a branching decision or a deduction */ 18690 SCIP_BOUNDCHGTYPE SCIPbdchginfoGetChgtype( 18691 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18692 ) 18693 { 18694 assert(bdchginfo != NULL); 18695 18696 return (SCIP_BOUNDCHGTYPE)(bdchginfo->boundchgtype); 18697 } 18698 18699 /** returns whether the bound change information belongs to a lower or upper bound change */ 18700 SCIP_BOUNDTYPE SCIPbdchginfoGetBoundtype( 18701 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18702 ) 18703 { 18704 assert(bdchginfo != NULL); 18705 18706 return (SCIP_BOUNDTYPE)(bdchginfo->boundtype); 18707 } 18708 18709 /** returns depth level of given bound change information */ 18710 int SCIPbdchginfoGetDepth( 18711 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18712 ) 18713 { 18714 assert(bdchginfo != NULL); 18715 18716 return bdchginfo->bdchgidx.depth; 18717 } 18718 18719 /** returns bound change position in its depth level of given bound change information */ 18720 int SCIPbdchginfoGetPos( 18721 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18722 ) 18723 { 18724 assert(bdchginfo != NULL); 18725 18726 return bdchginfo->bdchgidx.pos; 18727 } 18728 18729 /** returns bound change index of given bound change information */ 18730 SCIP_BDCHGIDX* SCIPbdchginfoGetIdx( 18731 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18732 ) 18733 { 18734 assert(bdchginfo != NULL); 18735 18736 return &bdchginfo->bdchgidx; 18737 } 18738 18739 /** returns inference variable of given bound change information */ 18740 SCIP_VAR* SCIPbdchginfoGetInferVar( 18741 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18742 ) 18743 { 18744 assert(bdchginfo != NULL); 18745 assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER 18746 || (SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER); 18747 18748 return bdchginfo->inferencedata.var; 18749 } 18750 18751 /** returns inference constraint of given bound change information */ 18752 SCIP_CONS* SCIPbdchginfoGetInferCons( 18753 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18754 ) 18755 { 18756 assert(bdchginfo != NULL); 18757 assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER); 18758 assert(bdchginfo->inferencedata.reason.cons != NULL); 18759 18760 return bdchginfo->inferencedata.reason.cons; 18761 } 18762 18763 /** returns inference propagator of given bound change information, or NULL if no propagator was responsible */ 18764 SCIP_PROP* SCIPbdchginfoGetInferProp( 18765 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18766 ) 18767 { 18768 assert(bdchginfo != NULL); 18769 assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER); 18770 18771 return bdchginfo->inferencedata.reason.prop; 18772 } 18773 18774 /** returns inference user information of given bound change information */ 18775 int SCIPbdchginfoGetInferInfo( 18776 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18777 ) 18778 { 18779 assert(bdchginfo != NULL); 18780 assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER 18781 || (SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER); 18782 18783 return bdchginfo->inferencedata.info; 18784 } 18785 18786 /** returns inference bound of inference variable of given bound change information */ 18787 SCIP_BOUNDTYPE SCIPbdchginfoGetInferBoundtype( 18788 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18789 ) 18790 { 18791 assert(bdchginfo != NULL); 18792 assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER 18793 || (SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER); 18794 18795 return (SCIP_BOUNDTYPE)(bdchginfo->inferboundtype); 18796 } 18797 18798 /** returns the relaxed bound change type */ 18799 SCIP_Real SCIPbdchginfoGetRelaxedBound( 18800 SCIP_BDCHGINFO* bdchginfo /**< bound change to add to the conflict set */ 18801 ) 18802 { 18803 return ((SCIP_BOUNDTYPE)(bdchginfo->boundtype) == SCIP_BOUNDTYPE_LOWER ? bdchginfo->var->conflictrelaxedlb : bdchginfo->var->conflictrelaxedub); 18804 } 18805 18806 18807 /** returns whether the bound change information belongs to a redundant bound change */ 18808 SCIP_Bool SCIPbdchginfoIsRedundant( 18809 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18810 ) 18811 { 18812 assert(bdchginfo != NULL); 18813 assert(bdchginfo->redundant == (bdchginfo->oldbound == bdchginfo->newbound)); /*lint !e777*/ 18814 18815 return bdchginfo->redundant; 18816 } 18817 18818 /** returns whether the bound change has an inference reason (constraint or propagator), that can be resolved */ 18819 SCIP_Bool SCIPbdchginfoHasInferenceReason( 18820 SCIP_BDCHGINFO* bdchginfo /**< bound change information */ 18821 ) 18822 { 18823 assert(bdchginfo != NULL); 18824 18825 return ((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) 18826 || ((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER 18827 && bdchginfo->inferencedata.reason.prop != NULL); 18828 } 18829 18830 /** for two bound change informations belonging to the same variable and bound, returns whether the first bound change 18831 * has a tighter new bound as the second bound change 18832 */ 18833 SCIP_Bool SCIPbdchginfoIsTighter( 18834 SCIP_BDCHGINFO* bdchginfo1, /**< first bound change information */ 18835 SCIP_BDCHGINFO* bdchginfo2 /**< second bound change information */ 18836 ) 18837 { 18838 assert(bdchginfo1 != NULL); 18839 assert(bdchginfo2 != NULL); 18840 assert(bdchginfo1->var == bdchginfo2->var); 18841 assert(bdchginfo1->boundtype == bdchginfo2->boundtype); 18842 18843 return (SCIPbdchginfoGetBoundtype(bdchginfo1) == SCIP_BOUNDTYPE_LOWER 18844 ? bdchginfo1->newbound > bdchginfo2->newbound 18845 : bdchginfo1->newbound < bdchginfo2->newbound); 18846 } 18847