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 reopt.c 26 * @ingroup OTHER_CFILES 27 * @brief data structures and methods for collecting reoptimization information 28 * @author Jakob Witzig 29 */ 30 31 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 32 #include <assert.h> 33 #include <string.h> 34 35 #include "scip/def.h" 36 #include "scip/mem.h" 37 #include "scip/event.h" 38 #include "scip/scip.h" 39 #include "scip/set.h" 40 #include "scip/sol.h" 41 #include "scip/var.h" 42 #include "scip/lp.h" 43 #include "scip/misc.h" 44 #include "scip/reopt.h" 45 #include "scip/tree.h" 46 #include "scip/primal.h" 47 #include "scip/sepastore.h" 48 #include "scip/cutpool.h" 49 #include "scip/prob.h" 50 #include "scip/cons.h" 51 #include "scip/cons_bounddisjunction.h" 52 #include "scip/cons_linear.h" 53 #include "scip/cons_logicor.h" 54 #include "scip/cons_setppc.h" 55 #include "scip/cons_linear.h" 56 #include "scip/clock.h" 57 #include "scip/history.h" 58 #include "blockmemshell/memory.h" 59 60 #define DEFAULT_MEM_VARAFTERDUAL 10 61 #define DEFAULT_MEM_VAR 10 62 #define DEFAULT_MEM_NODES 1000 63 #define DEFAULT_MEM_RUN 200 64 #define DEFAULT_MEM_DUALCONS 10 65 66 #define DEFAULT_RANDSEED 67 67 68 /* event handler properties */ 69 #define EVENTHDLR_NAME "Reopt" 70 #define EVENTHDLR_DESC "node event handler for reoptimization" 71 72 /* ---------------- Callback methods of event handler ---------------- */ 73 74 /** exec the event handler */ 75 static 76 SCIP_DECL_EVENTEXEC(eventExecReopt) 77 { /*lint --e{715}*/ 78 SCIP_NODE* eventnode; 79 SCIP_Real oldbound; 80 SCIP_Real newbound; 81 82 assert(scip != NULL); 83 assert(eventhdlr != NULL); 84 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 85 assert(SCIPvarGetType(SCIPeventGetVar(event)) != SCIP_VARTYPE_CONTINUOUS); 86 87 if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING ) 88 return SCIP_OKAY; 89 90 eventnode = SCIPgetCurrentNode(scip); 91 oldbound = SCIPeventGetOldbound(event); 92 newbound = SCIPeventGetNewbound(event); 93 94 /* if we are called from the last node in the tree that is cut off, eventnode will be NULL and we do not have to store the bound changes */ 95 if( eventnode == NULL ) 96 return SCIP_OKAY; 97 98 /* skip if the node is not the focus node */ 99 if( SCIPnodeGetType(eventnode) != SCIP_NODETYPE_FOCUSNODE || SCIPnodeGetDepth(eventnode) != SCIPgetEffectiveRootDepth(scip) ) 100 return SCIP_OKAY; 101 102 SCIPdebugMsg(scip, "catch event for node %lld: <%s>: %g -> %g\n", SCIPnodeGetNumber(eventnode), 103 SCIPvarGetName(SCIPeventGetVar(event)), SCIPeventGetOldbound(event), SCIPeventGetNewbound(event)); 104 105 assert(SCIPisFeasLT(scip, newbound, oldbound) || SCIPisFeasGT(scip, newbound, oldbound)); 106 107 SCIP_CALL( SCIPaddReoptDualBndchg(scip, eventnode, SCIPeventGetVar(event), newbound, oldbound) ); 108 109 return SCIP_OKAY; 110 } 111 112 /** solving process initialization method of event handler (called when branch and bound process is about to begin) */ 113 static 114 SCIP_DECL_EVENTINITSOL(eventInitsolReopt) 115 { 116 SCIP_VAR** vars; 117 118 assert(scip != NULL); 119 assert(eventhdlr != NULL); 120 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 121 122 if( !SCIPisReoptEnabled(scip) ) 123 return SCIP_OKAY; 124 125 vars = SCIPgetVars(scip); 126 for( int varnr = 0; varnr < SCIPgetNVars(scip); ++varnr ) 127 { 128 if( SCIPvarGetType(vars[varnr]) != SCIP_VARTYPE_CONTINUOUS ) 129 { 130 SCIP_CALL(SCIPcatchVarEvent(scip, vars[varnr], SCIP_EVENTTYPE_GBDCHANGED, eventhdlr, NULL, NULL)); 131 } 132 } 133 134 return SCIP_OKAY; 135 } 136 137 /** solving process deinitialization method of event handler (called before branch and bound process data is freed) */ 138 static 139 SCIP_DECL_EVENTEXITSOL(eventExitsolReopt) 140 { 141 SCIP_VAR** vars; 142 143 assert(scip != NULL); 144 145 assert(eventhdlr != NULL); 146 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 147 148 if( !SCIPisReoptEnabled(scip) ) 149 return SCIP_OKAY; 150 151 vars = SCIPgetVars(scip); 152 153 for( int varnr = 0; varnr < SCIPgetNVars(scip); ++varnr ) 154 { 155 if( SCIPvarGetType(vars[varnr]) == SCIP_VARTYPE_BINARY ) 156 { 157 SCIP_CALL(SCIPdropVarEvent(scip, vars[varnr], SCIP_EVENTTYPE_GBDCHANGED , eventhdlr, NULL, -1)); 158 } 159 } 160 return SCIP_OKAY; 161 } 162 163 /* ---------------- Callback methods of reoptimization methods ---------------- */ 164 165 /* 166 * memory growing methods for dynamically allocated arrays 167 */ 168 169 /** ensures size for activeconss */ 170 static 171 SCIP_RETCODE ensureActiveconssSize( 172 SCIP_REOPT* reopt, /**< reoptimization data structure */ 173 SCIP_SET* set, /**< global SCIP settings */ 174 BMS_BLKMEM* blkmem, /**< block memory */ 175 int num /**< minimum number of entries to store */ 176 ) 177 { 178 if( reopt->nmaxactiveconss < num ) 179 { 180 int newsize = SCIPsetCalcMemGrowSize(set, num + 1); 181 182 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->activeconss, reopt->nmaxactiveconss, newsize) ); 183 reopt->nmaxactiveconss = newsize; 184 } 185 assert(num <= reopt->nmaxactiveconss); 186 187 return SCIP_OKAY; 188 } 189 190 /** ensures, that sols[pos] array can store at least num entries */ 191 static 192 SCIP_RETCODE ensureSolsSize( 193 SCIP_REOPT* reopt, /**< reoptimization data structure */ 194 SCIP_SET* set, /**< global SCIP settings */ 195 BMS_BLKMEM* blkmem, /**< block memory */ 196 int num, /**< minimum number of entries to store */ 197 int runidx /**< run index for which the memory should checked */ 198 ) 199 { 200 assert(runidx >= 0); 201 assert(runidx <= reopt->runsize); 202 203 if( num > reopt->soltree->solssize[runidx] ) 204 { 205 int newsize = SCIPsetCalcMemGrowSize(set, num + 1); 206 207 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->soltree->sols[runidx], 208 reopt->soltree->solssize[runidx], newsize) ); /*lint !e866 */ 209 210 reopt->soltree->solssize[runidx] = newsize; 211 } 212 assert(num <= reopt->soltree->solssize[runidx]); 213 214 return SCIP_OKAY; 215 } 216 217 /** ensures, that sols array can store at least num entries */ 218 static 219 SCIP_RETCODE ensureRunSize( 220 SCIP_REOPT* reopt, /**< reoptimization data structure */ 221 SCIP_SET* set, /**< gloabl SCIP settings */ 222 int num, /**< minimum number of entries to store */ 223 BMS_BLKMEM* blkmem /**< block memory */ 224 ) 225 { 226 if( num >= reopt->runsize ) 227 { 228 int newsize = SCIPsetCalcMemGrowSize(set, num+1); 229 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->soltree->sols, reopt->runsize, newsize) ); 230 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->soltree->nsols, reopt->runsize, newsize) ); 231 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->soltree->solssize, reopt->runsize, newsize) ); 232 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->prevbestsols, reopt->runsize, newsize) ); 233 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->varhistory, reopt->runsize, newsize) ); 234 SCIP_ALLOC( BMSreallocMemoryArray(&reopt->objs, newsize) ); 235 236 for( int s = reopt->runsize; s < newsize; ++s ) 237 { 238 reopt->varhistory[s] = NULL; 239 reopt->prevbestsols[s] = NULL; 240 reopt->objs[s] = NULL; 241 reopt->soltree->solssize[s] = 0; 242 reopt->soltree->nsols[s] = 0; 243 reopt->soltree->sols[s] = NULL; 244 } 245 246 reopt->runsize = newsize; 247 } 248 assert(num < reopt->runsize); 249 250 return SCIP_OKAY; 251 } 252 253 /** check the memory of the reoptimization tree and if necessary reallocate */ 254 static 255 SCIP_RETCODE reopttreeCheckMemory( 256 SCIP_REOPTTREE* reopttree, /**< reoptimization tree */ 257 SCIP_SET* set, /**< global SCIP settings */ 258 BMS_BLKMEM* blkmem /**< block memory */ 259 ) 260 { 261 assert(reopttree != NULL); 262 assert(blkmem != NULL); 263 264 if( SCIPqueueIsEmpty(reopttree->openids) ) 265 { 266 int newsize; 267 268 assert(reopttree->nreoptnodes == (int)(reopttree->reoptnodessize)); 269 270 newsize = SCIPsetCalcMemGrowSize(set, (int)reopttree->reoptnodessize+1); 271 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopttree->reoptnodes, reopttree->reoptnodessize, newsize) ); /*lint !e647*/ 272 273 for( unsigned int id = reopttree->reoptnodessize; id < (unsigned int)newsize; ++id ) 274 { 275 SCIP_CALL( SCIPqueueInsertUInt(reopttree->openids, id) ); 276 reopttree->reoptnodes[id] = NULL; 277 } 278 279 reopttree->reoptnodessize = (unsigned int)newsize; 280 } 281 282 return SCIP_OKAY; 283 } 284 285 /** check allocated memory of a node within the reoptimization tree and if necessary reallocate */ 286 static 287 SCIP_RETCODE reoptnodeCheckMemory( 288 SCIP_REOPTNODE* reoptnode, /**< node of the reoptimization tree */ 289 SCIP_SET* set, /**< global SCIP settings */ 290 BMS_BLKMEM* blkmem, /**< block memory */ 291 int var_mem, /**< memory for variables */ 292 int child_mem, /**< memory for child nodes */ 293 int conss_mem /**< memory for constraints */ 294 ) 295 { 296 int newsize; 297 298 assert(reoptnode != NULL); 299 assert(blkmem != NULL); 300 assert(var_mem >= 0); 301 assert(child_mem >= 0); 302 assert(conss_mem >= 0); 303 304 /* check allocated memory for variable and bound information */ 305 if( var_mem > 0 ) 306 { 307 if( reoptnode->varssize == 0 ) 308 { 309 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reoptnode->vars, var_mem) ); 310 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reoptnode->varbounds, var_mem) ); 311 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reoptnode->varboundtypes, var_mem) ); 312 reoptnode->varssize = var_mem; 313 } 314 else if( reoptnode->varssize < var_mem ) 315 { 316 newsize = SCIPsetCalcMemGrowSize(set, var_mem+1); 317 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reoptnode->vars, reoptnode->varssize, newsize) ); 318 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reoptnode->varbounds, reoptnode->varssize, newsize) ); 319 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reoptnode->varboundtypes, reoptnode->varssize, newsize) ); 320 reoptnode->varssize = newsize; 321 } 322 } 323 324 /* check allocated memory for child node information */ 325 if( child_mem > 0 ) 326 { 327 if( reoptnode->allocchildmem == 0 ) 328 { 329 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reoptnode->childids, child_mem) ); 330 reoptnode->nchilds = 0; 331 reoptnode->allocchildmem = child_mem; 332 } 333 else if( reoptnode->allocchildmem < child_mem ) 334 { 335 newsize = SCIPsetCalcMemGrowSize(set, child_mem+1); 336 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reoptnode->childids, reoptnode->allocchildmem, newsize) ); 337 reoptnode->allocchildmem = newsize; 338 } 339 } 340 341 /* check allocated memory for add constraints */ 342 if( conss_mem > 0 ) 343 { 344 if( reoptnode->consssize == 0 ) 345 { 346 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reoptnode->conss, conss_mem) ); 347 reoptnode->nconss = 0; 348 reoptnode->consssize = conss_mem; 349 } 350 else if( reoptnode->consssize < conss_mem ) 351 { 352 newsize = SCIPsetCalcMemGrowSize(set, conss_mem); 353 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reoptnode->conss, reoptnode->consssize, newsize) ); 354 reoptnode->consssize = newsize; 355 } 356 } 357 358 return SCIP_OKAY; 359 } 360 361 /* 362 * local methods 363 */ 364 365 /** returns the number of stored solutions in the subtree induced by @p solnode */ 366 static 367 int soltreeNInducedSols( 368 SCIP_SOLNODE* solnode /**< node within the solution tree */ 369 ) 370 { 371 SCIP_SOLNODE* sibling; 372 int nsols; 373 374 assert(solnode != NULL); 375 376 if( solnode->child == NULL && solnode->sol == NULL ) 377 return 0; 378 if( solnode->child == NULL && solnode->sol != NULL ) 379 return 1; 380 381 nsols = 0; 382 sibling = solnode->child; 383 384 /* traverse through the list */ 385 while( sibling != NULL ) 386 { 387 nsols += soltreeNInducedSols(sibling); 388 sibling = sibling->sibling; 389 } 390 391 return nsols; 392 } 393 394 /** returns the similarity of the objective functions of two given iterations */ 395 static 396 SCIP_Real reoptSimilarity( 397 SCIP_REOPT* reopt, /**< reoptimization data */ 398 SCIP_SET* set, /**< global SCIP settings */ 399 int obj1_id, /**< id of one objective function */ 400 int obj2_id, /**< id of the other objective function */ 401 SCIP_VAR** vars, /**< problem variables */ 402 int nvars /**< number of problem variables */ 403 ) 404 { 405 SCIP_Real similarity; 406 SCIP_Real norm_obj1; 407 SCIP_Real norm_obj2; 408 409 assert(reopt != NULL); 410 assert(vars != NULL); 411 assert(nvars >= 0); 412 413 similarity = 0.0; 414 norm_obj1 = 0.0; 415 norm_obj2 = 0.0; 416 417 /* calculate similarity */ 418 for( int v = 0; v < nvars; ++v ) 419 { 420 SCIP_VAR* origvar; 421 SCIP_VAR* transvar; 422 SCIP_Real c1; 423 SCIP_Real c2; 424 SCIP_Real lb; 425 SCIP_Real ub; 426 427 origvar = vars[v]; 428 429 /* get the original variable */ 430 if( !SCIPvarIsOriginal(origvar) ) 431 { 432 SCIP_RETCODE retcode; 433 SCIP_Real constant = 0.0; 434 SCIP_Real scalar = 1.0; 435 436 retcode = SCIPvarGetOrigvarSum(&origvar, &scalar, &constant); 437 438 if( retcode != SCIP_OKAY ) 439 return SCIP_INVALID; 440 } 441 assert(origvar != NULL && SCIPvarIsOriginal(origvar)); 442 443 /* get the transformed variable, we skip globally fixed variables */ 444 transvar = SCIPvarGetTransVar(origvar); 445 assert(transvar != NULL); 446 447 lb = SCIPvarGetLbLocal(transvar); 448 ub = SCIPvarGetUbLocal(transvar); 449 450 if( SCIPsetIsFeasLT(set, lb, ub) ) 451 { 452 int probidx; 453 454 probidx = SCIPvarGetIndex(origvar); 455 assert(0 <= probidx && probidx < reopt->nobjvars); 456 457 c1 = reopt->objs[obj1_id][probidx]; 458 c2 = reopt->objs[obj2_id][probidx]; 459 460 /* vector product */ 461 similarity += c1*c2; 462 norm_obj1 += SQR(c1); 463 norm_obj2 += SQR(c2); 464 } 465 } 466 467 /* divide similarity by norms of the objective vectors */ 468 norm_obj1 = SQRT(norm_obj1); 469 norm_obj2 = SQRT(norm_obj2); 470 471 if( !SCIPsetIsZero(set, norm_obj1) && !SCIPsetIsZero(set, norm_obj2) ) 472 similarity /= (norm_obj1 * norm_obj2); 473 474 /* make sure that we are between -1.0 und +1.0 */ 475 similarity = MAX(similarity, -1.0); 476 similarity = MIN(similarity, 1.0); 477 478 return similarity; 479 } 480 481 /** delete the given reoptimization node */ 482 static 483 SCIP_RETCODE reoptnodeDelete( 484 SCIP_REOPTNODE** reoptnode, /**< node of the reoptimization tree */ 485 BMS_BLKMEM* blkmem /**< block memory */ 486 ) 487 { 488 assert((*reoptnode) != NULL ); 489 assert(blkmem != NULL ); 490 491 /* delete data for constraints */ 492 if( (*reoptnode)->consssize > 0 ) 493 { 494 assert((*reoptnode)->conss != NULL); 495 496 for( int c = 0; c < (*reoptnode)->nconss; ++c ) 497 { 498 assert((*reoptnode)->conss[c] != NULL); 499 assert((*reoptnode)->conss[c]->vals != NULL); 500 assert((*reoptnode)->conss[c]->vars != NULL); 501 502 BMSfreeBlockMemoryArrayNull(blkmem, &(*reoptnode)->conss[c]->boundtypes, (*reoptnode)->conss[c]->varssize); 503 BMSfreeBlockMemoryArrayNull(blkmem, &(*reoptnode)->conss[c]->vals, (*reoptnode)->conss[c]->varssize); 504 BMSfreeBlockMemoryArrayNull(blkmem, &(*reoptnode)->conss[c]->vars, (*reoptnode)->conss[c]->varssize); 505 BMSfreeBlockMemory(blkmem, &(*reoptnode)->conss[c]); /*lint !e866*/ 506 } 507 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->conss, (*reoptnode)->consssize); 508 (*reoptnode)->nconss = 0; 509 (*reoptnode)->consssize = 0; 510 (*reoptnode)->conss = NULL; 511 } 512 513 /* free list of children */ 514 if( (*reoptnode)->childids != NULL ) 515 { 516 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->childids, (*reoptnode)->allocchildmem); 517 (*reoptnode)->nchilds = 0; 518 (*reoptnode)->allocchildmem = 0; 519 (*reoptnode)->childids = NULL; 520 } 521 522 /* delete dual constraint */ 523 if( (*reoptnode)->dualredscur != NULL ) 524 { 525 assert((*reoptnode)->dualredscur->varssize > 0); 526 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->dualredscur->boundtypes, (*reoptnode)->dualredscur->varssize); 527 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->dualredscur->vals, (*reoptnode)->dualredscur->varssize); 528 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->dualredscur->vars, (*reoptnode)->dualredscur->varssize); 529 BMSfreeBlockMemory(blkmem, &(*reoptnode)->dualredscur); 530 (*reoptnode)->dualredscur = NULL; 531 } 532 533 /* delete dual constraint */ 534 if( (*reoptnode)->dualredsnex != NULL ) 535 { 536 assert((*reoptnode)->dualredsnex->varssize > 0); 537 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->dualredsnex->boundtypes, (*reoptnode)->dualredsnex->varssize); 538 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->dualredsnex->vals, (*reoptnode)->dualredsnex->varssize); 539 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->dualredsnex->vars, (*reoptnode)->dualredsnex->varssize); 540 BMSfreeBlockMemory(blkmem, &(*reoptnode)->dualredsnex); 541 (*reoptnode)->dualredsnex = NULL; 542 } 543 544 /* free boundtypes */ 545 if ((*reoptnode)->varboundtypes != NULL ) 546 { 547 assert((*reoptnode)->varssize > 0); 548 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->varboundtypes, (*reoptnode)->varssize); 549 (*reoptnode)->varboundtypes = NULL; 550 } 551 552 /* free bounds */ 553 if ((*reoptnode)->varbounds != NULL ) 554 { 555 assert((*reoptnode)->varssize > 0); 556 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->varbounds, (*reoptnode)->varssize); 557 (*reoptnode)->varbounds = NULL; 558 } 559 560 /* free variables */ 561 if ((*reoptnode)->vars != NULL ) 562 { 563 assert((*reoptnode)->varssize > 0); 564 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->vars, (*reoptnode)->varssize); 565 (*reoptnode)->vars = NULL; 566 } 567 568 (*reoptnode)->varssize = 0; 569 570 /* free afterdual-boundtypes */ 571 if ((*reoptnode)->afterdualvarboundtypes != NULL ) 572 { 573 assert((*reoptnode)->afterdualvarssize > 0); 574 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->afterdualvarboundtypes, (*reoptnode)->afterdualvarssize); 575 (*reoptnode)->afterdualvarboundtypes = NULL; 576 } 577 578 /* free afterdual-bounds */ 579 if ((*reoptnode)->afterdualvarbounds != NULL ) 580 { 581 assert((*reoptnode)->afterdualvarssize > 0); 582 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->afterdualvarbounds, (*reoptnode)->afterdualvarssize); 583 (*reoptnode)->afterdualvarbounds = NULL; 584 } 585 586 /* free afterdual-variables */ 587 if ((*reoptnode)->afterdualvars != NULL ) 588 { 589 assert((*reoptnode)->afterdualvarssize > 0); 590 BMSfreeBlockMemoryArray(blkmem, &(*reoptnode)->afterdualvars, (*reoptnode)->afterdualvarssize); 591 (*reoptnode)->afterdualvars = NULL; 592 } 593 594 (*reoptnode)->afterdualvarssize = 0; 595 596 BMSfreeBlockMemory(blkmem, reoptnode); 597 (*reoptnode) = NULL; 598 599 return SCIP_OKAY; 600 } 601 602 /** reset the given reoptimization node */ 603 static 604 SCIP_RETCODE reoptnodeReset( 605 SCIP_REOPTNODE* reoptnode, /**< reoptimization node */ 606 SCIP_SET* set, /**< global SCIP settings */ 607 BMS_BLKMEM* blkmem /**< block memory */ 608 ) 609 { 610 assert(reoptnode != NULL); 611 assert(set != NULL); 612 assert(blkmem != NULL); 613 614 /* remove and delete all constraints */ 615 if( reoptnode->nconss > 0 ) 616 { 617 assert(reoptnode->conss != NULL); 618 assert(reoptnode->consssize > 0); 619 620 for( int c = 0; c < reoptnode->nconss; ++c ) 621 { 622 if( !reoptnode->conss[c]->linear ) 623 { 624 assert(reoptnode->conss[c]->boundtypes != NULL); 625 BMSfreeBlockMemoryArray(blkmem, &reoptnode->conss[c]->boundtypes, reoptnode->conss[c]->varssize); 626 } 627 BMSfreeBlockMemoryArray(blkmem, &reoptnode->conss[c]->vals, reoptnode->conss[c]->varssize); 628 BMSfreeBlockMemoryArray(blkmem, &reoptnode->conss[c]->vars, reoptnode->conss[c]->varssize); 629 BMSfreeBlockMemory(blkmem, &reoptnode->conss[c]); /*lint !e866 */ 630 } 631 reoptnode->nconss = 0; 632 } 633 634 /* remove all children */ 635 if( reoptnode->childids != NULL ) 636 reoptnode->nchilds = 0; 637 638 /* delete dual constraint */ 639 if( reoptnode->dualredscur != NULL ) 640 { 641 assert(reoptnode->dualredscur->varssize > 0); 642 if( !reoptnode->dualredscur->linear ) 643 { 644 assert(reoptnode->dualredscur->boundtypes != NULL); 645 BMSfreeBlockMemoryArray(blkmem, &reoptnode->dualredscur->boundtypes, reoptnode->dualredscur->varssize); 646 } 647 BMSfreeBlockMemoryArray(blkmem, &reoptnode->dualredscur->vals, reoptnode->dualredscur->varssize); 648 BMSfreeBlockMemoryArray(blkmem, &reoptnode->dualredscur->vars, reoptnode->dualredscur->varssize); 649 BMSfreeBlockMemory(blkmem, &reoptnode->dualredscur); 650 reoptnode->dualredscur = NULL; 651 } 652 653 /* delete dual constraint */ 654 if( reoptnode->dualredsnex != NULL ) 655 { 656 assert(reoptnode->dualredsnex->varssize > 0); 657 if( !reoptnode->dualredsnex->linear ) 658 { 659 assert(reoptnode->dualredsnex->boundtypes != NULL); 660 BMSfreeBlockMemoryArray(blkmem, &reoptnode->dualredsnex->boundtypes, reoptnode->dualredsnex->varssize); 661 } 662 BMSfreeBlockMemoryArray(blkmem, &reoptnode->dualredsnex->vals, reoptnode->dualredsnex->varssize); 663 BMSfreeBlockMemoryArray(blkmem, &reoptnode->dualredsnex->vars, reoptnode->dualredsnex->varssize); 664 BMSfreeBlockMemory(blkmem, &reoptnode->dualredsnex); 665 reoptnode->dualredsnex = NULL; 666 } 667 668 reoptnode->parentID = 0; 669 reoptnode->nvars = 0; 670 reoptnode->nafterdualvars = 0; 671 reoptnode->dualreds = FALSE; 672 reoptnode->reopttype = (unsigned int)SCIP_REOPTTYPE_NONE; 673 reoptnode->lowerbound = -SCIPsetInfinity(set); 674 675 return SCIP_OKAY; 676 } 677 678 /** delete the node stored at position @p nodeID of the reoptimization tree */ 679 static 680 SCIP_RETCODE reopttreeDeleteNode( 681 SCIP_REOPTTREE* reopttree, /**< reoptimization tree */ 682 SCIP_SET* set, /**< global SCIP settings */ 683 BMS_BLKMEM* blkmem, /**< block memory */ 684 unsigned int id, /**< id of a node */ 685 SCIP_Bool softreset /**< delete at the end of the solving process */ 686 ) 687 { 688 assert(reopttree != NULL ); 689 assert(id < reopttree->reoptnodessize); 690 assert(reopttree->reoptnodes[id] != NULL ); 691 692 if( softreset ) 693 { 694 SCIP_CALL( reoptnodeReset(reopttree->reoptnodes[id], set, blkmem) ); 695 } 696 else 697 { 698 SCIP_CALL( reoptnodeDelete(&reopttree->reoptnodes[id], blkmem) ); 699 } 700 701 assert(softreset || reopttree->reoptnodes[id] == NULL); 702 assert(reopttree->reoptnodes[id] == NULL || reopttree->reoptnodes[id]->conss == NULL || reopttree->reoptnodes[id]->nconss == 0); 703 assert(reopttree->reoptnodes[id] == NULL || reopttree->reoptnodes[id]->childids == NULL || reopttree->reoptnodes[id]->nchilds == 0); 704 705 --reopttree->nreoptnodes; 706 707 return SCIP_OKAY; 708 } 709 710 /** constructor of the solution tree */ 711 static 712 SCIP_RETCODE createSolTree( 713 SCIP_SOLTREE* soltree, /**< solution tree */ 714 BMS_BLKMEM* blkmem /**< block memory */ 715 ) 716 { 717 assert(soltree != NULL); 718 719 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &soltree->sols, DEFAULT_MEM_RUN) ); 720 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &soltree->nsols, DEFAULT_MEM_RUN) ); 721 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &soltree->solssize, DEFAULT_MEM_RUN) ); 722 723 for( int s = 0; s < DEFAULT_MEM_RUN; ++s ) 724 { 725 soltree->nsols[s] = 0; 726 soltree->solssize[s] = 0; 727 soltree->sols[s] = NULL; 728 } 729 730 /* allocate the root node */ 731 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &soltree->root) ); 732 soltree->root->sol = NULL; 733 soltree->root->value = SCIP_INVALID; 734 soltree->root->updated = FALSE; 735 soltree->root->father = NULL; 736 soltree->root->child = NULL; 737 soltree->root->sibling = NULL; 738 739 return SCIP_OKAY; 740 } 741 742 /** free the given solution node */ 743 static 744 SCIP_RETCODE soltreefreeNode( 745 SCIP_REOPT* reopt, /**< reoptimization data */ 746 SCIP_SET* set, /**< global SCIP settings */ 747 SCIP_PRIMAL* primal, /**< the primal */ 748 BMS_BLKMEM* blkmem, /**< block memory */ 749 SCIP_SOLNODE** solnode /**< node within the solution tree */ 750 ) 751 { 752 SCIP_SOLNODE* child; 753 SCIP_SOLNODE* sibling; 754 755 assert(reopt != NULL); 756 assert(set != NULL); 757 assert(primal != NULL || set->stage == SCIP_STAGE_INIT); 758 assert(solnode != NULL); 759 assert(blkmem != NULL); 760 761 child = (*solnode)->child; 762 763 /* traverse through the list and free recursive all subtree */ 764 while( child != NULL ) 765 { 766 SCIP_CALL( soltreefreeNode(reopt, set, primal, blkmem, &child) ); 767 assert(child != NULL); 768 769 sibling = child->sibling; 770 BMSfreeBlockMemoryNull(blkmem, &child); 771 child = sibling; 772 } 773 774 if( (*solnode)->sol != NULL ) 775 { 776 assert(set->stage == SCIP_STAGE_PROBLEM); 777 778 SCIP_CALL( SCIPsolFree(&(*solnode)->sol, blkmem, primal) ); 779 } 780 781 return SCIP_OKAY; 782 } 783 784 /** free the solution tree */ 785 static 786 SCIP_RETCODE freeSolTree( 787 SCIP_REOPT* reopt, /**< reoptimization data */ 788 SCIP_SET* set, /**< global SCIP settings */ 789 SCIP_PRIMAL* origprimal, /**< the origprimal */ 790 BMS_BLKMEM* blkmem /**< block memory */ 791 ) 792 { 793 assert(reopt != NULL); 794 assert(reopt->soltree != NULL); 795 assert(reopt->soltree->root != NULL); 796 assert(set != NULL); 797 assert(blkmem != NULL); 798 799 /* free all nodes recursive */ 800 SCIP_CALL( soltreefreeNode(reopt, set, origprimal, blkmem, &reopt->soltree->root) ); 801 BMSfreeBlockMemoryNull(blkmem, &reopt->soltree->root); 802 803 BMSfreeBlockMemoryArray(blkmem, &reopt->soltree->sols, reopt->runsize); 804 BMSfreeBlockMemoryArray(blkmem, &reopt->soltree->nsols, reopt->runsize); 805 BMSfreeBlockMemoryArray(blkmem, &reopt->soltree->solssize, reopt->runsize); 806 807 BMSfreeMemory(&reopt->soltree); 808 809 return SCIP_OKAY; 810 } 811 812 /** creates and adds a solution node to the solution tree */ 813 static 814 SCIP_RETCODE solnodeAddChild( 815 SCIP_SET* set, /**< global SCIP settings */ 816 BMS_BLKMEM* blkmem, /**< block memory */ 817 SCIP_SOLNODE* curnode, /**< current node in the solution tree */ 818 SCIP_SOLNODE** child, /**< pointer to store the node representing the solution value */ 819 SCIP_VAR* var, /**< variable represented by this node */ 820 SCIP_Real val, /**< value the child shell represent */ 821 SCIP_Bool* added /**< TRUE iff we created a new node, i.e, we have not seen this solution so far */ 822 ) 823 { 824 SCIP_SOLNODE* solnode; 825 826 assert(set != NULL); 827 assert(blkmem != NULL); 828 assert(curnode != NULL); 829 assert(child != NULL && *child == NULL); 830 assert(!SCIPsetIsInfinity(set, -val) && !SCIPsetIsInfinity(set, val)); 831 832 /* get the first node of the child node list */ 833 *child = curnode->child; 834 835 /* this is the first solution in the subtree induced by the current node */ 836 if( *child == NULL ) 837 { 838 assert(soltreeNInducedSols(curnode) == 0); 839 840 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &solnode) ); 841 solnode->sol = NULL; 842 solnode->updated = FALSE; 843 solnode->father = curnode; 844 solnode->child = NULL; 845 solnode->sibling = NULL; 846 solnode->value = val; 847 #ifndef NDEBUG 848 assert(var != NULL); 849 solnode->var = var; 850 #endif 851 852 *added = TRUE; 853 *child = solnode; 854 855 curnode->child = *child; 856 857 #ifdef SCIP_MORE_DEBUG 858 SCIPsetDebugMsg(set, "-> create new node %p: value=%g, sibling=%p\n", (void*) solnode, solnode->value, 859 (void*) solnode->sibling); 860 #endif 861 } 862 else 863 { 864 /* we traverse through all children */ 865 while( *child != NULL ) 866 { 867 #ifdef SCIP_MORE_DEBUG 868 SCIPsetDebugMsg(set, "-> check %p: father=%p, value=%g, sibling=%p\n", (void*) *child, (void*) (*child)->father, 869 (*child)->value, (void*) (*child)->sibling); 870 #endif 871 /* we found a node repesenting this solution value */ 872 if( SCIPsetIsEQ(set, val, (*child)->value) ) 873 break; 874 875 /* we are at the end of the list */ 876 if( (*child)->sibling == NULL ) 877 { 878 /* create a new solnode */ 879 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &solnode) ); 880 solnode->sol = NULL; 881 solnode->updated = FALSE; 882 solnode->father = curnode; 883 solnode->child = NULL; 884 solnode->value = val; 885 #ifndef NDEBUG 886 assert(var != NULL); 887 solnode->var = var; 888 #endif 889 *added = TRUE; 890 891 /* we have to append the new node at the end of the list. but we have to check whether the insertion before 892 * the current node would be correct. in that case, we switch the values, the child pointer, and the 893 * solution 894 */ 895 solnode->sibling = NULL; 896 (*child)->sibling = solnode; 897 898 #ifdef SCIP_MORE_DEBUG 899 SCIPsetDebugMsg(set, "-> create new node %p: value=%g, sibling=%p\n", (void*) solnode, solnode->value, 900 (void*) solnode->sibling); 901 #endif 902 /* the given value is lower than the current, insertion before the current node would be correct 903 * in this case we do not have to change the child pointer 904 */ 905 if( SCIPsetIsLT(set, val, (*child)->value) ) 906 { 907 #ifdef SCIP_MORE_DEBUG 908 SCIPsetDebugMsg(set, "-> need to switch:\n"); 909 SCIPsetDebugMsg(set, " before switching: node %p witch child=%p, sibling=%p, sol=%p, value=%g\n", 910 (void*) (*child), (void*) (*child)->child, (void*) (*child)->sibling, (void*) (*child)->sol, 911 (*child)->value); 912 SCIPsetDebugMsg(set, " node %p witch child=%p, sibling=%p, sol=%p, value=%g\n", 913 (void*) solnode, (void*) solnode->child, (void*) solnode->sibling, (void*) solnode->sol, 914 solnode->value); 915 #endif 916 /* switch child pointer */ 917 solnode->child = (*child)->child; 918 (*child)->child = NULL; 919 920 /* switch solution values */ 921 solnode->value = (*child)->value; 922 (*child)->value = val; 923 assert(SCIPsetIsLT(set, (*child)->value, solnode->value)); 924 925 /* switch solution pointer */ 926 solnode->sol = (*child)->sol; 927 (*child)->sol = NULL; 928 #ifdef SCIP_MORE_DEBUG 929 SCIPsetDebugMsg(set, " after switching: node %p witch child=%p, sibling=%p, sol=%p, value=%g\n", 930 (void*) (*child), (void*) (*child)->child, (void*) (*child)->sibling, (void*) (*child)->sol, 931 (*child)->value); 932 SCIPsetDebugMsg(set, " node %p witch child=%p, sibling=%p, sol=%p, value=%g\n", 933 (void*) solnode, (void*) solnode->child, (void*) solnode->sibling, (void*) solnode->sol, 934 solnode->value); 935 #endif 936 } 937 /* set the child pointer to the new created solnode */ 938 else 939 (*child) = solnode; 940 941 break; 942 } 943 944 /* the next sibling represents a solution value of larger size. 945 * we insert a new node between the current child and the next sibling. 946 */ 947 if( SCIPsetIsLT(set, val, (*child)->sibling->value) ) 948 { 949 /* create a new solnode that points to the sibling of the current child */ 950 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &solnode) ); 951 solnode->sol = NULL; 952 solnode->updated = FALSE; 953 solnode->father = curnode; 954 solnode->child = NULL; 955 solnode->sibling = (*child)->sibling; 956 solnode->value = val; 957 #ifndef NDEBUG 958 assert(var != NULL); 959 solnode->var = var; 960 #endif 961 *added = TRUE; 962 963 /* change the poiter of the next sibling to the new node */ 964 (*child)->sibling = solnode; 965 966 *child = solnode; 967 #ifdef SCIP_MORE_DEBUG 968 SCIPsetDebugMsg(set, "-> create new node %p: value=%g, sibling=%p\n", (void*) solnode, solnode->value, 969 (void*) solnode->sibling); 970 #endif 971 break; 972 } 973 974 /* go to the next sibling */ 975 *child = (*child)->sibling; 976 } 977 978 #ifdef SCIP_DEBUG 979 /* check whether the insert was correct and the list is increasing */ 980 solnode = curnode->child; 981 assert(solnode != NULL); 982 983 while( solnode->sibling != NULL ) 984 { 985 assert(SCIPsetIsLT(set, solnode->value, solnode->sibling->value)); 986 solnode = solnode->sibling; 987 } 988 #endif 989 } 990 return SCIP_OKAY; 991 } 992 993 /** add a solution to the solution tree */ 994 static 995 SCIP_RETCODE soltreeAddSol( 996 SCIP_REOPT* reopt, /**< reoptimization data */ 997 SCIP_SET* set, /**< global SCIP settings */ 998 SCIP_STAT* stat, /**< dynamic problem statistics */ 999 SCIP_PRIMAL* origprimal, /**< orig primal */ 1000 BMS_BLKMEM* blkmem, /**< block memory */ 1001 SCIP_VAR** vars, /**< array of original variables */ 1002 SCIP_SOL* sol, /**< solution to add */ 1003 SCIP_SOLNODE** solnode, /**< current solution node */ 1004 int nvars, /**< number of variables */ 1005 SCIP_Bool bestsol, /**< is the solution an optimal (best found) solution */ 1006 SCIP_Bool* added /**< pointer to store the result */ 1007 ) 1008 { 1009 SCIP_SOLNODE* cursolnode; 1010 SCIP_Bool purelp; 1011 1012 assert(reopt != NULL); 1013 assert(set != NULL); 1014 assert(stat != NULL); 1015 assert(origprimal != NULL); 1016 assert(blkmem != NULL); 1017 assert(vars != NULL); 1018 assert(sol != NULL); 1019 assert(solnode != NULL); 1020 1021 cursolnode = reopt->soltree->root; 1022 *added = FALSE; 1023 purelp = TRUE; 1024 1025 if( set->reopt_savesols > 0 ) 1026 { 1027 #ifdef MORE_DEBUG 1028 SCIPsetDebugMsg(set, "try to add solution found by <%s>\n", (SCIPsolGetHeur(sol) == NULL ? 1029 "relaxation" : SCIPheurGetName(SCIPsolGetHeur(sol)))); 1030 #endif 1031 1032 for( int varid = 0; varid < nvars; ++varid ) 1033 { 1034 if( SCIPvarGetType(vars[varid]) != SCIP_VARTYPE_CONTINUOUS ) 1035 { 1036 SCIP_SOLNODE* child; 1037 1038 purelp = FALSE; 1039 child = NULL; 1040 SCIP_CALL( solnodeAddChild(set, blkmem, cursolnode, &child, vars[varid], 1041 SCIPsolGetVal(sol, set, stat, vars[varid]), added) ); 1042 assert(child != NULL); 1043 cursolnode = child; 1044 } 1045 } 1046 1047 /* the solution was added or is an optimal solution */ 1048 if( (*added || bestsol) && !purelp ) 1049 { 1050 SCIP_SOL* copysol; 1051 1052 assert(cursolnode->child == NULL); 1053 1054 if( *added ) 1055 { 1056 SCIP_CALL( SCIPsolCopy(©sol, blkmem, set, stat, origprimal, sol) ); 1057 cursolnode->sol = copysol; 1058 } 1059 else 1060 /* this is a pseudo add; we do not want to save this solution more than once, but we will link this solution 1061 * to the solution storage of this round 1062 */ 1063 (*added) = TRUE; 1064 1065 if( bestsol ) 1066 { 1067 assert(reopt->prevbestsols != NULL); 1068 assert(cursolnode->sol != NULL); 1069 1070 reopt->prevbestsols[reopt->run-1] = cursolnode->sol; 1071 } 1072 1073 (*solnode) = cursolnode; 1074 } 1075 } 1076 1077 return SCIP_OKAY; 1078 } 1079 1080 /** reset all marks 'updated' to FALSE */ 1081 static 1082 void soltreeResetMarks( 1083 SCIP_SOLNODE* node /**< node within the solution tree */ 1084 ) 1085 { 1086 assert(node != NULL); 1087 1088 if( node->child != NULL ) 1089 { 1090 SCIP_SOLNODE* child; 1091 1092 /* the node is no leaf */ 1093 assert(node->sol == NULL); 1094 assert(!node->updated); 1095 1096 child = node->child; 1097 1098 /* traverse through the list of siblings */ 1099 while( child != NULL ) 1100 { 1101 soltreeResetMarks(child); 1102 child = child->sibling; 1103 } 1104 } 1105 else 1106 { 1107 /* the node is a leaf */ 1108 assert(node->father != NULL); 1109 assert(node->sol != NULL); 1110 node->updated = FALSE; 1111 } 1112 } 1113 1114 /** allocate memory for a node within the reoptimization tree */ 1115 static 1116 SCIP_RETCODE createReoptnode( 1117 SCIP_REOPTTREE* reopttree, /**< reoptimization tree */ 1118 SCIP_SET* set, /**< global SCIP settings */ 1119 BMS_BLKMEM* blkmem, /**< block memory */ 1120 unsigned int id /**< id of the node to create */ 1121 ) 1122 { 1123 assert(reopttree != NULL ); 1124 assert(id < reopttree->reoptnodessize); 1125 1126 SCIPsetDebugMsg(set, "create a reoptnode at ID %u\n", id); 1127 1128 if( reopttree->reoptnodes[id] == NULL ) 1129 { 1130 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &reopttree->reoptnodes[id]) ); /*lint !e866*/ 1131 1132 reopttree->reoptnodes[id]->conss = NULL; 1133 reopttree->reoptnodes[id]->nconss = 0; 1134 reopttree->reoptnodes[id]->consssize = 0; 1135 reopttree->reoptnodes[id]->childids = NULL; 1136 reopttree->reoptnodes[id]->allocchildmem = 0; 1137 reopttree->reoptnodes[id]->nchilds = 0; 1138 reopttree->reoptnodes[id]->nvars = 0; 1139 reopttree->reoptnodes[id]->nafterdualvars = 0; 1140 reopttree->reoptnodes[id]->parentID = 0; 1141 reopttree->reoptnodes[id]->dualreds = FALSE; 1142 reopttree->reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_NONE; 1143 reopttree->reoptnodes[id]->varssize = 0; 1144 reopttree->reoptnodes[id]->afterdualvarssize = 0; 1145 reopttree->reoptnodes[id]->vars = NULL; 1146 reopttree->reoptnodes[id]->varbounds = NULL; 1147 reopttree->reoptnodes[id]->varboundtypes = NULL; 1148 reopttree->reoptnodes[id]->afterdualvars = NULL; 1149 reopttree->reoptnodes[id]->afterdualvarbounds = NULL; 1150 reopttree->reoptnodes[id]->afterdualvarboundtypes = NULL; 1151 reopttree->reoptnodes[id]->dualredscur = NULL; 1152 reopttree->reoptnodes[id]->dualredsnex = NULL; 1153 reopttree->reoptnodes[id]->lowerbound = -SCIPsetInfinity(set); 1154 } 1155 else 1156 { 1157 assert(reopttree->reoptnodes[id]->nvars == 0); 1158 assert(reopttree->reoptnodes[id]->nafterdualvars == 0); 1159 reopttree->reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_NONE; 1160 reopttree->reoptnodes[id]->lowerbound = -SCIPsetInfinity(set); 1161 } 1162 1163 /* increase the counter */ 1164 ++reopttree->nreoptnodes; 1165 1166 assert(reopttree->nreoptnodes + SCIPqueueNElems(reopttree->openids) == (int)reopttree->reoptnodessize); 1167 1168 return SCIP_OKAY; 1169 } 1170 1171 /** constructor of the reoptimization tree */ 1172 static 1173 SCIP_RETCODE createReopttree( 1174 SCIP_REOPTTREE* reopttree, /**< pointer to the reoptimization tree */ 1175 SCIP_SET* set, /**< global SCIP settings */ 1176 BMS_BLKMEM* blkmem /**< block memory */ 1177 ) 1178 { 1179 assert(reopttree != NULL); 1180 assert(set != NULL); 1181 assert(blkmem != NULL); 1182 1183 /* allocate memory */ 1184 reopttree->reoptnodessize = DEFAULT_MEM_NODES; 1185 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reopttree->reoptnodes, reopttree->reoptnodessize) ); 1186 1187 /* initialize the queue of open IDs */ 1188 SCIP_CALL( SCIPqueueCreate(&reopttree->openids, (int)reopttree->reoptnodessize, 2.0) ); 1189 1190 /* fill the queue, but reserve the 0 for the root */ 1191 for( unsigned int id = 1; id < reopttree->reoptnodessize; ++id ) 1192 { 1193 reopttree->reoptnodes[id] = NULL; 1194 SCIP_CALL( SCIPqueueInsertUInt(reopttree->openids, id) ); 1195 } 1196 assert(SCIPqueueNElems(reopttree->openids) == (int)(reopttree->reoptnodessize)-1); 1197 1198 reopttree->nreoptnodes = 0; 1199 reopttree->ntotalfeasnodes = 0; 1200 reopttree->nfeasnodes = 0; 1201 reopttree->ninfnodes = 0; 1202 reopttree->ntotalinfnodes= 0; 1203 reopttree->nprunednodes = 0; 1204 reopttree->ntotalprunednodes= 0; 1205 reopttree->ncutoffreoptnodes = 0; 1206 reopttree->ntotalcutoffreoptnodes = 0; 1207 1208 /* initialize the root node */ 1209 reopttree->reoptnodes[0] = NULL; 1210 SCIP_CALL( createReoptnode(reopttree, set, blkmem, 0) ); 1211 1212 return SCIP_OKAY; 1213 } 1214 1215 /** clears the reopttree, e.g., to restart and solve the next problem from scratch */ 1216 static 1217 SCIP_RETCODE clearReoptnodes( 1218 SCIP_REOPTTREE* reopttree, /**< reoptimization tree */ 1219 SCIP_SET* set, /**< global SCIP settings */ 1220 BMS_BLKMEM* blkmem, /**< block memory */ 1221 SCIP_Bool softreset /**< delete nodes before exit the solving process */ 1222 ) 1223 { 1224 assert(reopttree != NULL ); 1225 1226 /* clear queue with open IDs */ 1227 SCIPqueueClear(reopttree->openids); 1228 assert(SCIPqueueNElems(reopttree->openids) == 0); 1229 1230 /* delete all data about nodes */ 1231 for( unsigned int id = 0; id < reopttree->reoptnodessize; ++id ) 1232 { 1233 if( reopttree->reoptnodes[id] != NULL ) 1234 { 1235 SCIP_CALL( reopttreeDeleteNode(reopttree, set, blkmem, id, softreset) ); 1236 assert(reopttree->reoptnodes[id] == NULL || reopttree->reoptnodes[id]->nvars == 0); 1237 } 1238 1239 if( id > 0 ) 1240 { 1241 SCIP_CALL( SCIPqueueInsertUInt(reopttree->openids, id) ); 1242 } 1243 } 1244 assert(SCIPqueueNElems(reopttree->openids) == (int)(reopttree->reoptnodessize)-1); 1245 1246 reopttree->nreoptnodes = 0; 1247 1248 return SCIP_OKAY; 1249 } 1250 1251 /** free the reoptimization tree */ 1252 static 1253 SCIP_RETCODE freeReoptTree( 1254 SCIP_REOPTTREE* reopttree, /**< reoptimization tree data */ 1255 SCIP_SET* set, /**< global SCIP settings */ 1256 BMS_BLKMEM* blkmem /**< block memory */ 1257 ) 1258 { 1259 assert(reopttree != NULL); 1260 assert(blkmem != NULL); 1261 1262 /* free nodes */ 1263 SCIP_CALL( clearReoptnodes(reopttree, set, blkmem, FALSE) ); 1264 1265 /* free the data */ 1266 BMSfreeBlockMemoryArray(blkmem, &reopttree->reoptnodes, reopttree->reoptnodessize); 1267 SCIPqueueFree(&reopttree->openids); 1268 1269 /* free the tree itself */ 1270 BMSfreeMemory(&reopttree); 1271 1272 return SCIP_OKAY; 1273 } 1274 1275 /** check memory for the constraint to handle bound changes based on dual information */ 1276 static 1277 SCIP_RETCODE checkMemDualCons( 1278 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1279 SCIP_SET* set, /**< global SCIP settings */ 1280 BMS_BLKMEM* blkmem, /**< block memory */ 1281 int size /**< size which need to be allocated */ 1282 ) 1283 { 1284 assert(reopt != NULL); 1285 assert(blkmem != NULL); 1286 assert(size > 0); 1287 1288 if( reopt->dualreds == NULL ) 1289 { 1290 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &reopt->dualreds) ); 1291 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reopt->dualreds->vars, size) ); 1292 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reopt->dualreds->vals, size) ); 1293 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reopt->dualreds->boundtypes, size) ); 1294 reopt->dualreds->varssize = size; 1295 reopt->dualreds->nvars = 0; 1296 } 1297 else if( reopt->dualreds->varssize < size ) 1298 { 1299 int newsize = SCIPsetCalcMemGrowSize(set, size+1); 1300 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->dualreds->vars, reopt->dualreds->varssize, newsize) ); 1301 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->dualreds->vals, reopt->dualreds->varssize, newsize) ); 1302 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->dualreds->boundtypes, reopt->dualreds->varssize, newsize) ); 1303 reopt->dualreds->varssize = newsize; 1304 } 1305 1306 return SCIP_OKAY; 1307 } 1308 1309 /** check the memory to store global constraints */ 1310 static 1311 SCIP_RETCODE checkMemGlbCons( 1312 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1313 SCIP_SET* set, /**< global SCIP settings */ 1314 BMS_BLKMEM* blkmem, /**< block memory */ 1315 int mem /**< memory which has to be allocated */ 1316 ) 1317 { 1318 assert(reopt != NULL); 1319 assert(blkmem != NULL); 1320 assert(mem > 0); 1321 1322 if( mem > 0 ) /*lint !e774*/ 1323 { 1324 if( reopt->glbconss == NULL ) 1325 { 1326 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reopt->glbconss, mem) ); 1327 reopt->nglbconss = 0; 1328 reopt->allocmemglbconss = mem; 1329 1330 for( int c = 0; c < reopt->allocmemglbconss; ++c ) 1331 reopt->glbconss[c] = NULL; 1332 } 1333 else if( reopt->allocmemglbconss < mem ) 1334 { 1335 int newsize = SCIPsetCalcMemGrowSize(set, mem+1); 1336 1337 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->glbconss, reopt->allocmemglbconss, newsize) ); 1338 1339 for( int c = reopt->allocmemglbconss; c < newsize; ++c ) 1340 reopt->glbconss[c] = NULL; 1341 1342 reopt->allocmemglbconss = newsize; 1343 } 1344 } 1345 1346 return SCIP_OKAY; 1347 } 1348 1349 /** reactivate globally valid constraints that were deactivated and necessary to ensure correctness */ 1350 static 1351 SCIP_RETCODE cleanActiveConss( 1352 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1353 SCIP_SET* set, /**< global SCIP settings */ 1354 BMS_BLKMEM* blkmem /**< block memory */ 1355 ) 1356 { 1357 assert(reopt != NULL); 1358 1359 /* exit if there are no active constraints */ 1360 if( reopt->nactiveconss == 0 ) 1361 return SCIP_OKAY; 1362 1363 SCIPsetDebugMsg(set, "Cleaning %d active conss.\n", reopt->nactiveconss); 1364 assert(reopt->activeconss != NULL); 1365 assert(reopt->activeconssset != NULL); 1366 assert(reopt->nactiveconss <= reopt->nmaxactiveconss); 1367 1368 /* loop over all stored constraints and reactivate deactivated constraints */ 1369 for( int i = 0; i < reopt->nactiveconss; ++i ) 1370 { 1371 assert(reopt->activeconss[i] != NULL); 1372 assert(SCIPhashsetExists(reopt->activeconssset, reopt->activeconss[i])); 1373 SCIP_CALL( SCIPconsRelease(&reopt->activeconss[i], blkmem, set) ); 1374 } 1375 1376 /* also clean up hashset */ 1377 SCIPhashsetRemoveAll(reopt->activeconssset); 1378 reopt->nactiveconss = 0; 1379 1380 return SCIP_OKAY; 1381 } 1382 1383 /** update the bound changes made by constraint propagations during current iteration; stop saving the bound changes if 1384 * we reach a branching decision based on a dual information. 1385 */ 1386 static 1387 SCIP_RETCODE updateConstraintPropagation( 1388 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1389 SCIP_SET* set, /**< global SCIP settings */ 1390 BMS_BLKMEM* blkmem, /**< block memory */ 1391 SCIP_NODE* node, /**< node of the search tree */ 1392 unsigned int id, /**< id of the node */ 1393 SCIP_Bool* transintoorig /**< transform variables into originals */ 1394 ) 1395 { 1396 int nvars; 1397 int nconsprops; 1398 int naddedbndchgs; 1399 1400 assert(reopt != NULL); 1401 assert(blkmem != NULL); 1402 assert(node != NULL); 1403 assert(0 < id && id < reopt->reopttree->reoptnodessize); 1404 assert(reopt->reopttree->reoptnodes[id] != NULL ); 1405 1406 /* get the number of all stored constraint propagations */ 1407 SCIPnodeGetNDomchg(node, NULL, &nconsprops, NULL); 1408 nvars = reopt->reopttree->reoptnodes[id]->nvars; 1409 1410 if( nconsprops > 0 ) 1411 { 1412 /* check the memory */ 1413 SCIP_CALL( reoptnodeCheckMemory(reopt->reopttree->reoptnodes[id], set, blkmem, nvars + nconsprops, 0, 0) ); 1414 1415 SCIPnodeGetConsProps(node, 1416 &reopt->reopttree->reoptnodes[id]->vars[nvars], 1417 &reopt->reopttree->reoptnodes[id]->varbounds[nvars], 1418 &reopt->reopttree->reoptnodes[id]->varboundtypes[nvars], 1419 &naddedbndchgs, 1420 reopt->reopttree->reoptnodes[id]->varssize-nvars); 1421 1422 assert(nvars + naddedbndchgs <= reopt->reopttree->reoptnodes[id]->varssize); 1423 1424 reopt->reopttree->reoptnodes[id]->nvars += naddedbndchgs; 1425 1426 *transintoorig = TRUE; 1427 } 1428 1429 return SCIP_OKAY; 1430 } 1431 1432 /** save bound changes made after the first bound change based on dual information, e.g., mode by strong branching 1433 * 1434 * This method can be used during reoptimization. If we want to reconstruct a node containing dual bound changes we 1435 * have to split the node into the original one and at least one node representing the pruned part. All bound changes, 1436 * i.e., (constraint) propagation, made after the first bound change based on dual information are still valid for 1437 * the original node after changing the objective function. thus, we can store them for the following iterations. 1438 * 1439 * It should be noted, that these bound changes will be found by (constraint) propagation methods anyway after changing 1440 * the objective function. do not saving these information and find them again might be useful for conflict analysis. 1441 */ 1442 static 1443 SCIP_RETCODE saveAfterDualBranchings( 1444 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1445 SCIP_SET* set, /**< global SCIP settings */ 1446 BMS_BLKMEM* blkmem, /**< block memory */ 1447 SCIP_NODE* node, /**< node of the search tree */ 1448 unsigned int id, /**< id of the node */ 1449 SCIP_Bool* transintoorig /**< transform variables into originals */ 1450 ) 1451 { 1452 int nbranchvars; 1453 1454 assert(reopt != NULL); 1455 assert(blkmem != NULL); 1456 assert(node != NULL); 1457 assert(0 < id && id < reopt->reopttree->reoptnodessize); 1458 assert(reopt->reopttree->reoptnodes[id] != NULL ); 1459 1460 nbranchvars = 0; 1461 1462 /* allocate memory */ 1463 if (reopt->reopttree->reoptnodes[id]->afterdualvarssize == 0) 1464 { 1465 assert(reopt->reopttree->reoptnodes[id]->afterdualvars == NULL ); 1466 assert(reopt->reopttree->reoptnodes[id]->afterdualvarbounds == NULL ); 1467 assert(reopt->reopttree->reoptnodes[id]->afterdualvarboundtypes == NULL ); 1468 1469 /* allocate block memory for node information */ 1470 reopt->reopttree->reoptnodes[id]->afterdualvarssize = DEFAULT_MEM_VARAFTERDUAL; 1471 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(reopt->reopttree->reoptnodes[id]->afterdualvars), \ 1472 reopt->reopttree->reoptnodes[id]->afterdualvarssize) ); 1473 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(reopt->reopttree->reoptnodes[id]->afterdualvarbounds), \ 1474 reopt->reopttree->reoptnodes[id]->afterdualvarssize) ); 1475 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(reopt->reopttree->reoptnodes[id]->afterdualvarboundtypes), \ 1476 reopt->reopttree->reoptnodes[id]->afterdualvarssize) ); 1477 } 1478 1479 assert(reopt->reopttree->reoptnodes[id]->afterdualvarssize > 0); 1480 assert(reopt->reopttree->reoptnodes[id]->nafterdualvars >= 0); 1481 1482 SCIPnodeGetBdChgsAfterDual(node, 1483 reopt->reopttree->reoptnodes[id]->afterdualvars, 1484 reopt->reopttree->reoptnodes[id]->afterdualvarbounds, 1485 reopt->reopttree->reoptnodes[id]->afterdualvarboundtypes, 1486 reopt->reopttree->reoptnodes[id]->nafterdualvars, 1487 &nbranchvars, 1488 reopt->reopttree->reoptnodes[id]->afterdualvarssize); 1489 1490 if( nbranchvars > reopt->reopttree->reoptnodes[id]->afterdualvarssize ) 1491 { 1492 int newsize = SCIPsetCalcMemGrowSize(set, nbranchvars+1); 1493 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(reopt->reopttree->reoptnodes[id]->afterdualvars), \ 1494 reopt->reopttree->reoptnodes[id]->afterdualvarssize, newsize) ); 1495 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(reopt->reopttree->reoptnodes[id]->afterdualvarbounds), \ 1496 reopt->reopttree->reoptnodes[id]->afterdualvarssize, newsize) ); 1497 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(reopt->reopttree->reoptnodes[id]->afterdualvarboundtypes), \ 1498 reopt->reopttree->reoptnodes[id]->afterdualvarssize, newsize) ); 1499 reopt->reopttree->reoptnodes[id]->afterdualvarssize = newsize; 1500 1501 SCIPnodeGetBdChgsAfterDual(node, 1502 reopt->reopttree->reoptnodes[id]->afterdualvars, 1503 reopt->reopttree->reoptnodes[id]->afterdualvarbounds, 1504 reopt->reopttree->reoptnodes[id]->afterdualvarboundtypes, 1505 reopt->reopttree->reoptnodes[id]->nafterdualvars, 1506 &nbranchvars, 1507 reopt->reopttree->reoptnodes[id]->afterdualvarssize); 1508 } 1509 1510 /* the stored variables of this node need to be transformed into the original space */ 1511 if( nbranchvars > 0 ) 1512 *transintoorig = TRUE; 1513 1514 SCIPsetDebugMsg(set, " -> save %d bound changes after dual reductions\n", nbranchvars); 1515 1516 assert(nbranchvars <= reopt->reopttree->reoptnodes[id]->afterdualvarssize); /* this should be the case */ 1517 1518 reopt->reopttree->reoptnodes[id]->nafterdualvars = nbranchvars; 1519 1520 return SCIP_OKAY; 1521 } 1522 1523 /** store cuts that are active in the current LP */ 1524 static 1525 SCIP_RETCODE storeCuts( 1526 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1527 SCIP_SET* set, /**< global SCIP settings */ 1528 BMS_BLKMEM* blkmem, /**< block memory */ 1529 SCIP_LP* lp, /**< current LP */ 1530 unsigned int id /**< id in the reopttree */ 1531 ) 1532 { 1533 SCIP_ROW** lprows; 1534 int nlprows; 1535 1536 assert(reopt != NULL); 1537 assert(set != NULL); 1538 assert(lp != NULL); 1539 assert(blkmem != NULL); 1540 1541 lprows = SCIPlpGetRows(lp); 1542 nlprows = SCIPlpGetNRows(lp); 1543 1544 for( int r = 0; r < nlprows; ++r ) 1545 { 1546 /* we can break if we reach the first row that is not part of the current LP */ 1547 if( SCIProwGetLPPos(lprows[r]) == -1 ) 1548 break; 1549 1550 /* currently we only want to store cuts generated by a seperator */ 1551 if( SCIProwGetOrigintype(lprows[r]) == SCIP_ROWORIGINTYPE_SEPA && SCIProwGetAge(lprows[r]) <= set->reopt_maxcutage ) 1552 { 1553 SCIP_VAR** cutvars; 1554 SCIP_COL** cols; 1555 SCIP_Real* cutvals; 1556 SCIP_Real lhs; 1557 SCIP_Real rhs; 1558 int ncutvars; 1559 SCIP_Bool storecut; 1560 1561 ncutvars = SCIProwGetNLPNonz(lprows[r]); 1562 lhs = SCIProwGetLhs(lprows[r]); 1563 rhs = SCIProwGetRhs(lprows[r]); 1564 1565 /* subtract row constant */ 1566 if( !SCIPsetIsInfinity(set, -lhs) ) 1567 lhs -= SCIProwGetConstant(lprows[r]); 1568 if( !SCIPsetIsInfinity(set, rhs) ) 1569 rhs -= SCIProwGetConstant(lprows[r]); 1570 1571 cutvals = SCIProwGetVals(lprows[r]); 1572 cols = SCIProwGetCols(lprows[r]); 1573 storecut = TRUE; 1574 1575 SCIP_CALL( SCIPsetAllocBufferArray(set, &cutvars, ncutvars) ); 1576 1577 for( int c = 0; c < ncutvars; ++c ) 1578 { 1579 SCIP_Real constant; 1580 SCIP_Real scalar; 1581 1582 cutvars[c] = SCIPcolGetVar(cols[c]); 1583 assert(cutvars[c] != NULL); 1584 1585 constant = 0.0; 1586 scalar = 1.0; 1587 1588 SCIP_CALL( SCIPvarGetOrigvarSum(&cutvars[c], &scalar, &constant) ); 1589 1590 /* the cut contains an artificial variable that might not be present after modifying the problem */ 1591 if( cutvars[c] != NULL ) 1592 { 1593 storecut = FALSE; 1594 break; 1595 } 1596 1597 assert(cutvars[c] != NULL); 1598 assert(!SCIPsetIsZero(set, scalar)); 1599 1600 /* subtract constant from sides */ 1601 if( !SCIPsetIsZero(set, constant) && !SCIPsetIsInfinity(set, -lhs) ) 1602 lhs -= constant; 1603 if( !SCIPsetIsZero(set, constant) && !SCIPsetIsInfinity(set, rhs) ) 1604 rhs -= constant; 1605 1606 cutvals[c] = cutvals[c]/scalar; 1607 } 1608 1609 if( storecut ) 1610 { 1611 /* add cut as a linear constraint */ 1612 SCIP_CALL( SCIPreoptnodeAddCons(reopt->reopttree->reoptnodes[id], set, blkmem, cutvars, cutvals, NULL, 1613 lhs, rhs, ncutvars, REOPT_CONSTYPE_CUT, TRUE) ); 1614 } 1615 1616 SCIPsetFreeBufferArray(set, &cutvars); 1617 } 1618 } 1619 1620 return SCIP_OKAY; 1621 } 1622 1623 /** transform variable and bounds back to the original space */ 1624 static 1625 SCIP_RETCODE transformIntoOrig( 1626 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1627 unsigned int id /**< id of the node */ 1628 ) 1629 { 1630 assert(reopt != NULL ); 1631 assert(0 < id && id < reopt->reopttree->reoptnodessize); 1632 assert(reopt->reopttree->reoptnodes[id] != NULL ); 1633 1634 /* transform branching variables and bound changes applied before the first dual reduction */ 1635 for( int varnr = 0; varnr < reopt->reopttree->reoptnodes[id]->nvars; ++varnr ) 1636 { 1637 SCIP_Real constant = 0.0; 1638 SCIP_Real scalar = 1.0; 1639 1640 if( !SCIPvarIsOriginal(reopt->reopttree->reoptnodes[id]->vars[varnr]) ) 1641 { 1642 SCIP_CALL( SCIPvarGetOrigvarSum(&reopt->reopttree->reoptnodes[id]->vars[varnr], &scalar, &constant)) ; 1643 reopt->reopttree->reoptnodes[id]->varbounds[varnr] = (reopt->reopttree->reoptnodes[id]->varbounds[varnr] - constant) / scalar; 1644 } 1645 assert(SCIPvarIsOriginal(reopt->reopttree->reoptnodes[id]->vars[varnr])); 1646 } 1647 1648 /* transform bound changes affected by dual reduction */ 1649 for( int varnr = 0; varnr < reopt->reopttree->reoptnodes[id]->nafterdualvars; ++varnr ) 1650 { 1651 SCIP_Real constant = 0.0; 1652 SCIP_Real scalar = 1.0; 1653 1654 if( !SCIPvarIsOriginal(reopt->reopttree->reoptnodes[id]->afterdualvars[varnr]) ) 1655 { 1656 SCIP_CALL( SCIPvarGetOrigvarSum(&reopt->reopttree->reoptnodes[id]->afterdualvars[varnr], &scalar, &constant)) ; 1657 reopt->reopttree->reoptnodes[id]->afterdualvarbounds[varnr] 1658 = (reopt->reopttree->reoptnodes[id]->afterdualvarbounds[varnr] - constant) / scalar; 1659 } 1660 assert(SCIPvarIsOriginal(reopt->reopttree->reoptnodes[id]->afterdualvars[varnr])); 1661 } 1662 1663 return SCIP_OKAY; 1664 } 1665 1666 /** search the next node along the root path that was saved by reoptimization */ 1667 static 1668 SCIP_RETCODE getLastSavedNode( 1669 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1670 SCIP_SET* set, /**< global SCIP settings */ 1671 SCIP_NODE* node, /**< node of the search tree */ 1672 SCIP_NODE** parent, /**< parent node within the search tree */ 1673 unsigned int* parentid, /**< id of the parent node */ 1674 int* nbndchgs /**< number of bound changes */ 1675 ) 1676 { 1677 assert(reopt != NULL); 1678 assert(reopt->reopttree != NULL); 1679 assert(reopt->reopttree->reoptnodes != NULL); 1680 1681 (*nbndchgs) = 0; 1682 (*parent) = node; 1683 1684 /* look for a saved parent along the root-path */ 1685 while( SCIPnodeGetDepth(*parent) != 0 ) 1686 { 1687 int nbranchings = 0; 1688 int nconsprop = 0; 1689 1690 if( set->reopt_saveconsprop ) 1691 SCIPnodeGetNDomchg((*parent), &nbranchings, &nconsprop, NULL); 1692 else 1693 SCIPnodeGetNDomchg((*parent), &nbranchings, NULL, NULL); 1694 1695 (*nbndchgs) = (*nbndchgs) + nbranchings + nconsprop; 1696 (*parent) = SCIPnodeGetParent(*parent); 1697 (*parentid) = SCIPnodeGetReoptID(*parent); 1698 1699 if( SCIPnodeGetDepth(*parent) == 0) 1700 { 1701 (*parentid) = 0; 1702 break; 1703 } 1704 else if( SCIPnodeGetReopttype((*parent)) >= SCIP_REOPTTYPE_TRANSIT ) 1705 { 1706 /* this is a special case: due to re-propagation the node could be already deleted. We need to reset reoptid 1707 * and reopttype and continue upto we have found the last stored node 1708 */ 1709 if( reopt->reopttree->reoptnodes[*parentid] == NULL ) 1710 { 1711 SCIPnodeSetReoptID(*parent, 0); 1712 SCIPnodeSetReopttype(*parent, SCIP_REOPTTYPE_NONE); 1713 } 1714 else 1715 { 1716 assert(reopt->reopttree->reoptnodes[*parentid] != NULL); 1717 assert(SCIPnodeGetReoptID((*parent)) < reopt->reopttree->reoptnodessize); 1718 assert((*parentid) && (*parentid) < reopt->reopttree->reoptnodessize); 1719 break; 1720 } 1721 } 1722 } 1723 1724 return SCIP_OKAY; 1725 } 1726 1727 /** adds the id @p childid to the array of child nodes of @p parentid */ 1728 static 1729 SCIP_RETCODE reoptAddChild( 1730 SCIP_REOPTTREE* reopttree, /**< reoptimization tree */ 1731 SCIP_SET* set, /**< global SCIP settings */ 1732 BMS_BLKMEM* blkmem, /**< block memory */ 1733 unsigned int parentid, /**< id of the parent node */ 1734 unsigned int childid /**< id of the child node */ 1735 ) 1736 { 1737 int nchilds; 1738 1739 assert(reopttree != NULL); 1740 assert(blkmem != NULL); 1741 assert(parentid < (unsigned int)reopttree->reoptnodessize); 1742 assert(childid < (unsigned int)reopttree->reoptnodessize); 1743 assert(reopttree->reoptnodes[parentid] != NULL); 1744 1745 nchilds = reopttree->reoptnodes[parentid]->nchilds; 1746 1747 /* ensure that the array is large enough */ 1748 SCIP_CALL( reoptnodeCheckMemory(reopttree->reoptnodes[parentid], set, blkmem, 0, nchilds+1, 0) ); 1749 assert(reopttree->reoptnodes[parentid]->allocchildmem > nchilds); 1750 1751 /* add the child */ 1752 reopttree->reoptnodes[parentid]->childids[nchilds] = childid; 1753 ++reopttree->reoptnodes[parentid]->nchilds; 1754 1755 SCIPsetDebugMsg(set, "add ID %u as a child of ID %u.\n", childid, parentid); 1756 1757 return SCIP_OKAY; 1758 } 1759 1760 /** move all children to the next node (along the root path) stored in the reoptimization tree */ 1761 static 1762 SCIP_RETCODE moveChildrenUp( 1763 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1764 SCIP_SET* set, /**< global SCIP settings */ 1765 BMS_BLKMEM* blkmem, /**< block memory */ 1766 unsigned int nodeid, /**< id of the node */ 1767 unsigned int parentid /**< id of the parent node */ 1768 ) 1769 { 1770 unsigned int childid; 1771 int nvars; 1772 1773 assert(reopt != NULL); 1774 assert(blkmem != NULL); 1775 assert(0 < nodeid && nodeid < reopt->reopttree->reoptnodessize); 1776 assert(parentid < reopt->reopttree->reoptnodessize); 1777 assert(reopt->reopttree->reoptnodes[nodeid]->childids != NULL); 1778 1779 /* ensure that enough memory at the parentID is available */ 1780 SCIP_CALL( reoptnodeCheckMemory(reopt->reopttree->reoptnodes[parentid], set, blkmem, 0, 1781 reopt->reopttree->reoptnodes[parentid]->nchilds + reopt->reopttree->reoptnodes[nodeid]->nchilds, 0) ); 1782 1783 while( reopt->reopttree->reoptnodes[nodeid]->nchilds > 0 ) 1784 { 1785 int nchilds; 1786 1787 nchilds = reopt->reopttree->reoptnodes[nodeid]->nchilds; 1788 childid = reopt->reopttree->reoptnodes[nodeid]->childids[nchilds-1]; 1789 assert(0 < childid && childid < reopt->reopttree->reoptnodessize); 1790 1791 /* check the memory */ 1792 SCIP_CALL( reoptnodeCheckMemory(reopt->reopttree->reoptnodes[childid], set, blkmem, 1793 reopt->reopttree->reoptnodes[childid]->nvars + reopt->reopttree->reoptnodes[nodeid]->nvars, 0, 0) ); 1794 assert(reopt->reopttree->reoptnodes[childid]->varssize >= reopt->reopttree->reoptnodes[childid]->nvars 1795 + reopt->reopttree->reoptnodes[nodeid]->nvars); 1796 1797 /* save branching information */ 1798 for( int varnr = 0; varnr < reopt->reopttree->reoptnodes[nodeid]->nvars; ++varnr ) 1799 { 1800 nvars = reopt->reopttree->reoptnodes[childid]->nvars; 1801 reopt->reopttree->reoptnodes[childid]->vars[nvars] = reopt->reopttree->reoptnodes[nodeid]->vars[varnr]; 1802 reopt->reopttree->reoptnodes[childid]->varbounds[nvars] = reopt->reopttree->reoptnodes[nodeid]->varbounds[varnr]; 1803 reopt->reopttree->reoptnodes[childid]->varboundtypes[nvars] = reopt->reopttree->reoptnodes[nodeid]->varboundtypes[varnr]; 1804 ++reopt->reopttree->reoptnodes[childid]->nvars; 1805 } 1806 1807 /* update the ID of the parent node */ 1808 reopt->reopttree->reoptnodes[childid]->parentID = parentid; 1809 1810 /* insert the node as a child */ 1811 SCIP_CALL( reoptAddChild(reopt->reopttree, set, blkmem, parentid, childid) ); 1812 1813 /* reduce the number of child nodes by 1 */ 1814 --reopt->reopttree->reoptnodes[nodeid]->nchilds; 1815 } 1816 1817 return SCIP_OKAY; 1818 } 1819 1820 /** delete all nodes in the subtree induced by nodeID */ 1821 static 1822 SCIP_RETCODE deleteChildrenBelow( 1823 SCIP_REOPTTREE* reopttree, /**< reoptimization tree */ 1824 SCIP_SET* set, /**< global SCIP settings */ 1825 BMS_BLKMEM* blkmem, /**< block memory */ 1826 unsigned int id, /**< id of the node */ 1827 SCIP_Bool delnodeitself, /**< should the node be deleted after deleting the induced subtree? */ 1828 SCIP_Bool exitsolve /**< will the solving process end after deletion */ 1829 ) 1830 { 1831 assert(reopttree != NULL ); 1832 assert(blkmem != NULL); 1833 assert(id < reopttree->reoptnodessize); 1834 assert(reopttree->reoptnodes[id] != NULL); 1835 1836 /* delete all children below */ 1837 if( reopttree->reoptnodes[id]->childids != NULL && reopttree->reoptnodes[id]->nchilds > 0 ) 1838 { 1839 SCIPsetDebugMsg(set, "-> delete subtree induced by ID %u (hard remove = %u)\n", id, exitsolve); 1840 1841 while( reopttree->reoptnodes[id]->nchilds > 0 ) 1842 { 1843 int nchilds; 1844 unsigned int childid; 1845 1846 nchilds = reopttree->reoptnodes[id]->nchilds; 1847 childid = reopttree->reoptnodes[id]->childids[nchilds-1]; 1848 assert(0 < childid && childid < reopttree->reoptnodessize); 1849 1850 SCIP_CALL( deleteChildrenBelow(reopttree, set, blkmem, childid, TRUE, exitsolve) ); 1851 1852 --reopttree->reoptnodes[id]->nchilds; 1853 } 1854 } 1855 1856 /* delete node data*/ 1857 if( delnodeitself ) 1858 { 1859 SCIP_CALL( reopttreeDeleteNode(reopttree, set, blkmem, id, exitsolve) ); 1860 SCIP_CALL( SCIPqueueInsertUInt(reopttree->openids, id) ); 1861 } 1862 1863 return SCIP_OKAY; 1864 } 1865 1866 /** replaces a reoptimization nodes by its stored child nodes */ 1867 static 1868 SCIP_RETCODE shrinkNode( 1869 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1870 SCIP_SET* set, /**< global SCIP settings */ 1871 SCIP_NODE* node, /**< node of the search tree */ 1872 unsigned int id, /**< id of the node */ 1873 SCIP_Bool* shrank, /**< pointer to store if the node was shrank */ 1874 BMS_BLKMEM* blkmem /**< block memory */ 1875 ) 1876 { 1877 SCIP_REOPTNODE** reoptnodes; 1878 1879 assert(reopt != NULL); 1880 assert(node != NULL); 1881 assert(id < reopt->reopttree->reoptnodessize); 1882 1883 reoptnodes = reopt->reopttree->reoptnodes; 1884 assert(reoptnodes != NULL); 1885 assert(reoptnodes[id] != NULL); 1886 1887 if( reoptnodes[id]->childids != NULL && reoptnodes[id]->nchilds > 0 ) 1888 { 1889 int ndomchgs = 0; 1890 unsigned int parentid = 0; 1891 SCIP_NODE* parent = NULL; 1892 1893 SCIP_CALL( getLastSavedNode(reopt, set, node, &parent, &parentid, &ndomchgs) ); 1894 1895 assert(parentid != id); 1896 assert(reoptnodes[parentid] != NULL ); 1897 assert(reoptnodes[parentid]->childids != NULL && reoptnodes[parentid]->nchilds); 1898 1899 /* check if we want move all children to the next saved node above 1900 * we want to shrink the path if either 1901 * - the maximal number of bound changes fix and the number of bound changes is 1902 * less than the given threshold set->reopt_maxdiffofnodes 1903 * or 1904 * - the number is calculated dynamically and the number of bound changes 1905 * is less than log2(SCIPgetNBinVars - (#vars of parent)) 1906 * */ 1907 if( ndomchgs <= set->reopt_maxdiffofnodes ) 1908 { 1909 int c; 1910 1911 SCIPsetDebugMsg(set, " -> shrink node %lld at ID %u, replaced by %d child nodes.\n", SCIPnodeGetNumber(node), 1912 id, reoptnodes[id]->nchilds); 1913 1914 /* copy the references of child nodes to the parent*/ 1915 SCIP_CALL( moveChildrenUp(reopt, set, blkmem, id, parentid) ); 1916 1917 /* delete the current node */ 1918 c = 0; 1919 while( reoptnodes[parentid]->childids[c] != id ) 1920 { 1921 ++c; 1922 assert(c < reoptnodes[parentid]->nchilds); 1923 } 1924 1925 assert(reoptnodes[parentid]->childids[c] == id); 1926 1927 /* replace the childid at position c by the last one */ 1928 reoptnodes[parentid]->childids[c] = reoptnodes[parentid]->childids[reoptnodes[parentid]->nchilds-1]; 1929 --reoptnodes[parentid]->nchilds; 1930 1931 SCIP_CALL( reopttreeDeleteNode(reopt->reopttree, set, blkmem, id, TRUE) ); 1932 SCIP_CALL( SCIPqueueInsertUInt(reopt->reopttree->openids, id) ); 1933 1934 *shrank = TRUE; 1935 1936 /* set the reopttype to none */ 1937 SCIPnodeSetReopttype(node, SCIP_REOPTTYPE_NONE); 1938 } 1939 } 1940 1941 return SCIP_OKAY; 1942 } 1943 1944 /** change all reopttypes in the subtree induced by @p nodeID */ 1945 static 1946 SCIP_RETCODE changeReopttypeOfSubtree( 1947 SCIP_REOPTTREE* reopttree, /**< reopttree */ 1948 unsigned int id, /**< id of the node */ 1949 SCIP_REOPTTYPE reopttype /**< reopttype */ 1950 ) 1951 { 1952 assert(reopttree != NULL); 1953 assert(id < reopttree->reoptnodessize); 1954 assert(reopttree->reoptnodes[id] != NULL); 1955 1956 if( reopttree->reoptnodes[id]->childids != NULL && reopttree->reoptnodes[id]->nchilds > 0 ) 1957 { 1958 unsigned int childid; 1959 int nchildids; 1960 int seenids = 0; 1961 1962 nchildids = reopttree->reoptnodes[id]->nchilds; 1963 1964 while( seenids < nchildids ) 1965 { 1966 /* get childID */ 1967 childid = reopttree->reoptnodes[id]->childids[seenids]; 1968 assert(childid < reopttree->reoptnodessize); 1969 assert(reopttree->reoptnodes[childid] != NULL); 1970 1971 /* change the reopttype of the node iff the node is neither infeasible nor induces an 1972 * infeasible subtree and if the node contains no bound changes based on dual decisions 1973 */ 1974 if( reopttree->reoptnodes[childid]->reopttype != SCIP_REOPTTYPE_STRBRANCHED 1975 && reopttree->reoptnodes[childid]->reopttype != SCIP_REOPTTYPE_INFSUBTREE ) /*lint !e641*/ 1976 reopttree->reoptnodes[childid]->reopttype = reopttype; /*lint !e641*/ 1977 1978 /* change reopttype of subtree */ 1979 SCIP_CALL( changeReopttypeOfSubtree(reopttree, childid, reopttype) ); 1980 1981 ++seenids; 1982 } 1983 } 1984 1985 return SCIP_OKAY; 1986 } 1987 1988 /** delete the constraint handling dual information for the current iteration and replace it with the dual constraint 1989 * for the next iteration 1990 */ 1991 static 1992 SCIP_RETCODE reoptnodeUpdateDualConss( 1993 SCIP_REOPTNODE* reoptnode, /**< reoptimization node */ 1994 BMS_BLKMEM* blkmem /**< block memory */ 1995 ) 1996 { 1997 assert(reoptnode != NULL); 1998 assert(blkmem != NULL); 1999 2000 if( reoptnode->dualredscur != NULL ) 2001 { 2002 SCIPdebugMessage("reset dual information (current run)\n"); 2003 2004 BMSfreeBlockMemoryArray(blkmem, &reoptnode->dualredscur->boundtypes, reoptnode->dualredscur->varssize); 2005 BMSfreeBlockMemoryArray(blkmem, &reoptnode->dualredscur->vals, reoptnode->dualredscur->varssize); 2006 BMSfreeBlockMemoryArray(blkmem, &reoptnode->dualredscur->vars, reoptnode->dualredscur->varssize); 2007 BMSfreeBlockMemory(blkmem, &reoptnode->dualredscur); 2008 reoptnode->dualredscur = NULL; 2009 } 2010 2011 if( reoptnode->dualredsnex != NULL ) 2012 { 2013 SCIPdebugMessage("set dual information of next run to current run\n"); 2014 reoptnode->dualredscur = reoptnode->dualredsnex; 2015 reoptnode->dualredsnex = NULL; 2016 } 2017 2018 reoptnode->dualreds = (reoptnode->dualredscur != NULL ? TRUE : FALSE); 2019 2020 return SCIP_OKAY; 2021 } 2022 2023 /** calculates a (local) similarity of a given node and returns if the subproblem should be solved from scratch */ 2024 static 2025 SCIP_RETCODE reoptCheckLocalRestart( 2026 SCIP_REOPT* reopt, /**< reoptimization data structure */ 2027 SCIP_SET* set, /**< global SCIP settings */ 2028 BMS_BLKMEM* blkmem, /**< block memory */ 2029 SCIP_NODE* node, /**< node of the search tree */ 2030 SCIP_VAR** transvars, /**< transformed variables */ 2031 int ntransvars, /**< number of transformed variables */ 2032 SCIP_Bool* localrestart /**< pointer to store if we want to restart solving the (sub)problem */ 2033 ) 2034 { 2035 unsigned int id; 2036 2037 assert(reopt != NULL); 2038 assert(reopt->reopttree != NULL); 2039 assert(set != NULL); 2040 assert(blkmem != NULL); 2041 assert(node != NULL); 2042 assert(transvars != NULL); 2043 2044 /* node == NULL is equivalent to node == root, this case should be handled by SCIPreoptCheckReopt */ 2045 assert(node != NULL); 2046 2047 *localrestart = FALSE; 2048 2049 id = SCIPnodeGetReoptID(node); 2050 assert(id < reopt->reopttree->reoptnodessize); 2051 2052 /* set the id to -1 if the node is not part of the reoptimization tree */ 2053 if( SCIPnodeGetDepth(node) > 0 && id == 0 ) 2054 return SCIP_OKAY; 2055 2056 if( set->reopt_objsimdelay > -1 ) 2057 { 2058 SCIP_Real sim = 0.0; 2059 SCIP_Real lb; 2060 SCIP_Real ub; 2061 SCIP_Real oldcoef; 2062 SCIP_Real newcoef; 2063 int idx; 2064 2065 if( id == 0 ) 2066 reopt->nlocrestarts = 0; 2067 2068 /* since the stored objective functions are already normalize the dot-product is equivalent to the similarity */ 2069 for( int v = 0; v < ntransvars; ++v ) 2070 { 2071 lb = SCIPvarGetLbLocal(transvars[v]); 2072 ub = SCIPvarGetUbLocal(transvars[v]); 2073 2074 /* skip already fixed variables */ 2075 if( SCIPsetIsFeasLT(set, lb, ub) ) 2076 { 2077 idx = SCIPvarGetProbindex(transvars[v]); 2078 assert(0 <= idx && idx < ntransvars); 2079 2080 oldcoef = SCIPreoptGetOldObjCoef(reopt, reopt->run-1, idx); 2081 newcoef = SCIPreoptGetOldObjCoef(reopt, reopt->run, idx); 2082 2083 sim += (oldcoef * newcoef); 2084 } 2085 } 2086 2087 /* delete the stored subtree and information about bound changes 2088 * based on dual information */ 2089 if( SCIPsetIsLT(set, sim, set->reopt_objsimdelay) ) 2090 { 2091 /* set the flag */ 2092 *localrestart = TRUE; 2093 2094 ++reopt->nlocrestarts; 2095 ++reopt->ntotallocrestarts; 2096 2097 /* delete the stored subtree */ 2098 SCIP_CALL( deleteChildrenBelow(reopt->reopttree, set, blkmem, id, FALSE, FALSE) ); 2099 2100 /* delete the stored constraints; we do this twice in a row because we want to delete both constraints */ 2101 SCIP_CALL( reoptnodeUpdateDualConss(reopt->reopttree->reoptnodes[id], blkmem) ); 2102 SCIP_CALL( reoptnodeUpdateDualConss(reopt->reopttree->reoptnodes[id], blkmem) ); 2103 } 2104 2105 SCIPsetDebugMsg(set, " -> local similarity: %.4f%s\n", sim, *localrestart ? " (solve subproblem from scratch)" : ""); 2106 } 2107 2108 return SCIP_OKAY; 2109 } 2110 2111 /** save ancestor branching information up to the next stored node */ 2112 static 2113 SCIP_RETCODE saveAncestorBranchings( 2114 SCIP_REOPTTREE* reopttree, /**< reoptimization tree */ 2115 SCIP_SET* set, /**< global SCIP settings */ 2116 BMS_BLKMEM* blkmem, /**< block memory */ 2117 SCIP_NODE* node, /**< node of the branch and bound tree */ 2118 SCIP_NODE* parent, /**< parent node */ 2119 unsigned int id, /**< id of the node */ 2120 unsigned int parentid /**< id of the parent node */ 2121 ) 2122 { 2123 int nbranchvars; 2124 2125 assert(reopttree != NULL ); 2126 assert(node != NULL ); 2127 assert(parent != NULL ); 2128 assert(1 <= id && id < reopttree->reoptnodessize); 2129 assert(reopttree->reoptnodes[id] != NULL ); 2130 assert(parentid < reopttree->reoptnodessize); 2131 assert(parentid == 0 || reopttree->reoptnodes[parentid] != NULL ); /* if the root is the next saved node, the nodedata can be NULL */ 2132 2133 SCIPsetDebugMsg(set, " -> save ancestor branchings\n"); 2134 2135 /* allocate memory */ 2136 if (reopttree->reoptnodes[id]->varssize == 0) 2137 { 2138 assert(reopttree->reoptnodes[id]->vars == NULL ); 2139 assert(reopttree->reoptnodes[id]->varbounds == NULL ); 2140 assert(reopttree->reoptnodes[id]->varboundtypes == NULL ); 2141 2142 /* allocate memory for node information */ 2143 SCIP_CALL( reoptnodeCheckMemory(reopttree->reoptnodes[id], set, blkmem, DEFAULT_MEM_VAR, 0, 0) ); 2144 } 2145 2146 assert(reopttree->reoptnodes[id]->varssize > 0); 2147 assert(reopttree->reoptnodes[id]->nvars == 0); 2148 2149 SCIPnodeGetAncestorBranchingsPart(node, parent, 2150 reopttree->reoptnodes[id]->vars, 2151 reopttree->reoptnodes[id]->varbounds, 2152 reopttree->reoptnodes[id]->varboundtypes, 2153 &nbranchvars, 2154 reopttree->reoptnodes[id]->varssize); 2155 2156 if( nbranchvars > reopttree->reoptnodes[id]->varssize ) 2157 { 2158 /* reallocate memory */ 2159 SCIP_CALL( reoptnodeCheckMemory(reopttree->reoptnodes[id], set, blkmem, nbranchvars, 0, 0) ); 2160 2161 SCIPnodeGetAncestorBranchingsPart(node, parent, 2162 reopttree->reoptnodes[id]->vars, 2163 reopttree->reoptnodes[id]->varbounds, 2164 reopttree->reoptnodes[id]->varboundtypes, 2165 &nbranchvars, 2166 reopttree->reoptnodes[id]->varssize); 2167 } 2168 2169 assert(nbranchvars <= reopttree->reoptnodes[id]->varssize); /* this should be the case */ 2170 2171 reopttree->reoptnodes[id]->nvars = nbranchvars; 2172 2173 assert(nbranchvars <= reopttree->reoptnodes[id]->varssize); 2174 assert(reopttree->reoptnodes[id]->vars != NULL ); 2175 2176 return SCIP_OKAY; 2177 } 2178 2179 2180 /** transform a constraint with linear representation into reoptimization constraint data */ 2181 static 2182 SCIP_RETCODE saveConsLinear( 2183 SCIP_REOPTCONSDATA* reoptconsdata, /**< reoptimization constraint data */ 2184 SCIP_SET* set, /**< global SCIP settings */ 2185 BMS_BLKMEM* blkmem, /**< block memory */ 2186 SCIP_CONS* cons, /**< linear constraint that should be stored */ 2187 SCIP_Bool* success /**< pointer to store the success */ 2188 ) 2189 { 2190 SCIP_VAR** vars; 2191 SCIP_Real* vals; 2192 SCIP_CONSHDLR* conshdlr; 2193 SCIP_Bool allocbuffervals; 2194 2195 assert(reoptconsdata != NULL); 2196 assert(cons != NULL); 2197 2198 *success = FALSE; 2199 allocbuffervals = FALSE; 2200 reoptconsdata->linear = TRUE; 2201 2202 vars = NULL; 2203 vals = NULL; 2204 SCIP_CALL( SCIPconsGetNVars(cons, set, &reoptconsdata->nvars, success) ); 2205 assert(*success); 2206 2207 /* allocate memory for variables and values; boundtypes are not needed */ 2208 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reoptconsdata->vars, reoptconsdata->nvars) ); 2209 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reoptconsdata->vals, reoptconsdata->nvars) ); 2210 reoptconsdata->varssize = reoptconsdata->nvars; 2211 2212 /* only needed for bounddisjuction constraints, thus we set them to NULL to avoid compiler warnings */ 2213 reoptconsdata->boundtypes = NULL; 2214 2215 conshdlr = SCIPconsGetHdlr(cons); 2216 assert(conshdlr != NULL); 2217 2218 /* get all variables, values, and sides */ 2219 if( strcmp(SCIPconshdlrGetName(conshdlr), "linear") == 0 ) 2220 { 2221 vars = SCIPgetVarsLinear(set->scip, cons); 2222 vals = SCIPgetValsLinear(set->scip, cons); 2223 reoptconsdata->lhs = SCIPgetLhsLinear(set->scip, cons); 2224 reoptconsdata->rhs = SCIPgetRhsLinear(set->scip, cons); 2225 } 2226 else if( strcmp(SCIPconshdlrGetName(conshdlr), "logicor") == 0 ) 2227 { 2228 vars = SCIPgetVarsLogicor(set->scip, cons); 2229 2230 /* initialize values to 1.0 */ 2231 SCIP_CALL( SCIPsetAllocBufferArray(set, &vals, reoptconsdata->nvars) ); 2232 allocbuffervals = TRUE; 2233 2234 for( int v = 0; v < reoptconsdata->nvars; ++v ) 2235 vals[v] = 1.0; 2236 2237 reoptconsdata->lhs = 1.0; 2238 reoptconsdata->rhs = SCIPsetInfinity(set); 2239 } 2240 else if( strcmp(SCIPconshdlrGetName(conshdlr), "setppc") == 0 ) 2241 { 2242 vars = SCIPgetVarsSetppc(set->scip, cons); 2243 2244 /* initialize values to 1.0 */ 2245 SCIP_CALL( SCIPsetAllocBufferArray(set, &vals, reoptconsdata->nvars) ); 2246 allocbuffervals = TRUE; 2247 2248 for( int v = 0; v < reoptconsdata->nvars; ++v ) 2249 vals[v] = 1.0; 2250 2251 switch( SCIPgetTypeSetppc(set->scip, cons) ) { 2252 case SCIP_SETPPCTYPE_PARTITIONING: 2253 reoptconsdata->lhs = 1.0; 2254 reoptconsdata->rhs = 1.0; 2255 break; 2256 case SCIP_SETPPCTYPE_PACKING: 2257 reoptconsdata->lhs = -SCIPsetInfinity(set); 2258 reoptconsdata->rhs = 1.0; 2259 break; 2260 case SCIP_SETPPCTYPE_COVERING: 2261 reoptconsdata->lhs = 1.0; 2262 reoptconsdata->rhs = SCIPsetInfinity(set); 2263 break; 2264 default: 2265 *success = FALSE; 2266 return SCIP_OKAY; 2267 } 2268 } 2269 else 2270 { 2271 assert(strcmp(SCIPconshdlrGetName(conshdlr), "linear") == 0 || strcmp(SCIPconshdlrGetName(conshdlr), "logicor") == 0 2272 || strcmp(SCIPconshdlrGetName(conshdlr), "setppc") == 0); 2273 2274 SCIPerrorMessage("Cannot handle constraints of type <%s> in saveConsLinear.\n", SCIPconshdlrGetName(conshdlr)); 2275 return SCIP_INVALIDDATA; 2276 } 2277 assert(vars != NULL); 2278 assert(vals != NULL); 2279 2280 /* transform all variables into the original space */ 2281 for( int v = 0; v < reoptconsdata->nvars; ++v ) 2282 { 2283 SCIP_Real constant = 0.0; 2284 SCIP_Real scalar = 1.0; 2285 2286 assert(vars[v] != NULL); 2287 2288 reoptconsdata->vars[v] = vars[v]; 2289 reoptconsdata->vals[v] = vals[v]; 2290 2291 SCIP_CALL( SCIPvarGetOrigvarSum(&reoptconsdata->vars[v], &scalar, &constant) ); 2292 assert(!SCIPsetIsZero(set, scalar)); 2293 2294 assert(!SCIPsetIsInfinity(set, REALABS(reoptconsdata->vals[v]))); 2295 reoptconsdata->vals[v] *= scalar; 2296 2297 if( !SCIPsetIsZero(set, constant) && !SCIPsetIsInfinity(set, -reoptconsdata->lhs) ) 2298 reoptconsdata->lhs -= constant; 2299 if( !SCIPsetIsZero(set, constant) && !SCIPsetIsInfinity(set, reoptconsdata->rhs) ) 2300 reoptconsdata->rhs -= constant; 2301 } 2302 2303 /* free buffer if needed */ 2304 if( allocbuffervals ) 2305 { 2306 SCIPsetFreeBufferArray(set, &vals); 2307 } 2308 2309 return SCIP_OKAY; 2310 } 2311 2312 /** transform a bounddisjunction constraint into reoptimization constraint data */ 2313 static 2314 SCIP_RETCODE saveConsBounddisjuction( 2315 SCIP_REOPTCONSDATA* reoptconsdata, /**< reoptimization constraint data */ 2316 SCIP_SET* set, /**< global SCIP settings */ 2317 BMS_BLKMEM* blkmem, /**< block memory */ 2318 SCIP_CONS* cons, /**< bounddisjuction constraint that should be stored */ 2319 SCIP_Bool* success /**< pointer to store the success */ 2320 ) 2321 { 2322 SCIP_VAR** vars; 2323 SCIP_CONSHDLR* conshdlr; 2324 SCIP_BOUNDTYPE* boundtypes; 2325 SCIP_Real* bounds; 2326 2327 assert(reoptconsdata != NULL); 2328 assert(cons != NULL); 2329 2330 *success = FALSE; 2331 reoptconsdata->linear = FALSE; 2332 2333 conshdlr = SCIPconsGetHdlr(cons); 2334 assert(conshdlr != NULL); 2335 assert(strcmp(SCIPconshdlrGetName(conshdlr), "bounddisjunction") == 0); 2336 2337 if( strcmp(SCIPconshdlrGetName(conshdlr), "bounddisjunction") != 0 ) 2338 { 2339 SCIPerrorMessage("Cannot handle constraints of type <%s> in saveConsBounddisjuction.\n", 2340 SCIPconshdlrGetName(conshdlr)); 2341 return SCIP_INVALIDDATA; 2342 } 2343 2344 SCIP_CALL( SCIPconsGetNVars(cons, set, &reoptconsdata->nvars, success) ); 2345 assert(*success); 2346 2347 /* allocate memory for variables and values; boundtypes are not needed */ 2348 vars = SCIPgetVarsBounddisjunction(NULL, cons); 2349 bounds = SCIPgetBoundsBounddisjunction(NULL, cons); 2350 boundtypes = SCIPgetBoundtypesBounddisjunction(NULL, cons); 2351 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reoptconsdata->vars, vars, reoptconsdata->nvars) ); 2352 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reoptconsdata->vals, bounds, reoptconsdata->nvars) ); 2353 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reoptconsdata->boundtypes, boundtypes, reoptconsdata->nvars) ); 2354 reoptconsdata->varssize = reoptconsdata->nvars; 2355 reoptconsdata->lhs = SCIP_UNKNOWN; 2356 reoptconsdata->rhs = SCIP_UNKNOWN; 2357 2358 /* transform all variables into the original space */ 2359 for( int v = 0; v < reoptconsdata->nvars; ++v ) 2360 { 2361 SCIP_Real constant = 0.0; 2362 SCIP_Real scalar = 1.0; 2363 2364 assert(reoptconsdata->vars[v] != NULL); 2365 2366 SCIP_CALL( SCIPvarGetOrigvarSum(&reoptconsdata->vars[v], &scalar, &constant) ); 2367 assert(!SCIPsetIsZero(set, scalar)); 2368 2369 assert(!SCIPsetIsInfinity(set, REALABS(reoptconsdata->vals[v]))); 2370 reoptconsdata->vals[v] -= constant; 2371 reoptconsdata->vals[v] *= scalar; 2372 2373 /* due to multipling with a negative scalar the relation need to be changed */ 2374 if( SCIPsetIsNegative(set, scalar) ) 2375 reoptconsdata->boundtypes[v] = (SCIP_BOUNDTYPE)(SCIP_BOUNDTYPE_UPPER - reoptconsdata->boundtypes[v]); /*lint !e656*/ 2376 } 2377 2378 return SCIP_OKAY; 2379 } 2380 2381 /** save additional all constraints that were additionally added to @p node */ 2382 static 2383 SCIP_RETCODE saveLocalConssData( 2384 SCIP_REOPTTREE* reopttree, /**< reopttree */ 2385 SCIP_SET* set, /**< global SCIP settings */ 2386 BMS_BLKMEM* blkmem, /**< block memory */ 2387 SCIP_NODE* node, /**< node of the branch and bound tree */ 2388 unsigned int id /**< id of the node*/ 2389 ) 2390 { 2391 SCIP_CONS** addedcons; 2392 int naddedconss; 2393 int addedconsssize; 2394 int nconss; 2395 2396 assert(node != NULL ); 2397 assert(reopttree != NULL); 2398 assert(id < reopttree->reoptnodessize); 2399 2400 /* save the added pseudo-constraint */ 2401 if( SCIPnodeGetNAddedConss(node) > 0 ) 2402 { 2403 addedconsssize = SCIPnodeGetNAddedConss(node); 2404 2405 SCIPsetDebugMsg(set, " -> save %d locally added constraints\n", addedconsssize); 2406 2407 /* get memory */ 2408 SCIP_CALL( SCIPsetAllocBufferArray(set, &addedcons, addedconsssize) ); 2409 SCIPnodeGetAddedConss(node, addedcons, &naddedconss, addedconsssize); 2410 2411 nconss = reopttree->reoptnodes[id]->nconss; 2412 2413 /* check memory for added constraints */ 2414 SCIP_CALL( reoptnodeCheckMemory(reopttree->reoptnodes[id], set, blkmem, 0, 0, naddedconss) ); 2415 2416 /* since the first nconss are already stored in the data structure, we skip them */ 2417 for( int c = nconss; c < naddedconss; ++c ) 2418 { 2419 SCIP_CONSHDLR* conshdlr; 2420 SCIP_Bool islinear; 2421 SCIP_Bool success; 2422 2423 conshdlr = SCIPconsGetHdlr(addedcons[c]); 2424 2425 /* check whether the constraint has a linear representation */ 2426 islinear = (strcmp(SCIPconshdlrGetName(conshdlr), "linear") == 0 2427 || strcmp(SCIPconshdlrGetName(conshdlr), "logicor") == 0 2428 || strcmp(SCIPconshdlrGetName(conshdlr), "setppc") == 0); 2429 2430 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &reopttree->reoptnodes[id]->conss[c]) ); /*lint !e866*/ 2431 2432 success = FALSE; 2433 2434 /* the constraint has a linear representation */ 2435 if( islinear ) 2436 { 2437 SCIP_CALL( saveConsLinear(reopttree->reoptnodes[id]->conss[c], set, blkmem, addedcons[c], &success) ); 2438 assert(success); 2439 2440 /* increase the counter for added constraints */ 2441 ++reopttree->reoptnodes[id]->nconss; 2442 } 2443 else 2444 { 2445 assert(strcmp(SCIPconshdlrGetName(conshdlr), "bounddisjunction") == 0); 2446 SCIP_CALL( saveConsBounddisjuction(reopttree->reoptnodes[id]->conss[c], set, blkmem, addedcons[c], &success) ); 2447 assert(success); 2448 2449 /* increase the counter for added constraints */ 2450 ++reopttree->reoptnodes[id]->nconss; 2451 } 2452 assert(reopttree->reoptnodes[id]->conss[c]->nvars > 0); 2453 2454 if( strcmp("reopt_inf", SCIPconsGetName(addedcons[c])) == 0 ) 2455 reopttree->reoptnodes[id]->conss[c]->constype = REOPT_CONSTYPE_INFSUBTREE; 2456 else if( strcmp("reopt_dual", SCIPconsGetName(addedcons[c])) == 0 ) 2457 reopttree->reoptnodes[id]->conss[c]->constype = REOPT_CONSTYPE_DUALREDS; 2458 else 2459 reopttree->reoptnodes[id]->conss[c]->constype = REOPT_CONSTYPE_UNKNOWN; 2460 } 2461 2462 assert(reopttree->reoptnodes[id]->nconss == naddedconss); 2463 SCIPsetFreeBufferArray(set, &addedcons); 2464 } 2465 2466 return SCIP_OKAY; 2467 } 2468 2469 /** collect all bound changes based on dual information 2470 * 2471 * If the bound changes are global, all information are already stored because they were caught by the event handler. 2472 * otherwise, we have to use SCIPnodeGetDualBoundchgs. 2473 * 2474 * Afterwards, we check if the constraint will be added in the next iteration or after splitting the node. 2475 */ 2476 static 2477 SCIP_RETCODE collectDualInformation( 2478 SCIP_REOPT* reopt, /**< reoptimization data structure */ 2479 SCIP_SET* set, /**< global SCIP settings */ 2480 BMS_BLKMEM* blkmem, /**< block memory */ 2481 SCIP_NODE* node, /**< node of the search tree */ 2482 unsigned int id, /**< id of the node */ 2483 SCIP_REOPTTYPE reopttype /**< reopttype */ 2484 ) 2485 { 2486 SCIP_Bool cons_is_next = TRUE; 2487 int nbndchgs; 2488 2489 assert(reopt != NULL); 2490 assert(reopt->reopttree != NULL); 2491 assert(id < reopt->reopttree->reoptnodessize); 2492 assert(reopt->reopttree->reoptnodes[id]->dualreds); 2493 assert(node != NULL); 2494 assert(blkmem != NULL); 2495 2496 /* first case, all bound changes were global */ 2497 if( reopt->currentnode == SCIPnodeGetNumber(node) && reopt->dualreds != NULL && reopt->dualreds->nvars > 0 ) 2498 { 2499 nbndchgs = reopt->dualreds->nvars; 2500 } 2501 else 2502 { 2503 assert(reopt->currentnode == SCIPnodeGetNumber(node)); 2504 2505 /* get the number of bound changes based on dual information */ 2506 nbndchgs = SCIPnodeGetNDualBndchgs(node); 2507 2508 /* ensure that enough memory is allocated */ 2509 SCIP_CALL( checkMemDualCons(reopt, set, blkmem, nbndchgs) ); 2510 2511 /* collect the bound changes */ 2512 SCIPnodeGetDualBoundchgs(node, reopt->dualreds->vars, reopt->dualreds->vals, reopt->dualreds->boundtypes, 2513 &nbndchgs, reopt->dualreds->varssize); 2514 assert(nbndchgs <= reopt->dualreds->varssize); 2515 2516 reopt->dualreds->nvars = nbndchgs; 2517 reopt->dualreds->linear = FALSE; 2518 2519 /* transform the variables into the original space */ 2520 for( int v = 0; v < nbndchgs; ++v ) 2521 { 2522 SCIP_Real constant = 0.0; 2523 SCIP_Real scalar = 1.0; 2524 2525 SCIP_CALL( SCIPvarGetOrigvarSum(&reopt->dualreds->vars[v], &scalar, &constant) ); 2526 reopt->dualreds->vals[v] = (reopt->dualreds->vals[v] - constant) / scalar; 2527 2528 assert(SCIPvarIsOriginal(reopt->dualreds->vars[v])); 2529 } 2530 } 2531 2532 assert(nbndchgs > 0); 2533 2534 /* due to the strong branching initialization it can be possible that two 2535 * constraints handling dual information are stored at the same time. 2536 * During reoptimizing a node we add the constraint stored at dualredscur only, 2537 * i.e, if dualredscur is not NULL, we need to store the constraint for the next 2538 * iteration at dualredsnex because the constraint stored at dualredscur is needed 2539 * to split the constraint in the current iteration. 2540 */ 2541 if( reopt->reopttree->reoptnodes[id]->dualredscur != NULL ) 2542 { 2543 assert(reopt->reopttree->reoptnodes[id]->dualredsnex == NULL); 2544 cons_is_next = FALSE; 2545 } 2546 assert((cons_is_next && reopt->reopttree->reoptnodes[id]->dualredscur == NULL) 2547 || (!cons_is_next && reopt->reopttree->reoptnodes[id]->dualredsnex == NULL)); 2548 2549 /* the constraint will be added next */ 2550 if( cons_is_next ) 2551 { 2552 assert(reopt->reopttree->reoptnodes[id]->dualredscur == NULL); 2553 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &reopt->reopttree->reoptnodes[id]->dualredscur) ); 2554 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reopt->reopttree->reoptnodes[id]->dualredscur->vars, \ 2555 reopt->dualreds->vars, nbndchgs) ); 2556 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reopt->reopttree->reoptnodes[id]->dualredscur->vals, \ 2557 reopt->dualreds->vals, nbndchgs) ); 2558 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reopt->reopttree->reoptnodes[id]->dualredscur->boundtypes, \ 2559 reopt->dualreds->boundtypes, nbndchgs) ); 2560 2561 reopt->reopttree->reoptnodes[id]->dualredscur->nvars = nbndchgs; 2562 reopt->reopttree->reoptnodes[id]->dualredscur->varssize = nbndchgs; 2563 reopt->reopttree->reoptnodes[id]->dualredscur->lhs = 1.0; 2564 reopt->reopttree->reoptnodes[id]->dualredscur->rhs = SCIPsetInfinity(set); 2565 reopt->reopttree->reoptnodes[id]->dualredscur->constype = (reopttype == SCIP_REOPTTYPE_STRBRANCHED ? 2566 REOPT_CONSTYPE_DUALREDS : REOPT_CONSTYPE_INFSUBTREE); 2567 reopt->reopttree->reoptnodes[id]->dualredscur->linear = FALSE; 2568 2569 SCIPsetDebugMsg(set, " -> save dual information of type 1: node %lld, nvars %d, constype %d\n", 2570 SCIPnodeGetNumber(node), reopt->reopttree->reoptnodes[id]->dualredscur->nvars, 2571 reopt->reopttree->reoptnodes[id]->dualredscur->constype); 2572 } 2573 /* the constraint will be added after next */ 2574 else 2575 { 2576 assert(reopt->reopttree->reoptnodes[id]->dualredsnex == NULL); 2577 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &reopt->reopttree->reoptnodes[id]->dualredsnex) ); 2578 reopt->reopttree->reoptnodes[id]->dualredsnex->nvars = -1; 2579 2580 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reopt->reopttree->reoptnodes[id]->dualredsnex->vars, \ 2581 reopt->dualreds->vars, nbndchgs) ); 2582 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reopt->reopttree->reoptnodes[id]->dualredsnex->vals, \ 2583 reopt->dualreds->vals, nbndchgs) ); 2584 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reopt->reopttree->reoptnodes[id]->dualredsnex->boundtypes, \ 2585 reopt->dualreds->boundtypes, nbndchgs) ); 2586 reopt->reopttree->reoptnodes[id]->dualredsnex->nvars = nbndchgs; 2587 reopt->reopttree->reoptnodes[id]->dualredsnex->varssize = nbndchgs; 2588 reopt->reopttree->reoptnodes[id]->dualredsnex->lhs = 1.0; 2589 reopt->reopttree->reoptnodes[id]->dualredsnex->rhs = SCIPsetInfinity(set); 2590 reopt->reopttree->reoptnodes[id]->dualredsnex->constype = (reopttype == SCIP_REOPTTYPE_STRBRANCHED ? 2591 REOPT_CONSTYPE_DUALREDS : REOPT_CONSTYPE_INFSUBTREE); 2592 2593 SCIPsetDebugMsg(set, " -> save dual information of type 2: node %lld, nvars %d, constype %d\n", 2594 SCIPnodeGetNumber(node), reopt->reopttree->reoptnodes[id]->dualredsnex->nvars, 2595 reopt->reopttree->reoptnodes[id]->dualredsnex->constype); 2596 } 2597 2598 return SCIP_OKAY; 2599 } 2600 2601 /** adds a node of the branch and bound tree to the reoptimization tree */ 2602 static 2603 SCIP_RETCODE addNode( 2604 SCIP_REOPT* reopt, /**< reoptimization data structure */ 2605 SCIP_SET* set, /**< global SCIP settings */ 2606 SCIP_LP* lp, /**< current LP */ 2607 BMS_BLKMEM* blkmem, /**< block memory */ 2608 SCIP_NODE* node, /**< current node */ 2609 SCIP_REOPTTYPE reopttype, /**< reason for storing the node*/ 2610 SCIP_Bool saveafterdual, /**< save branching decisions after the first dual */ 2611 SCIP_Bool isrootnode, /**< node is the root node */ 2612 SCIP_Real lowerbound /**< lower bound of the node */ 2613 ) 2614 { 2615 SCIP_NODE* parent = NULL; 2616 SCIP_Bool shrank = FALSE; 2617 unsigned int id; 2618 unsigned int parentid = 0; 2619 2620 assert(reopt != NULL); 2621 assert(set != NULL); 2622 assert(blkmem != NULL); 2623 assert(node != NULL); 2624 2625 if( set->reopt_maxsavednodes == 0 ) 2626 return SCIP_OKAY; 2627 2628 assert(reopttype == SCIP_REOPTTYPE_TRANSIT 2629 || reopttype == SCIP_REOPTTYPE_INFSUBTREE 2630 || reopttype == SCIP_REOPTTYPE_STRBRANCHED 2631 || reopttype == SCIP_REOPTTYPE_LOGICORNODE 2632 || reopttype == SCIP_REOPTTYPE_LEAF 2633 || reopttype == SCIP_REOPTTYPE_PRUNED 2634 || reopttype == SCIP_REOPTTYPE_FEASIBLE); 2635 2636 /* start clock */ 2637 SCIPclockStart(reopt->savingtime, set); 2638 2639 /* the node was created by reoptimization, i.e., we need to update the 2640 * stored data */ 2641 if( SCIPnodeGetReoptID(node) >= 1 ) 2642 { 2643 SCIP_Bool transintoorig; 2644 2645 assert(reopttype != SCIP_REOPTTYPE_LEAF); 2646 assert(!isrootnode); 2647 2648 id = SCIPnodeGetReoptID(node); 2649 assert(id < reopt->reopttree->reoptnodessize); 2650 2651 /* this is a special case: 2652 * due to re-propagation of the an anchester node it can happen that we try to update a node that was created by 2653 * reoptimization and already removed by deleteChildrenBelow. In this case we do not want to save the current 2654 * node 2655 */ 2656 if( reopt->reopttree->reoptnodes[id] == NULL ) 2657 { 2658 parent = SCIPnodeGetParent(node); 2659 assert(parent != NULL); 2660 2661 parentid = SCIPnodeGetReoptID(parent); 2662 2663 /* traverse along the branching path until reaching a node that is part of the reoptimization tree or the root node */ 2664 while( SCIPnodeGetDepth(parent) > 0 && reopt->reopttree->reoptnodes[parentid] == NULL ) 2665 { 2666 /* the parent node is not part of the reoptimization, reset the reoptid and reopttype of the parent node */ 2667 SCIPnodeSetReoptID(parent, 0); 2668 SCIPnodeSetReopttype(parent, SCIP_REOPTTYPE_NONE); 2669 2670 parent = SCIPnodeGetParent(parent); 2671 assert(parent != NULL); 2672 2673 parentid = SCIPnodeGetReoptID(parent); 2674 } 2675 2676 /* the anchestor node has to be part of the reoptimization tree. either the parent is the root itself or 2677 * marked to be a leaf, pruned or feasible 2678 */ 2679 assert(reopt->reopttree->reoptnodes[parentid] != NULL); 2680 assert(parentid == 0 2681 || reopt->reopttree->reoptnodes[parentid]->reopttype == SCIP_REOPTTYPE_FEASIBLE 2682 || reopt->reopttree->reoptnodes[parentid]->reopttype == SCIP_REOPTTYPE_INFSUBTREE 2683 || reopt->reopttree->reoptnodes[parentid]->reopttype == SCIP_REOPTTYPE_LEAF 2684 || reopt->reopttree->reoptnodes[parentid]->reopttype == SCIP_REOPTTYPE_PRUNED); /*lint !e641*/ 2685 2686 SCIPsetDebugMsg(set, " -> skip saving\n"); 2687 SCIPnodeSetReoptID(node, 0); 2688 SCIPnodeSetReopttype(node, SCIP_REOPTTYPE_NONE); 2689 2690 /* stop clock */ 2691 SCIPclockStop(reopt->savingtime, set); 2692 2693 return SCIP_OKAY; 2694 } 2695 2696 SCIPsetDebugMsg(set, "update node %lld at ID %u:\n", SCIPnodeGetNumber(node), id); 2697 2698 transintoorig = FALSE; 2699 2700 /* store separated cuts */ 2701 if( set->reopt_usecuts ) 2702 { 2703 SCIP_CALL( storeCuts(reopt, set, blkmem, lp, id) ); 2704 } 2705 2706 /* save primal bound changes made after the first dual bound change */ 2707 if( saveafterdual ) 2708 { 2709 assert(reopttype == SCIP_REOPTTYPE_STRBRANCHED); 2710 SCIP_CALL( saveAfterDualBranchings(reopt, set, blkmem, node, id, &transintoorig) ); 2711 } 2712 2713 /* update constraint propagations */ 2714 if( set->reopt_saveconsprop ) 2715 { 2716 SCIP_CALL( updateConstraintPropagation(reopt, set, blkmem, node, id, &transintoorig) ); 2717 } 2718 2719 /* ensure that all variables describing the branching path are original */ 2720 if( transintoorig ) 2721 { 2722 SCIP_CALL( transformIntoOrig(reopt, id) ); 2723 } 2724 2725 /* update the lowerbound if the new lower bound is finite */ 2726 if( !SCIPsetIsInfinity(set, REALABS(lowerbound)) ) 2727 reopt->reopttree->reoptnodes[id]->lowerbound = lowerbound; 2728 SCIPsetDebugMsg(set, " -> reopttype: %d, lowerbound: %g\n", reopttype, reopt->reopttree->reoptnodes[id]->lowerbound); 2729 2730 #ifdef SCIP_MORE_DEBUG 2731 { 2732 SCIPsetDebugMsg(set, " -> saved variables:\n"); 2733 for( int varnr = 0; varnr < reopt->reopttree->reoptnodes[id]->nvars; ++varnr ) 2734 { 2735 SCIPsetDebugMsg(set, " <%s> %s %g\n", SCIPvarGetName(reopt->reopttree->reoptnodes[id]->vars[varnr]), 2736 reopt->reopttree->reoptnodes[id]->varboundtypes[varnr] == SCIP_BOUNDTYPE_LOWER ? 2737 "=>" : "<=", reopt->reopttree->reoptnodes[id]->varbounds[varnr]); 2738 } 2739 for( int varnr = 0; varnr < reopt->reopttree->reoptnodes[id]->nafterdualvars; ++varnr ) 2740 { 2741 SCIPsetDebugMsg(set, " -> saved variables:\n"); 2742 for( int varnr = 0; varnr < reopt->reopttree->reoptnodes[id]->nvars; ++varnr ) 2743 { 2744 SCIPsetDebugMsg(set, " <%s> %s %g\n", SCIPvarGetName(reopt->reopttree->reoptnodes[id]->vars[varnr]), 2745 reopt->reopttree->reoptnodes[id]->varboundtypes[varnr] == SCIP_BOUNDTYPE_LOWER ? 2746 "=>" : "<=", reopt->reopttree->reoptnodes[id]->varbounds[varnr]); 2747 } 2748 for( int varnr = 0; varnr < reopt->reopttree->reoptnodes[id]->nafterdualvars; ++varnr ) 2749 { 2750 SCIPsetDebugMsg(set, " <%s> %s %g (after dual red.)\n", SCIPvarGetName(reopt->reopttree->reoptnodes[id]->afterdualvars[varnr]), 2751 reopt->reopttree->reoptnodes[id]->afterdualvarboundtypes[varnr] == SCIP_BOUNDTYPE_LOWER ? 2752 "=>" : "<=", reopt->reopttree->reoptnodes[id]->afterdualvarbounds[varnr]); 2753 } 2754 } 2755 } 2756 #endif 2757 2758 /* update LPI state */ 2759 switch( reopttype ) 2760 { 2761 case SCIP_REOPTTYPE_TRANSIT: 2762 if( set->reopt_shrinkinner ) 2763 { 2764 SCIP_CALL( shrinkNode(reopt, set, node, id, &shrank, blkmem) ); 2765 } 2766 goto TRANSIT; 2767 2768 case SCIP_REOPTTYPE_LOGICORNODE: 2769 case SCIP_REOPTTYPE_LEAF: 2770 goto TRANSIT; 2771 2772 case SCIP_REOPTTYPE_INFSUBTREE: 2773 /* delete the whole subtree induced be the current node */ 2774 SCIP_CALL( deleteChildrenBelow(reopt->reopttree, set, blkmem, id, FALSE, FALSE) ); 2775 goto PSEUDO; 2776 2777 case SCIP_REOPTTYPE_STRBRANCHED: 2778 goto PSEUDO; 2779 2780 case SCIP_REOPTTYPE_FEASIBLE: 2781 /* delete the subtree */ 2782 if( set->reopt_reducetofrontier ) 2783 { 2784 SCIP_CALL( deleteChildrenBelow(reopt->reopttree, set, blkmem, id, FALSE, FALSE) ); 2785 SCIP_CALL( SCIPreoptResetDualBndchgs(reopt, node, blkmem) ); 2786 } 2787 /* dive through all children and change the reopttype to PRUNED */ 2788 else 2789 { 2790 SCIP_CALL( changeReopttypeOfSubtree(reopt->reopttree, id, SCIP_REOPTTYPE_PRUNED) ); 2791 } 2792 goto FEASIBLE; 2793 2794 case SCIP_REOPTTYPE_PRUNED: 2795 /* delete the subtree */ 2796 if( set->reopt_reducetofrontier ) 2797 { 2798 SCIP_CALL( deleteChildrenBelow(reopt->reopttree, set, blkmem, id, FALSE, FALSE) ); 2799 SCIP_CALL( SCIPreoptResetDualBndchgs(reopt, node, blkmem) ); 2800 } 2801 /* dive through all children and change the reopttype to LEAF */ 2802 else 2803 { 2804 SCIP_CALL( changeReopttypeOfSubtree(reopt->reopttree, id, SCIP_REOPTTYPE_PRUNED) ); 2805 } 2806 2807 /* increase number of reoptimized nodes that could be pruned */ 2808 ++reopt->reopttree->ncutoffreoptnodes; 2809 ++reopt->reopttree->ntotalcutoffreoptnodes; 2810 2811 goto PRUNED; 2812 2813 default: 2814 break; 2815 } /*lint !e788*/ 2816 2817 /* stop clock */ 2818 SCIPclockStart(reopt->savingtime, set); 2819 2820 return SCIP_OKAY; 2821 } 2822 2823 /* get new IDs */ 2824 SCIP_CALL( reopttreeCheckMemory(reopt->reopttree, set, blkmem) ); 2825 2826 /* the current node is the root node */ 2827 if( isrootnode ) 2828 { 2829 id = 0; 2830 2831 /* save local constraints 2832 * note: currently, there will be no constraint to save because all global constraints are added by calling 2833 * SCIPprobAddCons. 2834 */ 2835 if (SCIPnodeGetNAddedConss(node) >= 1) 2836 { 2837 assert(reopt->reopttree->reoptnodes[id]->nconss == 0); 2838 2839 SCIP_CALL( saveLocalConssData(reopt->reopttree, set, blkmem, node, id) ); 2840 } 2841 2842 /* store separated cuts 2843 * note: we need to call this after saveLocalConssData to be sure that the local conss array is ordered, first all 2844 * local constraints, then cuts 2845 */ 2846 if( set->reopt_usecuts ) 2847 { 2848 SCIP_CALL( storeCuts(reopt, set, blkmem, lp, id) ); 2849 } 2850 2851 switch( reopttype ) 2852 { 2853 case SCIP_REOPTTYPE_TRANSIT: 2854 /* ensure that no dual constraints are stored */ 2855 SCIP_CALL( SCIPreoptResetDualBndchgs(reopt, node, blkmem) ); 2856 2857 /* update the lowerbound */ 2858 if( !SCIPsetIsInfinity(set, REALABS(lowerbound)) ) 2859 reopt->reopttree->reoptnodes[id]->lowerbound = lowerbound; 2860 2861 goto TRANSIT; 2862 2863 case SCIP_REOPTTYPE_INFSUBTREE: 2864 case SCIP_REOPTTYPE_STRBRANCHED: 2865 reopt->reopttree->reoptnodes[0]->reopttype = (unsigned int)reopttype; 2866 reopt->reopttree->reoptnodes[0]->dualreds = TRUE; 2867 reopt->reopttree->reoptnodes[0]->nvars = 0; 2868 2869 if( reopttype == SCIP_REOPTTYPE_INFSUBTREE ) 2870 { 2871 /* delete the whole subtree induced be the current node */ 2872 SCIP_CALL( deleteChildrenBelow(reopt->reopttree, set, blkmem, 0, FALSE, FALSE) ); 2873 } 2874 2875 /* update the lowerbound */ 2876 if( !SCIPsetIsInfinity(set, REALABS(lowerbound)) ) 2877 reopt->reopttree->reoptnodes[id]->lowerbound = lowerbound; 2878 2879 SCIPsetDebugMsg(set, "update node %d at ID %d:\n", 1, 0); 2880 SCIPsetDebugMsg(set, " -> nvars: 0, ncons: 0, parentID: -, reopttype: %d, lowerbound: %g\n", reopttype, 2881 reopt->reopttree->reoptnodes[id]->lowerbound); 2882 2883 goto PSEUDO; 2884 2885 case SCIP_REOPTTYPE_FEASIBLE: 2886 ++reopt->reopttree->ntotalfeasnodes; 2887 ++reopt->reopttree->nfeasnodes; 2888 reopt->reopttree->reoptnodes[0]->reopttype = (unsigned int)SCIP_REOPTTYPE_FEASIBLE; 2889 reopt->reopttree->reoptnodes[0]->dualreds = FALSE; 2890 2891 if( reopt->reopttree->reoptnodes[0]->childids != NULL && reopt->reopttree->reoptnodes[0]->nchilds > 0 ) 2892 { 2893 /* delete the subtree */ 2894 if( set->reopt_reducetofrontier ) 2895 { 2896 SCIP_CALL( deleteChildrenBelow(reopt->reopttree, set, blkmem, 0, FALSE, FALSE) ); 2897 SCIP_CALL( SCIPreoptResetDualBndchgs(reopt, node, blkmem) ); 2898 } 2899 /* dive through all children and change the reopttype to LEAF */ 2900 else 2901 { 2902 SCIP_CALL( changeReopttypeOfSubtree(reopt->reopttree, 0, SCIP_REOPTTYPE_PRUNED) ); 2903 } 2904 } 2905 else 2906 SCIP_CALL( SCIPreoptResetDualBndchgs(reopt, node, blkmem) ); 2907 2908 /* update the lowerbound */ 2909 if( !SCIPsetIsInfinity(set, REALABS(lowerbound)) ) 2910 reopt->reopttree->reoptnodes[id]->lowerbound = lowerbound; 2911 2912 SCIPsetDebugMsg(set, "update node %d at ID %d:\n", 1, 0); 2913 SCIPsetDebugMsg(set, " -> nvars: 0, ncons: 0, parentID: -, reopttype: %d, lowerbound: %g\n", reopttype, 2914 reopt->reopttree->reoptnodes[id]->lowerbound); 2915 2916 break; 2917 2918 case SCIP_REOPTTYPE_PRUNED: 2919 ++reopt->reopttree->nprunednodes; 2920 ++reopt->reopttree->ntotalprunednodes; 2921 reopt->reopttree->reoptnodes[0]->reopttype = (unsigned int)SCIP_REOPTTYPE_PRUNED; 2922 reopt->reopttree->reoptnodes[0]->dualreds = FALSE; 2923 2924 if( reopt->reopttree->reoptnodes[0]->childids != NULL && reopt->reopttree->reoptnodes[0]->nchilds > 0 ) 2925 { 2926 /* delete the subtree */ 2927 if( set->reopt_reducetofrontier ) 2928 { 2929 SCIP_CALL( deleteChildrenBelow(reopt->reopttree, set, blkmem, 0, FALSE, FALSE) ); 2930 SCIP_CALL( SCIPreoptResetDualBndchgs(reopt, node, blkmem) ); 2931 } 2932 /* dive through all children and change the reopttype to LEAF */ 2933 else 2934 { 2935 SCIP_CALL( changeReopttypeOfSubtree(reopt->reopttree, 0, SCIP_REOPTTYPE_PRUNED) ); 2936 } 2937 } 2938 else 2939 SCIP_CALL( SCIPreoptResetDualBndchgs(reopt, node, blkmem) ); 2940 2941 /* update the lowerbound if it was not set */ 2942 if( !SCIPsetIsInfinity(set, REALABS(lowerbound)) ) 2943 reopt->reopttree->reoptnodes[id]->lowerbound = lowerbound; 2944 2945 SCIPsetDebugMsg(set, "update node %d at ID %d:\n", 1, 0); 2946 SCIPsetDebugMsg(set, " -> nvars: 0, ncons: 0, parentID: -, reopttype: %d, lowerbound:%g \n", reopttype, 2947 reopt->reopttree->reoptnodes[id]->lowerbound); 2948 2949 break; 2950 2951 default: 2952 assert(reopttype == SCIP_REOPTTYPE_TRANSIT 2953 || reopttype == SCIP_REOPTTYPE_INFSUBTREE 2954 || reopttype == SCIP_REOPTTYPE_STRBRANCHED 2955 || reopttype == SCIP_REOPTTYPE_PRUNED 2956 || reopttype == SCIP_REOPTTYPE_FEASIBLE); 2957 break; 2958 }/*lint !e788*/ 2959 2960 /* reset the information of dual bound changes */ 2961 reopt->currentnode = -1; 2962 if( reopt->dualreds != NULL ) 2963 reopt->dualreds->nvars = 0; 2964 2965 /* stop clock */ 2966 SCIPclockStop(reopt->savingtime, set); 2967 2968 return SCIP_OKAY; 2969 } 2970 else 2971 { 2972 int nbndchgdiff; 2973 SCIP_Bool transintoorig; 2974 2975 SCIPsetDebugMsg(set, "try to add node #%lld to the reopttree\n", SCIPnodeGetNumber(node)); 2976 SCIPsetDebugMsg(set, " -> reopttype = %d\n", reopttype); 2977 2978 /* check if we really want to save this node: 2979 * 1. save the node if reopttype is at least SCIP_REOPTTYPE_INFSUBTREE 2980 * 2. save the node if the number of bound changes of this node 2981 * and the last saved node is at least a given number n 2982 */ 2983 2984 /* get the ID of the last saved node or 0 for the root */ 2985 SCIP_CALL( getLastSavedNode(reopt, set, node, &parent, &parentid, &nbndchgdiff) ); 2986 2987 if( (reopttype < SCIP_REOPTTYPE_INFSUBTREE && nbndchgdiff <= set->reopt_maxdiffofnodes) 2988 || reopt->reopttree->reoptnodes[parentid]->reopttype >= SCIP_REOPTTYPE_LEAF ) /*lint !e641*/ 2989 { 2990 SCIPsetDebugMsg(set, " -> skip saving\n"); 2991 2992 /* stop clock */ 2993 SCIPclockStop(reopt->savingtime, set); 2994 2995 return SCIP_OKAY; 2996 } 2997 2998 /* check if there are free slots to store the node */ 2999 SCIP_CALL( reopttreeCheckMemory(reopt->reopttree, set, blkmem) ); 3000 3001 id = SCIPqueueRemoveUInt(reopt->reopttree->openids); 3002 3003 SCIPsetDebugMsg(set, " -> save at ID %u\n", id); 3004 3005 assert(reopt->reopttree->reoptnodes[id] == NULL 3006 || (reopt->reopttree->reoptnodes[id]->nvars == 0 && reopt->reopttree->reoptnodes[id]->nconss == 0)); 3007 assert(id >= 1 && id < reopt->reopttree->reoptnodessize); 3008 assert(!isrootnode); 3009 3010 /* get memory for nodedata */ 3011 assert(reopt->reopttree->reoptnodes[id] == NULL || reopt->reopttree->reoptnodes[id]->nvars == 0); 3012 SCIP_CALL( createReoptnode(reopt->reopttree, set, blkmem, id) ); 3013 reopt->reopttree->reoptnodes[id]->parentID = parentid; 3014 3015 assert(parent != NULL ); 3016 assert((SCIPnodeGetDepth(parent) == 0 && parentid == 0) || (SCIPnodeGetDepth(parent) >= 1 && parentid > 0)); 3017 assert(id >= 1); 3018 3019 /* create the array of "child nodes" if they not exist */ 3020 if( reopt->reopttree->reoptnodes[parentid]->childids == NULL 3021 || reopt->reopttree->reoptnodes[parentid]->allocchildmem == 0 ) 3022 { 3023 SCIP_CALL( reoptnodeCheckMemory(reopt->reopttree->reoptnodes[parentid], set, blkmem, 0, 2, 0) ); 3024 } 3025 3026 /* add the new node as a "child node" of the last saved reoptminization node */ 3027 SCIP_CALL( reoptAddChild(reopt->reopttree, set, blkmem, parentid, id) ); 3028 3029 /* save branching path */ 3030 SCIP_CALL( saveAncestorBranchings(reopt->reopttree, set, blkmem, node, parent, id, parentid) ); 3031 3032 /* save bound changes after some dual reduction */ 3033 if( saveafterdual ) 3034 { 3035 assert(reopttype == SCIP_REOPTTYPE_STRBRANCHED); 3036 SCIP_CALL( saveAfterDualBranchings(reopt, set, blkmem, node, id, &transintoorig) ); 3037 } 3038 else 3039 { 3040 SCIPsetDebugMsg(set, " -> skip saving bound changes after dual reductions.\n"); 3041 } 3042 3043 /* transform all bounds of branched variables and ensure that they are original. */ 3044 SCIP_CALL( transformIntoOrig(reopt, id) ); 3045 3046 /* save pseudo-constraints (if one exists) */ 3047 if (SCIPnodeGetNAddedConss(node) >= 1) 3048 { 3049 assert(reopt->reopttree->reoptnodes[id]->nconss == 0); 3050 3051 SCIP_CALL( saveLocalConssData(reopt->reopttree, set, blkmem, node, id) ); 3052 } 3053 3054 /* store separated cuts 3055 * note: we need to call this after saveLocalConssData to be sure that the local conss array is ordered, first all 3056 * local constraints, then cuts 3057 */ 3058 if( set->reopt_usecuts ) 3059 { 3060 SCIP_CALL( storeCuts(reopt, set, blkmem, lp, id) ); 3061 } 3062 3063 /* update the lowerbound if it was not set */ 3064 if( !SCIPsetIsInfinity(set, REALABS(lowerbound)) ) 3065 reopt->reopttree->reoptnodes[id]->lowerbound = lowerbound; 3066 3067 /* set ID */ 3068 SCIPnodeSetReoptID(node, id); 3069 3070 /* set the REOPTTYPE */ 3071 SCIPnodeSetReopttype(node, reopttype); 3072 3073 SCIPsetDebugMsg(set, "save node #%lld successful\n", SCIPnodeGetNumber(node)); 3074 SCIPsetDebugMsg(set, " -> nvars: %d, ncons: %d, parentID: %u, reopttype: %d, lowerbound: %g\n", 3075 reopt->reopttree->reoptnodes[id]->nvars + reopt->reopttree->reoptnodes[id]->nafterdualvars, 3076 reopt->reopttree->reoptnodes[id]->nconss, reopt->reopttree->reoptnodes[id]->parentID, 3077 reopttype, reopt->reopttree->reoptnodes[id]->lowerbound); 3078 #ifdef SCIP_MORE_DEBUG 3079 { 3080 for( int varnr = 0; varnr < reopt->reopttree->reoptnodes[id]->nvars; ++varnr ) 3081 { 3082 for( int varnr = 0; varnr < reopt->reopttree->reoptnodes[id]->nvars; ++varnr ) 3083 { 3084 SCIPsetDebugMsg(set, " <%s> %s %g\n", SCIPvarGetName(reopt->reopttree->reoptnodes[id]->vars[varnr]), 3085 reopt->reopttree->reoptnodes[id]->varboundtypes[varnr] == SCIP_BOUNDTYPE_LOWER ? 3086 "=>" : "<=", reopt->reopttree->reoptnodes[id]->varbounds[varnr]); 3087 } 3088 for( int varnr = 0; varnr < reopt->reopttree->reoptnodes[id]->nafterdualvars; ++varnr ) 3089 { 3090 SCIPsetDebugMsg(set, " <%s> %s %g (after dual red.)\n", 3091 SCIPvarGetName(reopt->reopttree->reoptnodes[id]->afterdualvars[varnr]), 3092 reopt->reopttree->reoptnodes[id]->afterdualvarboundtypes[varnr] == SCIP_BOUNDTYPE_LOWER ? 3093 "=>" : "<=", reopt->reopttree->reoptnodes[id]->afterdualvarbounds[varnr]); 3094 } 3095 } 3096 } 3097 #endif 3098 } /*lint !e438*/ 3099 3100 switch( reopttype ) 3101 { 3102 case SCIP_REOPTTYPE_TRANSIT: 3103 case SCIP_REOPTTYPE_LOGICORNODE: 3104 case SCIP_REOPTTYPE_LEAF: 3105 TRANSIT: 3106 if( !shrank ) 3107 reopt->reopttree->reoptnodes[id]->reopttype = (unsigned int)reopttype; 3108 else 3109 { 3110 SCIPnodeSetReoptID(node, 0); 3111 SCIPnodeSetReopttype(node, SCIP_REOPTTYPE_NONE); 3112 } 3113 break; 3114 3115 case SCIP_REOPTTYPE_INFSUBTREE: 3116 case SCIP_REOPTTYPE_STRBRANCHED: 3117 PSEUDO: 3118 assert(reopt->currentnode == SCIPnodeGetNumber(node)); 3119 3120 reopt->reopttree->reoptnodes[id]->reopttype = (unsigned int)reopttype; 3121 reopt->reopttree->reoptnodes[id]->dualreds = TRUE; 3122 3123 /* get all the dual information and decide if the constraint need 3124 * to be added next or after next */ 3125 SCIP_CALL( collectDualInformation(reopt, set, blkmem, node, id, reopttype) ); 3126 3127 break; 3128 3129 case SCIP_REOPTTYPE_FEASIBLE: 3130 FEASIBLE: 3131 reopt->reopttree->reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_FEASIBLE; 3132 reopt->reopttree->reoptnodes[id]->dualreds = FALSE; 3133 ++reopt->reopttree->nfeasnodes; 3134 ++reopt->reopttree->ntotalfeasnodes; 3135 3136 break; 3137 3138 case SCIP_REOPTTYPE_PRUNED: 3139 PRUNED: 3140 reopt->reopttree->reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_PRUNED; 3141 reopt->reopttree->reoptnodes[id]->dualreds = FALSE; 3142 ++reopt->reopttree->nprunednodes; 3143 ++reopt->reopttree->ntotalprunednodes; 3144 3145 break; 3146 3147 default: 3148 assert(reopttype == SCIP_REOPTTYPE_TRANSIT 3149 || reopttype == SCIP_REOPTTYPE_LOGICORNODE 3150 || reopttype == SCIP_REOPTTYPE_LEAF 3151 || reopttype == SCIP_REOPTTYPE_INFSUBTREE 3152 || reopttype == SCIP_REOPTTYPE_STRBRANCHED 3153 || reopttype == SCIP_REOPTTYPE_FEASIBLE 3154 || reopttype == SCIP_REOPTTYPE_PRUNED); 3155 break; 3156 } /*lint !e788*/ 3157 3158 /* stop clock */ 3159 SCIPclockStop(reopt->savingtime, set); 3160 3161 /* reset the information of dual bound changes */ 3162 reopt->currentnode = -1; 3163 if( reopt->dualreds != NULL ) 3164 reopt->dualreds->nvars = 0; 3165 3166 return SCIP_OKAY; 3167 } 3168 3169 /** delete the stored information about dual bound changes of the last focused node */ 3170 static 3171 void deleteLastDualBndchgs( 3172 SCIP_REOPT* reopt /**< reoptimization data structure */ 3173 ) 3174 { 3175 assert(reopt != NULL); 3176 3177 if( reopt->dualreds != NULL && reopt->dualreds->nvars > 0 ) 3178 { 3179 SCIPdebugMessage("delete %d dual variable information about node %lld\n", reopt->dualreds->nvars, 3180 reopt->currentnode); 3181 reopt->dualreds->nvars = 0; 3182 reopt->currentnode = -1; 3183 } 3184 } 3185 3186 /** delete the stored constraints that dual information at the given reoptimization node */ 3187 static 3188 SCIP_RETCODE reoptnodeResetDualConss( 3189 SCIP_REOPTNODE* reoptnode, /**< reoptimization node */ 3190 BMS_BLKMEM* blkmem /**< block memory */ 3191 ) 3192 { 3193 assert(reoptnode != NULL); 3194 assert(blkmem != NULL); 3195 3196 if( reoptnode->dualredscur != NULL ) 3197 { 3198 SCIP_REOPTCONSDATA* reoptconsdata; 3199 3200 SCIPdebugMessage("reset dual information (current run)\n"); 3201 3202 reoptconsdata = reoptnode->dualredscur; 3203 3204 BMSfreeBlockMemoryArray(blkmem, &reoptconsdata->boundtypes, reoptconsdata->varssize); 3205 BMSfreeBlockMemoryArray(blkmem, &reoptconsdata->vals, reoptconsdata->varssize); 3206 BMSfreeBlockMemoryArray(blkmem, &reoptconsdata->vars, reoptconsdata->varssize); 3207 BMSfreeBlockMemory(blkmem, &reoptnode->dualredscur); 3208 reoptnode->dualredscur = NULL; 3209 } 3210 3211 if( reoptnode->dualredsnex != NULL ) 3212 { 3213 SCIP_REOPTCONSDATA* reoptconsdata; 3214 3215 SCIPdebugMessage("reset dual information (next run)\n"); 3216 3217 reoptconsdata = reoptnode->dualredsnex; 3218 3219 BMSfreeBlockMemoryArray(blkmem, &reoptconsdata->boundtypes, reoptconsdata->varssize); 3220 BMSfreeBlockMemoryArray(blkmem, &reoptconsdata->vals, reoptconsdata->varssize); 3221 BMSfreeBlockMemoryArray(blkmem, &reoptconsdata->vars, reoptconsdata->varssize); 3222 BMSfreeBlockMemory(blkmem, &reoptnode->dualredsnex); 3223 reoptnode->dualredsnex = NULL; 3224 } 3225 3226 reoptnode->dualreds = FALSE; 3227 3228 return SCIP_OKAY; 3229 } 3230 3231 3232 /** transform given set of variables, bounds and boundtypes into a global cut. 3233 * 3234 * @note: boundtypes can be NULL if all variables are binary or a MIP solution should be separated. 3235 * @note: continuous variables will be skiped if boundtypes is NULL 3236 */ 3237 static 3238 SCIP_RETCODE addGlobalCut( 3239 SCIP_REOPT* reopt, /**< reoptimization data structure */ 3240 BMS_BLKMEM* blkmem, /**< block memory */ 3241 SCIP_SET* set, /**< global SCIP settings */ 3242 SCIP_VAR** vars, /**< variables of the cut */ 3243 SCIP_Real* vals, /**< values of the cut */ 3244 SCIP_BOUNDTYPE* boundtypes, /**< bounds of the cut */ 3245 int nvars, /**< number of variables in the cut */ 3246 int nbinvars, /**< number of binary variables */ 3247 int nintvars /**< number of integer variables */ 3248 ) 3249 { 3250 SCIP_REOPTCONSDATA* reoptconsdata; 3251 int nglbconss; 3252 int nvarsadded; 3253 3254 assert(reopt != NULL); 3255 assert(blkmem != NULL); 3256 assert(set != NULL); 3257 assert(vars != NULL); 3258 assert(vals != NULL); 3259 assert(nbinvars + nintvars == nvars); 3260 3261 nvarsadded = 0; 3262 3263 /* check whether we have enough memory allocated */ 3264 SCIP_CALL( checkMemGlbCons(reopt, set, blkmem, 10) ); 3265 nglbconss = reopt->nglbconss; 3266 reoptconsdata = NULL; 3267 3268 if( reopt->glbconss[nglbconss] == NULL ) 3269 { 3270 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &reopt->glbconss[nglbconss]) ); /*lint !e866*/ 3271 reoptconsdata = reopt->glbconss[nglbconss]; 3272 3273 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reoptconsdata->vars, (int)(nbinvars+2*nintvars)) ); 3274 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reoptconsdata->vals, (int)(nbinvars+2*nintvars)) ); 3275 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reoptconsdata->boundtypes, (int)(nbinvars+2*nintvars)) ); 3276 reoptconsdata->varssize = (int)(nbinvars+2*nintvars); 3277 reoptconsdata->nvars = 0; 3278 } 3279 else 3280 { 3281 assert(reopt->glbconss[nglbconss]->nvars == 0); 3282 assert(reopt->glbconss[nglbconss]->varssize > 0); 3283 3284 reoptconsdata = reopt->glbconss[nglbconss]; 3285 3286 if( reoptconsdata->varssize < nbinvars+2*nintvars ) 3287 { 3288 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reoptconsdata->vars, reoptconsdata->varssize, \ 3289 (int)(nbinvars+2*nintvars)) ); 3290 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reoptconsdata->vals, reoptconsdata->varssize, \ 3291 (int)(nbinvars+2*nintvars)) ); 3292 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reoptconsdata->boundtypes, reoptconsdata->varssize, \ 3293 (int)(nbinvars+2*nintvars)) ); 3294 reoptconsdata->varssize = (int)(nbinvars+2*nintvars); 3295 } 3296 } 3297 assert(reoptconsdata != NULL); 3298 3299 reoptconsdata->lhs = 1.0; 3300 reoptconsdata->rhs = SCIPsetInfinity(set); 3301 reoptconsdata->linear = FALSE; 3302 reoptconsdata->constype = REOPT_CONSTYPE_CUT; 3303 3304 for( int v = 0; v < nvars; ++v ) 3305 { 3306 assert(nvarsadded < reoptconsdata->varssize); 3307 assert(vars[v] != NULL); 3308 assert(SCIPvarIsOriginal(vars[v])); 3309 assert(SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsIntegral(set, vals[v])); 3310 3311 /* if no boundtypes are given we skip continuous variables, otherwise we would add trivial clauses: 3312 * a) x <= ub 3313 * b) lb <= x 3314 * c) (x <= val) or (x >= val) 3315 */ 3316 if( boundtypes == NULL && SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ) 3317 continue; 3318 3319 if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY ) 3320 { 3321 reoptconsdata->vars[nvarsadded] = vars[v]; 3322 3323 if( SCIPsetIsEQ(set, vals[v], 1.0) ) 3324 { 3325 assert(boundtypes == NULL || boundtypes[v] == SCIP_BOUNDTYPE_LOWER); 3326 reoptconsdata->vals[nvarsadded] = 0.0; 3327 reoptconsdata->boundtypes[nvarsadded] = SCIP_BOUNDTYPE_UPPER; 3328 } 3329 else 3330 { 3331 assert(SCIPsetIsEQ(set, vals[v], 0.0)); 3332 assert(boundtypes == NULL || boundtypes[v] == SCIP_BOUNDTYPE_UPPER); 3333 reoptconsdata->vals[nvarsadded] = 1.0; 3334 reoptconsdata->boundtypes[nvarsadded] = SCIP_BOUNDTYPE_LOWER; 3335 } 3336 ++nvarsadded; 3337 } 3338 else if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS) 3339 { 3340 assert(boundtypes != NULL); 3341 3342 reoptconsdata->vals[nvarsadded] = vals[v]; 3343 reoptconsdata->boundtypes[nvarsadded] = (boundtypes[v] == SCIP_BOUNDTYPE_LOWER ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER); 3344 ++nvarsadded; 3345 } 3346 else 3347 { 3348 SCIP_Real roundedval; 3349 SCIP_Real ubglb; 3350 SCIP_Real lbglb; 3351 3352 assert(SCIPvarGetType(vars[v]) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vars[v]) == SCIP_VARTYPE_IMPLINT); 3353 3354 reoptconsdata->vars[nvarsadded] = vars[v]; 3355 3356 ubglb = SCIPvarGetUbGlobal(vars[v]); 3357 lbglb = SCIPvarGetLbGlobal(vars[v]); 3358 3359 /* case 1 : x == val == ub -> x <= ub-1 3360 * case 2 : x == val == lb -> x >= lb+1 3361 * case 3.1: x <= val < ub -> x >= y+1 3362 * case 3.2: x >= val > lb -> x <= y-1 3363 * case 4 : lb < x == val < ub -> (x <= y-1) or (x >= y+1) 3364 */ 3365 3366 /* case 1 */ 3367 if( SCIPsetIsEQ(set, vals[v], ubglb) ) 3368 { 3369 assert(boundtypes == NULL || boundtypes[v] == SCIP_BOUNDTYPE_LOWER); 3370 reoptconsdata->vals[nvarsadded] = ubglb - 1.0; 3371 reoptconsdata->boundtypes[nvarsadded] = SCIP_BOUNDTYPE_UPPER; 3372 ++nvarsadded; 3373 } 3374 /* case 2 */ 3375 else if( SCIPsetIsEQ(set, vals[v], lbglb) ) 3376 { 3377 assert(boundtypes == NULL || boundtypes[v] == SCIP_BOUNDTYPE_UPPER); 3378 reoptconsdata->vals[nvarsadded] = lbglb + 1.0; 3379 reoptconsdata->boundtypes[nvarsadded] = SCIP_BOUNDTYPE_LOWER; 3380 ++nvarsadded; 3381 } 3382 else if( boundtypes != NULL ) 3383 { 3384 /* we round the solution value to get a 'clean' bound */ 3385 assert(SCIPsetIsIntegral(set, vals[v])); 3386 roundedval = SCIPsetRound(set, vals[v]); 3387 3388 /* case 3.1 */ 3389 if( boundtypes[v] == SCIP_BOUNDTYPE_UPPER ) 3390 { 3391 reoptconsdata->vals[nvarsadded] = roundedval + 1.0; 3392 reoptconsdata->boundtypes[nvarsadded] = SCIP_BOUNDTYPE_LOWER; 3393 ++nvarsadded; 3394 } 3395 /* case 3.2 */ 3396 else 3397 { 3398 assert(boundtypes[v] == SCIP_BOUNDTYPE_LOWER); 3399 reoptconsdata->vals[nvarsadded] = roundedval - 1.0; 3400 reoptconsdata->boundtypes[nvarsadded] = SCIP_BOUNDTYPE_UPPER; 3401 ++nvarsadded; 3402 } 3403 } 3404 /* case 4: in this case we have to add two clauses: (x <= val-1) and (x >= val+1) */ 3405 else 3406 { 3407 /* we round the solution value to get a 'clean' bound */ 3408 assert(SCIPsetIsIntegral(set, vals[v])); 3409 roundedval = SCIPsetRound(set, vals[v]); 3410 3411 /* first clause: x <= val-1 */ 3412 reoptconsdata->vals[nvarsadded] = roundedval - 1.0; 3413 reoptconsdata->boundtypes[nvarsadded] = SCIP_BOUNDTYPE_UPPER; 3414 ++nvarsadded; 3415 3416 /* second clause: x >= val+1 */ 3417 reoptconsdata->vars[nvarsadded] = vars[v]; 3418 reoptconsdata->vals[nvarsadded] = roundedval + 1.0; 3419 reoptconsdata->boundtypes[nvarsadded] = SCIP_BOUNDTYPE_LOWER; 3420 ++nvarsadded; 3421 } 3422 } 3423 } 3424 assert(nvars <= nvarsadded); 3425 assert(nvarsadded == nbinvars + 2 * nintvars); 3426 3427 reoptconsdata->nvars = nvarsadded; 3428 ++reopt->nglbconss; 3429 3430 return SCIP_OKAY; 3431 } 3432 3433 /** generate a global constraint to separate an infeasible subtree */ 3434 static 3435 SCIP_RETCODE saveGlobalCons( 3436 SCIP_REOPT* reopt, /**< reoptimization data structure */ 3437 SCIP_SET* set, /**< global SCIP settings */ 3438 BMS_BLKMEM* blkmem, /**< block memory */ 3439 SCIP_NODE* node, /**< node of the search tree */ 3440 REOPT_CONSTYPE consttype /**< reopttype of the constraint */ 3441 ) 3442 { 3443 assert(reopt != NULL); 3444 assert(node != NULL); 3445 3446 if( consttype == REOPT_CONSTYPE_INFSUBTREE ) 3447 { 3448 SCIP_VAR** vars; 3449 SCIP_Real* vals; 3450 SCIP_BOUNDTYPE* boundtypes; 3451 int allocmem; 3452 int nbranchvars; 3453 int nbinvars; 3454 int nintvars; 3455 3456 /* allocate memory to store the infeasible path */ 3457 allocmem = SCIPnodeGetDepth(node); 3458 SCIP_CALL( SCIPsetAllocBufferArray(set, &vars, allocmem) ); 3459 SCIP_CALL( SCIPsetAllocBufferArray(set, &vals, allocmem) ); 3460 SCIP_CALL( SCIPsetAllocBufferArray(set, &boundtypes, allocmem) ); 3461 3462 /* get the branching path */ 3463 SCIPnodeGetAncestorBranchings(node, vars, vals, boundtypes, &nbranchvars, allocmem); 3464 3465 if( allocmem < nbranchvars ) 3466 { 3467 SCIP_CALL( SCIPsetReallocBufferArray(set, &vars, nbranchvars) ); 3468 SCIP_CALL( SCIPsetReallocBufferArray(set, &vals, nbranchvars) ); 3469 SCIP_CALL( SCIPsetReallocBufferArray(set, &boundtypes, nbranchvars) ); 3470 allocmem = nbranchvars; 3471 3472 SCIPnodeGetAncestorBranchings(node, vars, vals, boundtypes, &nbranchvars, allocmem); 3473 } 3474 3475 /* we count the number of binary and (impl) integer variables */ 3476 nbinvars = 0; 3477 nintvars = 0; 3478 for( int v = 0; v < nbranchvars; ++v ) 3479 { 3480 if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY ) 3481 ++nbinvars; 3482 if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vars[v]) == SCIP_VARTYPE_IMPLINT ) 3483 ++nintvars; 3484 } 3485 assert(nbinvars + nintvars == nbranchvars); 3486 3487 SCIP_CALL( addGlobalCut(reopt, blkmem, set, vars, vals, boundtypes, nbranchvars, nbinvars, nintvars) ); 3488 assert(!reopt->glbconss[reopt->nglbconss - 1]->linear); 3489 3490 /* free buffer */ 3491 SCIPsetFreeBufferArray(set, &boundtypes); 3492 SCIPsetFreeBufferArray(set, &vals); 3493 SCIPsetFreeBufferArray(set, &vars); 3494 } 3495 3496 return SCIP_OKAY; 3497 } 3498 3499 3500 /** move all id of child nodes from reoptimization node stored at @p id1 to the node stored at @p id2 */ 3501 static 3502 SCIP_RETCODE reoptMoveIDs( 3503 SCIP_REOPTTREE* reopttree, /**< reopttree */ 3504 SCIP_SET* set, /**< global SCIP settings */ 3505 BMS_BLKMEM* blkmem, /**< block memory */ 3506 unsigned int id1, /**< source id */ 3507 unsigned int id2 /**< target id */ 3508 ) 3509 { 3510 int nchilds_id1; 3511 int nchilds_id2; 3512 3513 assert(reopttree != NULL); 3514 assert(blkmem != NULL); 3515 assert(id1 < reopttree->reoptnodessize); 3516 assert(id2 < reopttree->reoptnodessize); 3517 assert(reopttree->reoptnodes[id1] != NULL); 3518 assert(reopttree->reoptnodes[id2] != NULL); 3519 3520 nchilds_id1 = reopttree->reoptnodes[id1]->nchilds; 3521 nchilds_id2 = reopttree->reoptnodes[id2]->nchilds; 3522 3523 /* ensure that the array storing the child id's is large enough */ 3524 SCIP_CALL( reoptnodeCheckMemory(reopttree->reoptnodes[id2], set, blkmem, 0, nchilds_id1+nchilds_id2, 0) ); 3525 assert(reopttree->reoptnodes[id2]->allocchildmem >= nchilds_id1+nchilds_id2); 3526 3527 SCIPsetDebugMsg(set, "move %d IDs: %u -> %u\n", nchilds_id1, id1, id2); 3528 3529 /* move the ids */ 3530 for( int c = 0; c < nchilds_id1; ++c ) 3531 { 3532 #ifdef SCIP_DEBUG 3533 { 3534 /* check that no id is added twice */ 3535 for( int k = 0; k < nchilds_id2; ++k ) 3536 assert(reopttree->reoptnodes[id2]->childids[k] != reopttree->reoptnodes[id1]->childids[c]); 3537 } 3538 #endif 3539 3540 reopttree->reoptnodes[id2]->childids[nchilds_id2+c] = reopttree->reoptnodes[id1]->childids[c]; 3541 } 3542 3543 /* update the number of childs */ 3544 reopttree->reoptnodes[id1]->nchilds = 0; 3545 reopttree->reoptnodes[id2]->nchilds += nchilds_id1; 3546 3547 return SCIP_OKAY; 3548 } 3549 3550 /** change all bound changes along the root path */ 3551 static 3552 SCIP_RETCODE changeAncestorBranchings( 3553 SCIP_REOPT* reopt, /**< reoptimization data structure */ 3554 SCIP_SET* set, /**< global SCIP settings */ 3555 SCIP_STAT* stat, /**< dynamic problem statistics */ 3556 SCIP_PROB* transprob, /**< transformed problem */ 3557 SCIP_PROB* origprob, /**< original problem */ 3558 SCIP_TREE* tree, /**< search tree */ 3559 SCIP_LP* lp, /**< current LP */ 3560 SCIP_BRANCHCAND* branchcand, /**< branching candidates */ 3561 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 3562 SCIP_CLIQUETABLE* cliquetable, /**< clique table */ 3563 BMS_BLKMEM* blkmem, /**< block memory */ 3564 SCIP_NODE* node, /**< node of the branch and bound tree */ 3565 unsigned int id, /**< id of stored node */ 3566 SCIP_Bool afterdualbranching /**< convert all bound changes made directly after the first bound 3567 * changes based on dual information into normal branchings */ 3568 ) 3569 { 3570 SCIP_REOPTTREE* reopttree; 3571 SCIP_REOPTNODE* reoptnode; 3572 3573 assert(reopt != NULL); 3574 assert(set != NULL); 3575 assert(stat != NULL); 3576 assert(transprob != NULL); 3577 assert(tree != NULL); 3578 assert(lp != NULL); 3579 assert(branchcand != NULL); 3580 assert(eventqueue != NULL); 3581 assert(cliquetable != NULL); 3582 assert(node != NULL); 3583 assert(blkmem != NULL); 3584 3585 reopttree = reopt->reopttree; 3586 assert(reopttree != NULL); 3587 assert(id < reopttree->reoptnodessize); 3588 3589 reoptnode = reopttree->reoptnodes[id]; 3590 assert(reoptnode != NULL); 3591 3592 /* copy memory to ensure that only original variables are saved */ 3593 if( reoptnode->nvars == 0 && reoptnode->nafterdualvars == 0) 3594 return SCIP_OKAY; 3595 3596 /* change the bounds along the branching path */ 3597 for( int v = 0; v < reoptnode->nvars; ++v ) 3598 { 3599 SCIP_VAR* var; 3600 SCIP_Real val; 3601 SCIP_BOUNDTYPE boundtype; 3602 SCIP_Real oldlb; 3603 SCIP_Real oldub; 3604 SCIP_Real newbound; 3605 3606 var = reoptnode->vars[v]; 3607 val = reoptnode->varbounds[v]; 3608 boundtype = reoptnode->varboundtypes[v]; 3609 3610 assert(SCIPvarIsOriginal(var)); 3611 SCIP_CALL( SCIPvarGetProbvarBound(&var, &val, &boundtype) ); 3612 assert(SCIPvarIsTransformed(var)); 3613 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR); 3614 3615 oldlb = SCIPvarGetLbLocal(var); 3616 oldub = SCIPvarGetUbLocal(var); 3617 newbound = val; 3618 3619 assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER); 3620 3621 if( boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, newbound, oldlb) && SCIPsetIsFeasLE(set, newbound, oldub) ) 3622 { 3623 SCIPvarAdjustLb(var, set, &newbound); 3624 3625 SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, 3626 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newbound, SCIP_BOUNDTYPE_LOWER, FALSE) ); 3627 } 3628 else if( boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, newbound, oldub) && SCIPsetIsFeasGE(set, newbound, oldlb) ) 3629 { 3630 SCIPvarAdjustUb(var, set, &newbound); 3631 3632 SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, 3633 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newbound, SCIP_BOUNDTYPE_UPPER, FALSE) ); 3634 } 3635 #ifdef SCIP_MORE_DEBUG 3636 SCIPsetDebugMsg(set, " (path) <%s> %s %g\n", SCIPvarGetName(var), boundtype == SCIP_BOUNDTYPE_LOWER ? "=>" : "<=", newbound); 3637 #endif 3638 } 3639 3640 if( afterdualbranching && reoptnode->nafterdualvars > 0 ) 3641 { 3642 /* check the memory to convert this bound changes into 'normal' */ 3643 SCIP_CALL( reoptnodeCheckMemory(reopttree->reoptnodes[id], set, blkmem, 3644 reoptnode->nvars + reoptnode->nafterdualvars, 0, 0) ); 3645 3646 /* change the bounds */ 3647 for( int v = 0; v < reoptnode->nafterdualvars; ++v ) 3648 { 3649 SCIP_VAR* var; 3650 SCIP_Real val; 3651 SCIP_BOUNDTYPE boundtype; 3652 SCIP_Bool bndchgd; 3653 SCIP_Real oldlb; 3654 SCIP_Real oldub; 3655 SCIP_Real newbound; 3656 3657 var = reoptnode->afterdualvars[v]; 3658 val = reoptnode->afterdualvarbounds[v]; 3659 boundtype = reoptnode->afterdualvarboundtypes[v]; 3660 3661 assert(SCIPvarIsOriginal(var)); 3662 SCIP_CALL( SCIPvarGetProbvarBound(&var, &val, &boundtype) ); 3663 assert(SCIPvarIsTransformed(var)); 3664 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR); 3665 3666 bndchgd = FALSE; 3667 3668 oldlb = SCIPvarGetLbLocal(var); 3669 oldub = SCIPvarGetUbLocal(var); 3670 newbound = val; 3671 3672 if( boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, newbound, oldlb) && SCIPsetIsFeasLE(set, newbound, oldub) ) 3673 { 3674 SCIPvarAdjustLb(var, set, &newbound); 3675 SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, 3676 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newbound, SCIP_BOUNDTYPE_LOWER, FALSE) ); 3677 3678 bndchgd = TRUE; 3679 } 3680 else if( boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, newbound, oldub) && SCIPsetIsFeasGE(set, newbound, oldlb) ) 3681 { 3682 SCIPvarAdjustUb(var, set, &newbound); 3683 SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, 3684 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newbound, SCIP_BOUNDTYPE_UPPER, FALSE) ); 3685 3686 bndchgd = TRUE; 3687 } 3688 3689 assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER); 3690 3691 #ifdef SCIP_MORE_DEBUG 3692 SCIPsetDebugMsg(set, " (prop) <%s> %s %g\n", SCIPvarGetName(var), boundtype == SCIP_BOUNDTYPE_LOWER ? "=>" : "<=", newbound); 3693 #endif 3694 if( bndchgd ) 3695 { 3696 int nvars; 3697 3698 nvars = reoptnode->nvars; 3699 reoptnode->vars[nvars] = reoptnode->afterdualvars[v]; 3700 reoptnode->varbounds[nvars] = reoptnode->afterdualvarbounds[v]; 3701 reoptnode->varboundtypes[nvars] = reoptnode->afterdualvarboundtypes[v]; 3702 ++reoptnode->nvars; 3703 } 3704 } 3705 3706 /* free the afterdualvars, -bounds, and -boundtypes */ 3707 BMSfreeBlockMemoryArray(blkmem, &reoptnode->afterdualvarboundtypes, reoptnode->afterdualvarssize); 3708 reoptnode->afterdualvarboundtypes = NULL; 3709 3710 BMSfreeBlockMemoryArray(blkmem, &reoptnode->afterdualvarbounds, reoptnode->afterdualvarssize); 3711 reoptnode->afterdualvarbounds = NULL; 3712 3713 BMSfreeBlockMemoryArray(blkmem, &reoptnode->afterdualvars, reoptnode->afterdualvarssize); 3714 reoptnode->afterdualvars = NULL; 3715 3716 reoptnode->nafterdualvars = 0; 3717 reoptnode->afterdualvarssize = 0; 3718 } 3719 3720 return SCIP_OKAY; 3721 } 3722 3723 3724 /** add a constraint to ensure that at least one variable bound gets different */ 3725 static 3726 SCIP_RETCODE addSplitcons( 3727 SCIP_REOPT* reopt, /**< reoptimization data structure */ 3728 SCIP* scip, /**< SCIP data structure */ 3729 SCIP_SET* set, /**< global SCIP settings */ 3730 SCIP_STAT* stat, /**< dynamic problem statistics */ 3731 BMS_BLKMEM* blkmem, /**< block memory */ 3732 SCIP_PROB* transprob, /**< transformed problem */ 3733 SCIP_PROB* origprob, /**< original problem */ 3734 SCIP_TREE* tree, /**< search tree */ 3735 SCIP_LP* lp, /**< current LP */ 3736 SCIP_BRANCHCAND* branchcand, /**< branching candidates */ 3737 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 3738 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 3739 SCIP_NODE* node, /**< node corresponding to the pruned part */ 3740 unsigned int id /**< id of stored node */ 3741 ) 3742 { 3743 SCIP_CONS* cons; 3744 char name[SCIP_MAXSTRLEN]; 3745 3746 assert(reopt != NULL); 3747 assert(reopt->reopttree != NULL); 3748 assert(id < reopt->reopttree->reoptnodessize); 3749 assert(reopt->reopttree->reoptnodes[id] != NULL); 3750 assert(reopt->reopttree->reoptnodes[id]->dualreds); 3751 assert(reopt->reopttree->reoptnodes[id]->dualredscur != NULL); 3752 assert(scip != NULL); 3753 assert(set != NULL); 3754 assert(stat != NULL); 3755 assert(blkmem != NULL); 3756 assert(transprob != NULL); 3757 assert(origprob != NULL); 3758 assert(tree != NULL); 3759 assert(lp != NULL); 3760 assert(branchcand != NULL); 3761 assert(eventqueue != NULL); 3762 assert(node != NULL); 3763 3764 assert(reopt->reopttree->reoptnodes[id]->dualredscur->constype == REOPT_CONSTYPE_DUALREDS 3765 || reopt->reopttree->reoptnodes[id]->dualredscur->constype == REOPT_CONSTYPE_INFSUBTREE); 3766 3767 #ifndef NDEBUG 3768 if( reopt->reopttree->reoptnodes[id]->dualredscur->constype == REOPT_CONSTYPE_DUALREDS ) 3769 SCIPsetDebugMsg(set, " create a split-node #%lld\n", SCIPnodeGetNumber(node)); 3770 else 3771 SCIPsetDebugMsg(set, " separate an infeasible subtree\n"); 3772 #endif 3773 3774 /* if the constraint consists of exactly one variable it can be interpreted 3775 * as a normal branching step, i.e., we can fix the variable to the negated bound */ 3776 if( reopt->reopttree->reoptnodes[id]->dualredscur->nvars == 1 ) 3777 { 3778 SCIP_REOPTCONSDATA* reoptconsdata; 3779 SCIP_VAR* var; 3780 SCIP_BOUNDTYPE boundtype; 3781 SCIP_Real oldlb; 3782 SCIP_Real oldub; 3783 SCIP_Real newbound; 3784 3785 reoptconsdata = reopt->reopttree->reoptnodes[id]->dualredscur; 3786 assert(!reoptconsdata->linear); 3787 assert(reoptconsdata->vars != NULL); 3788 assert(reoptconsdata->vals != NULL); 3789 assert(reoptconsdata->boundtypes != NULL); 3790 3791 var = reoptconsdata->vars[0]; 3792 newbound = reoptconsdata->vals[0]; 3793 boundtype = reoptconsdata->boundtypes[0]; 3794 3795 assert(SCIPvarIsOriginal(var)); 3796 SCIP_CALL( SCIPvarGetProbvarBound(&var, &newbound, &boundtype) ); 3797 assert(SCIPvarIsTransformed(var)); 3798 3799 oldlb = SCIPvarGetLbLocal(var); 3800 oldub = SCIPvarGetUbLocal(var); 3801 3802 if( boundtype == SCIP_BOUNDTYPE_LOWER ) 3803 { 3804 newbound = reoptconsdata->vals[0] - 1.0; 3805 /* if newbound > local upper bound, the variable cannot take the old value and we exit */ 3806 if( SCIPisGT(scip, newbound, oldub) ) 3807 return SCIP_OKAY; 3808 assert(SCIPisLE(scip, newbound, oldub)); 3809 } 3810 else 3811 { 3812 newbound = reoptconsdata->vals[0] + 1.0; 3813 /* if newbound < local lower bound, the variable cannot take the old value and we exit */ 3814 if( SCIPisLT(scip, newbound, oldlb) ) 3815 return SCIP_OKAY; 3816 assert(SCIPisGE(scip, newbound, oldlb)); 3817 } 3818 boundtype = (SCIP_BOUNDTYPE) (1 - (int)boundtype); 3819 assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER); 3820 3821 if( boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, newbound, oldlb) && SCIPsetIsFeasLE(set, newbound, oldub) ) 3822 { 3823 SCIPvarAdjustLb(var, set, &newbound); 3824 SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, 3825 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newbound, SCIP_BOUNDTYPE_LOWER, FALSE) ); 3826 } 3827 else if( boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, newbound, oldub) && SCIPsetIsFeasGE(set, newbound, oldlb) ) 3828 { 3829 SCIPvarAdjustUb(var, set, &newbound); 3830 SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, 3831 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newbound, SCIP_BOUNDTYPE_UPPER, FALSE) ); 3832 } 3833 3834 SCIPsetDebugMsg(set, " -> constraint consists of only one variable: <%s> %s %g\n", SCIPvarGetName(var), 3835 boundtype == SCIP_BOUNDTYPE_LOWER ? "=>" : "<=", newbound); 3836 } 3837 else 3838 { 3839 SCIP_REOPTCONSDATA* reoptconsdata; 3840 SCIP_VAR** consvars; 3841 SCIP_Real consval; 3842 SCIP_BOUNDTYPE consboundtype; 3843 int nbinvars = 0; 3844 #ifndef NDEBUG 3845 int nintvars = 0; 3846 int ncontvars = 0; 3847 #endif 3848 3849 reoptconsdata = reopt->reopttree->reoptnodes[id]->dualredscur; 3850 assert(!reoptconsdata->linear); 3851 assert(reoptconsdata->vars != NULL); 3852 assert(reoptconsdata->vals != NULL); 3853 assert(reoptconsdata->boundtypes != NULL); 3854 3855 /* allocate buffer */ 3856 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, reoptconsdata->nvars) ); 3857 3858 /* count number of binary, integer, and continuous variables */ 3859 for( int v = 0; v < reoptconsdata->nvars; ++v ) 3860 { 3861 switch ( SCIPvarGetType(reoptconsdata->vars[v]) ) 3862 { 3863 case SCIP_VARTYPE_BINARY: 3864 ++nbinvars; 3865 break; 3866 case SCIP_VARTYPE_IMPLINT: 3867 case SCIP_VARTYPE_INTEGER: 3868 if( SCIPisEQ(scip, SCIPvarGetLbLocal(reoptconsdata->vars[v]), 0.0) 3869 && SCIPisEQ(scip, SCIPvarGetUbLocal(reoptconsdata->vars[v]), 1.0) ) 3870 ++nbinvars; 3871 #ifndef NDEBUG 3872 else 3873 ++nintvars; 3874 #endif 3875 break; 3876 case SCIP_VARTYPE_CONTINUOUS: 3877 #ifndef NDEBUG 3878 ++ncontvars; 3879 #endif 3880 break; 3881 default: 3882 SCIPerrorMessage("Variable <%s> has to be either binary, (implied) integer, or continuous.\n", 3883 SCIPvarGetName(reoptconsdata->vars[v])); 3884 return SCIP_INVALIDDATA; 3885 } 3886 } 3887 3888 if( reoptconsdata->constype == REOPT_CONSTYPE_INFSUBTREE ) 3889 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "reopt_inf"); 3890 else 3891 { 3892 assert(reoptconsdata->constype == REOPT_CONSTYPE_DUALREDS); 3893 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "reopt_dual"); 3894 } 3895 3896 /* case 1: all variables are binary, we use a logic-or constraint. */ 3897 if( reoptconsdata->nvars == nbinvars ) 3898 { 3899 for( int v = 0; v < reoptconsdata->nvars; ++v ) 3900 { 3901 consvars[v] = reoptconsdata->vars[v]; 3902 consval = reoptconsdata->vals[v]; 3903 consboundtype = SCIPsetIsFeasEQ(set, consval, 1.0) ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER; 3904 3905 assert(SCIPvarIsOriginal(consvars[v])); 3906 SCIP_CALL( SCIPvarGetProbvarBound(&consvars[v], &consval, &consboundtype) ); 3907 assert(SCIPvarIsTransformed(consvars[v])); 3908 assert(SCIPvarGetStatus(consvars[v]) != SCIP_VARSTATUS_MULTAGGR); 3909 3910 if ( SCIPsetIsFeasEQ(set, consval, 1.0) ) 3911 { 3912 SCIP_CALL( SCIPvarNegate(consvars[v], blkmem, set, stat, &consvars[v]) ); 3913 assert(SCIPvarIsNegated(consvars[v])); 3914 } 3915 } 3916 3917 SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, name, reoptconsdata->nvars, consvars, 3918 FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE) ); 3919 } 3920 /* case 2: at least one variable is integer or continuous. we use a bounddisjunction constraint. */ 3921 else 3922 { 3923 SCIP_Real* consvals; 3924 SCIP_BOUNDTYPE* consboundtypes; 3925 3926 assert(nintvars > 0 || ncontvars > 0); 3927 3928 /* alloc buffer memory */ 3929 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, reoptconsdata->nvars) ); 3930 SCIP_CALL( SCIPallocBufferArray(scip, &consboundtypes, reoptconsdata->nvars) ); 3931 3932 /* iterate over all variables and transform them */ 3933 for( int v = 0; v < reoptconsdata->nvars; ++v ) 3934 { 3935 consvars[v] = reoptconsdata->vars[v]; 3936 consvals[v] = reoptconsdata->vals[v]; 3937 consboundtypes[v] = reoptconsdata->boundtypes[v]; 3938 3939 /* we have to switch the bounds. 3940 * case 1: integer variable with bound x <= u is transformed to u+1 <= x 3941 * and l <= x is transformed to x <= l-1 3942 * case 2: continuous variable with bound x <= u is transformed to u <= x 3943 * and l <= x is transformed to x <= l 3944 */ 3945 if( SCIPvarGetType(consvars[v]) == SCIP_VARTYPE_BINARY 3946 || SCIPvarGetType(consvars[v]) == SCIP_VARTYPE_INTEGER 3947 || SCIPvarGetType(consvars[v]) == SCIP_VARTYPE_IMPLINT ) 3948 { 3949 if( consboundtypes[v] == SCIP_BOUNDTYPE_UPPER ) 3950 { 3951 consvals[v] += 1.0; 3952 assert(SCIPsetIsLE(set, consvals[v], SCIPvarGetUbGlobal(consvars[v]))); 3953 } 3954 else 3955 { 3956 consvals[v] -= 1.0; 3957 assert(SCIPsetIsGE(set, consvals[v], SCIPvarGetLbGlobal(consvars[v]))); 3958 } 3959 } 3960 3961 consboundtypes[v] = (SCIP_BOUNDTYPE)(1 - consboundtypes[v]); /*lint !e641*/ 3962 3963 assert(SCIPvarIsOriginal(consvars[v])); 3964 SCIP_CALL( SCIPvarGetProbvarBound(&consvars[v], &consvals[v], &consboundtypes[v]) ); 3965 assert(SCIPvarIsTransformed(consvars[v])); 3966 assert(SCIPvarGetStatus(consvars[v]) != SCIP_VARSTATUS_MULTAGGR); 3967 } 3968 3969 /* create the constraints and add them to the corresponding nodes */ 3970 SCIP_CALL( SCIPcreateConsBounddisjunctionRedundant(scip, &cons, name, reoptconsdata->nvars, consvars, consboundtypes, 3971 consvals, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE) ); 3972 3973 /* free buffer memory */ 3974 SCIPfreeBufferArray(scip, &consboundtypes); 3975 SCIPfreeBufferArray(scip, &consvals); 3976 } 3977 3978 SCIPsetDebugMsg(set, " -> add constraint in node #%lld:\n", SCIPnodeGetNumber(node)); 3979 #ifdef SCIP_DEBUG_CONSS 3980 SCIPdebugPrintCons(scip, cons, NULL); 3981 #endif 3982 3983 SCIP_CALL( SCIPaddConsNode(scip, node, cons, NULL) ); 3984 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 3985 3986 /* free buffer */ 3987 SCIPfreeBufferArray(scip, &consvars); 3988 } 3989 3990 return SCIP_OKAY; 3991 } 3992 3993 /** fix all bounds ad stored in dualredscur at the given node @p node_fix */ 3994 static 3995 SCIP_RETCODE fixBounds( 3996 SCIP_REOPT* reopt, /**< reoptimization data structure */ 3997 SCIP_SET* set, /**< global SCIP settings */ 3998 SCIP_STAT* stat, /**< dynamic problem statistics */ 3999 SCIP_PROB* transprob, /**< transformed problem */ 4000 SCIP_PROB* origprob, /**< original problem */ 4001 SCIP_TREE* tree, /**< search tree */ 4002 SCIP_LP* lp, /**< current LP */ 4003 SCIP_BRANCHCAND* branchcand, /**< branching candidates */ 4004 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 4005 SCIP_CLIQUETABLE* cliquetable, /**< clique table */ 4006 BMS_BLKMEM* blkmem, /**< block memory */ 4007 SCIP_NODE* node, /**< node corresponding to the fixed part */ 4008 unsigned int id, /**< id of stored node */ 4009 SCIP_Bool updatedualconss /**< update constraint representing dual bound changes */ 4010 ) 4011 { 4012 SCIP_REOPTTREE* reopttree; 4013 SCIP_REOPTNODE* reoptnode; 4014 4015 assert(reopt != NULL); 4016 assert(set != NULL); 4017 assert(stat != NULL); 4018 assert(transprob != NULL); 4019 assert(origprob != NULL); 4020 assert(tree != NULL); 4021 assert(lp != NULL); 4022 assert(branchcand != NULL); 4023 assert(eventqueue != NULL); 4024 assert(cliquetable != NULL); 4025 assert(node != NULL); 4026 assert(blkmem != NULL); 4027 4028 reopttree = reopt->reopttree; 4029 assert(reopttree != NULL); 4030 assert(0 < id && id < reopttree->reoptnodessize); 4031 4032 reoptnode = reopttree->reoptnodes[id]; 4033 assert(reoptnode != NULL); 4034 assert(reoptnode->dualreds); 4035 assert(reoptnode->dualredscur != NULL); 4036 4037 /* ensure that the arrays to store the bound changes are large enough */ 4038 SCIP_CALL( reoptnodeCheckMemory(reoptnode, set, blkmem, reoptnode->nvars + reoptnode->dualredscur->nvars, 0, 0) ); 4039 4040 for( int v = 0; v < reoptnode->dualredscur->nvars; ++v ) 4041 { 4042 SCIP_VAR* var; 4043 SCIP_Real val; 4044 SCIP_BOUNDTYPE boundtype; 4045 SCIP_Bool bndchgd; 4046 4047 var = reoptnode->dualredscur->vars[v]; 4048 val = reoptnode->dualredscur->vals[v]; 4049 boundtype = reoptnode->dualredscur->boundtypes[v]; 4050 4051 SCIP_CALL(SCIPvarGetProbvarBound(&var, &val, &boundtype)); 4052 assert(SCIPvarIsTransformedOrigvar(var)); 4053 4054 bndchgd = FALSE; 4055 4056 if( boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, val, SCIPvarGetLbLocal(var)) 4057 && SCIPsetIsFeasLE(set, val, SCIPvarGetUbLocal(var)) ) 4058 { 4059 SCIPvarAdjustLb(var, set, &val); 4060 SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, 4061 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, val, SCIP_BOUNDTYPE_LOWER, FALSE) ); 4062 4063 bndchgd = TRUE; 4064 } 4065 else if( boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, val, SCIPvarGetUbLocal(var)) 4066 && SCIPsetIsFeasGE(set, val, SCIPvarGetLbLocal(var)) ) 4067 { 4068 SCIPvarAdjustUb(var, set, &val); 4069 SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, 4070 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, val, SCIP_BOUNDTYPE_UPPER, FALSE) ); 4071 4072 bndchgd = TRUE; 4073 } 4074 else if( boundtype != SCIP_BOUNDTYPE_LOWER && boundtype != SCIP_BOUNDTYPE_UPPER ) 4075 { 4076 SCIPerrorMessage("** Unknown boundtype: %d **\n", boundtype); 4077 return SCIP_INVALIDDATA; 4078 } 4079 #ifdef SCIP_MORE_DEBUG 4080 SCIPsetDebugMsg(set, " (dual) <%s> %s %g\n", SCIPvarGetName(var), boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", val); 4081 #endif 4082 /* add variable and bound to branching path information, because we don't want to delete this data */ 4083 if( bndchgd ) 4084 { 4085 int pos; 4086 SCIP_Real constant; 4087 SCIP_Real scalar; 4088 4089 pos = reoptnode->nvars; 4090 4091 reoptnode->vars[pos] = var; 4092 scalar = 1.0; 4093 constant = 0.0; 4094 SCIP_CALL( SCIPvarGetOrigvarSum(&reoptnode->vars[pos], &scalar, &constant) ); 4095 assert(SCIPvarIsOriginal(reoptnode->vars[pos])); 4096 4097 reoptnode->varbounds[pos] = reoptnode->dualredscur->vals[v]; 4098 reoptnode->varboundtypes[pos] = (SCIPsetIsFeasEQ(set, reoptnode->varbounds[pos], 0.0) ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER); 4099 ++reoptnode->nvars; 4100 } 4101 } 4102 4103 if( updatedualconss ) 4104 { 4105 /* delete dualredscur and move dualredsnex -> dualredscur */ 4106 SCIP_CALL( reoptnodeUpdateDualConss(reoptnode, blkmem) ); 4107 } 4108 4109 return SCIP_OKAY; 4110 } 4111 4112 /** fix all bounds corresponding to dual bound changes in a previous iteration in the fashion of interdiction branching; 4113 * keep the first negbndchg-1 bound changes as stored in dualredscur and negate the negbndchg-th bound. 4114 */ 4115 static 4116 SCIP_RETCODE fixInterdiction( 4117 SCIP_REOPT* reopt, /**< reoptimization data structure */ 4118 SCIP_SET* set, /**< global SCIP settings */ 4119 SCIP_STAT* stat, /**< dynamic problem statistics */ 4120 SCIP_PROB* transprob, /**< transformed problem */ 4121 SCIP_PROB* origprob, /**< original problem */ 4122 SCIP_TREE* tree, /**< search tree */ 4123 SCIP_LP* lp, /**< current LP */ 4124 SCIP_BRANCHCAND* branchcand, /**< branching candidates */ 4125 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 4126 SCIP_CLIQUETABLE* cliquetable, /**< clique table */ 4127 BMS_BLKMEM* blkmem, /**< block memory */ 4128 SCIP_NODE* node, /**< child node */ 4129 unsigned int id, /**< id of the node */ 4130 int* perm, /**< array of permuted indices */ 4131 SCIP_VAR** vars, /**< variables */ 4132 SCIP_Real* vals, /**< bounds */ 4133 SCIP_BOUNDTYPE* boundtypes, /**< boundtypes */ 4134 int nvars, /**< number of variables */ 4135 int negbndchg /**< index of the variable that should negated */ 4136 ) 4137 { 4138 SCIP_VAR* var; 4139 SCIP_Real val; 4140 SCIP_BOUNDTYPE boundtype; 4141 int nbndchgs; 4142 4143 assert(reopt != NULL); 4144 assert(set != NULL); 4145 assert(stat != NULL); 4146 assert(transprob != NULL); 4147 assert(origprob != NULL); 4148 assert(tree != NULL); 4149 assert(lp != NULL); 4150 assert(branchcand != NULL); 4151 assert(eventqueue != NULL); 4152 assert(cliquetable != NULL); 4153 assert(node != NULL); 4154 assert(perm != NULL); 4155 assert(vars != NULL); 4156 assert(vals != NULL); 4157 assert(boundtypes != NULL); 4158 assert(nvars >= 0); 4159 assert(blkmem != NULL); 4160 assert(0 < id && id < reopt->reopttree->reoptnodessize); 4161 4162 #ifndef NDEBUG 4163 { 4164 SCIP_REOPTTREE* reopttree; 4165 SCIP_REOPTNODE* reoptnode; 4166 4167 reopttree = reopt->reopttree; 4168 assert(reopttree != NULL); 4169 4170 reoptnode = reopttree->reoptnodes[id]; 4171 assert(reoptnode != NULL); 4172 assert(reoptnode->dualreds); 4173 } 4174 #endif 4175 4176 nbndchgs = MIN(negbndchg, nvars); 4177 4178 /* change the first nbndchg-1 bounds as stored in dualredscur and negate the negbndchg-th bound */ 4179 for( int v = 0; v < nbndchgs; ++v ) 4180 { 4181 var = vars[perm[v]]; 4182 val = vals[perm[v]]; 4183 boundtype = boundtypes[perm[v]]; 4184 4185 SCIP_CALL(SCIPvarGetProbvarBound(&var, &val, &boundtype)); 4186 assert(SCIPvarIsTransformedOrigvar(var)); 4187 4188 /* negate the last bound change */ 4189 if( v == nbndchgs-1 ) 4190 { 4191 boundtype = (SCIP_BOUNDTYPE)(SCIP_BOUNDTYPE_UPPER - boundtype); /*lint !e656*/ 4192 if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && boundtype == SCIP_BOUNDTYPE_UPPER ) 4193 val = val - 1.0; 4194 else if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && boundtype == SCIP_BOUNDTYPE_LOWER ) 4195 val = val + 1.0; 4196 } 4197 4198 if( boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, val, SCIPvarGetLbLocal(var)) 4199 && SCIPsetIsFeasLE(set, val, SCIPvarGetUbLocal(var)) ) 4200 { 4201 SCIPvarAdjustLb(var, set, &val); 4202 SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, 4203 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, val, SCIP_BOUNDTYPE_LOWER, FALSE) ); 4204 } 4205 else if( boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, val, SCIPvarGetUbLocal(var)) 4206 && SCIPsetIsFeasGE(set, val, SCIPvarGetLbLocal(var)) ) 4207 { 4208 SCIPvarAdjustUb(var, set, &val); 4209 SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, 4210 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, val, SCIP_BOUNDTYPE_UPPER, FALSE) ); 4211 } 4212 else if( boundtype != SCIP_BOUNDTYPE_LOWER && boundtype != SCIP_BOUNDTYPE_UPPER ) 4213 { 4214 SCIPerrorMessage("** Unknown boundtype: %d **\n", boundtype); 4215 return SCIP_INVALIDDATA; 4216 } 4217 #ifdef SCIP_MORE_DEBUG 4218 SCIPsetDebugMsg(set, " (dual) <%s> %s %g\n", SCIPvarGetName(var), boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", val); 4219 #endif 4220 } 4221 4222 return SCIP_OKAY; 4223 } 4224 4225 /** add all constraints stored at @p id to the given nodes @p node_fix and @p node_cons */ 4226 static 4227 SCIP_RETCODE addLocalConss( 4228 SCIP* scip, /**< SCIP data structure */ 4229 SCIP_REOPT* reopt, /**< reoptimization data structure */ 4230 SCIP_SET* set, /**< global SCIP settings */ 4231 SCIP_STAT* stat, /**< dynamic problem statistics */ 4232 BMS_BLKMEM* blkmem, /**< block memory */ 4233 SCIP_NODE* node, /**< node of the branch and bound tree*/ 4234 unsigned int id /**< id of stored node */ 4235 ) 4236 { 4237 char name[SCIP_MAXSTRLEN]; 4238 4239 assert(scip != NULL); 4240 assert(reopt != NULL); 4241 assert(reopt->reopttree != NULL); 4242 assert(set != NULL); 4243 assert(stat != NULL); 4244 assert(blkmem != NULL); 4245 assert(node != NULL); 4246 assert(0 < id && id < reopt->reopttree->reoptnodessize); 4247 4248 if( reopt->reopttree->reoptnodes[id]->nconss == 0 ) 4249 return SCIP_OKAY; 4250 4251 SCIPsetDebugMsg(set, " -> add %d constraint(s) to node #%lld:\n", reopt->reopttree->reoptnodes[id]->nconss, 4252 SCIPnodeGetNumber(node)); 4253 4254 for( int c = 0; c < reopt->reopttree->reoptnodes[id]->nconss; ++c ) 4255 { 4256 SCIP_CONS* cons; 4257 SCIP_REOPTCONSDATA* reoptconsdata; 4258 4259 reoptconsdata = reopt->reopttree->reoptnodes[id]->conss[c]; 4260 assert(reoptconsdata != NULL); 4261 assert(reoptconsdata->nvars > 0); 4262 assert(reoptconsdata->varssize >= reoptconsdata->nvars); 4263 4264 if( reoptconsdata->constype == REOPT_CONSTYPE_CUT ) 4265 continue; 4266 4267 if( reoptconsdata->constype == REOPT_CONSTYPE_INFSUBTREE ) 4268 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "reopt_inf"); 4269 else if( reoptconsdata->constype == REOPT_CONSTYPE_DUALREDS ) 4270 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "reopt_dual"); 4271 else 4272 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "reopt_unkn"); 4273 4274 if( reoptconsdata->linear ) 4275 { 4276 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, reoptconsdata->nvars, reoptconsdata->vars, reoptconsdata->vals, 4277 reoptconsdata->lhs, reoptconsdata->rhs, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE) ); 4278 } 4279 else 4280 { 4281 assert(reoptconsdata->boundtypes != NULL); 4282 SCIP_CALL( SCIPcreateConsBounddisjunctionRedundant(scip, &cons, name, reoptconsdata->nvars, reoptconsdata->vars, reoptconsdata->boundtypes, 4283 reoptconsdata->vals, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE) ); 4284 } 4285 #ifdef SCIP_DEBUG_CONSS 4286 SCIPdebugPrintCons(scip, cons, NULL); 4287 #endif 4288 SCIP_CALL( SCIPaddConsNode(scip, node, cons, NULL) ); 4289 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 4290 } 4291 4292 return SCIP_OKAY; 4293 } 4294 4295 /** reset the internal statistics at the beginning of a new iteration */ 4296 static 4297 void resetStats( 4298 SCIP_REOPT* reopt /**< reoptimization data structure */ 4299 ) 4300 { 4301 assert(reopt != NULL); 4302 4303 reopt->lastbranched = -1; 4304 reopt->currentnode = -1; 4305 reopt->lastseennode = -1; 4306 reopt->reopttree->nfeasnodes = 0; 4307 reopt->reopttree->ninfnodes = 0; 4308 reopt->reopttree->nprunednodes = 0; 4309 reopt->reopttree->ncutoffreoptnodes = 0; 4310 4311 if( reopt->dualreds != NULL ) 4312 reopt->dualreds->nvars = 0; 4313 } 4314 4315 /** check the stored bound changes of all child nodes for redundancy and infeasibility 4316 * 4317 * Due to strongbranching initialization at node stored at @p id it can happen, that some bound changes stored in the 4318 * child nodes of the reoptimization node stored at @p id become redundant or make the subproblem infeasible. in this 4319 * method we remove all redundant bound changes and delete infeasible child nodes. 4320 */ 4321 static 4322 SCIP_RETCODE dryBranch( 4323 SCIP_REOPT* reopt, /**< reoptimization data structure */ 4324 SCIP_SET* set, /**< global SCIP settings */ 4325 BMS_BLKMEM* blkmem, /**< block memory */ 4326 SCIP_Bool* runagain, /**< pointer to store of this method should run again */ 4327 unsigned int id /**< id of stored node */ 4328 ) 4329 { 4330 SCIP_REOPTNODE* reoptnode; 4331 unsigned int* cutoffchilds; 4332 int ncutoffchilds = 0; 4333 unsigned int* redchilds; 4334 int nredchilds = 0; 4335 int c; 4336 4337 assert(reopt != NULL); 4338 assert(reopt->reopttree != NULL); 4339 assert(id < reopt->reopttree->reoptnodessize); 4340 assert(reopt->reopttree->reoptnodes != NULL); 4341 assert(reopt->reopttree->reoptnodes[id] != NULL); 4342 4343 reoptnode = reopt->reopttree->reoptnodes[id]; 4344 4345 *runagain = FALSE; 4346 4347 SCIPsetDebugMsg(set, "start dry branching of node at ID %u\n", id); 4348 4349 /* allocate buffer arrays */ 4350 SCIP_CALL( SCIPsetAllocBufferArray(set, &cutoffchilds, reoptnode->nchilds) ); 4351 SCIP_CALL( SCIPsetAllocBufferArray(set, &redchilds, reoptnode->nchilds) ); 4352 4353 /* iterate over all child nodes and check each bound changes 4354 * for redundancy and conflict */ 4355 for( c = 0; c < reoptnode->nchilds; ++c ) 4356 { 4357 SCIP_REOPTNODE* child; 4358 SCIP_Bool cutoff; 4359 SCIP_Bool redundant; 4360 int* redundantvars; 4361 int nredundantvars; 4362 unsigned int childid; 4363 4364 cutoff = FALSE; 4365 redundant = FALSE; 4366 nredundantvars = 0; 4367 4368 childid = reoptnode->childids[c]; 4369 assert(childid < reopt->reopttree->reoptnodessize); 4370 child = reopt->reopttree->reoptnodes[childid]; 4371 assert(child != NULL); 4372 #ifdef SCIP_MORE_DEBUG 4373 SCIPsetDebugMsg(set, "-> check child at ID %d (%d vars, %d conss):\n", childid, child->nvars, child->nconss); 4374 #endif 4375 if( child->nvars > 0 ) 4376 { 4377 /* allocate buffer memory to store the redundant variables */ 4378 SCIP_CALL( SCIPsetAllocBufferArray(set, &redundantvars, child->nvars) ); 4379 4380 for( int v = 0; v < child->nvars && !cutoff; ++v ) 4381 { 4382 SCIP_VAR* transvar; 4383 SCIP_Real transval; 4384 SCIP_BOUNDTYPE transbndtype; 4385 SCIP_Real ub; 4386 SCIP_Real lb; 4387 4388 transvar = child->vars[v]; 4389 transval = child->varbounds[v]; 4390 transbndtype = child->varboundtypes[v]; 4391 4392 /* transform into the transformed space */ 4393 SCIP_CALL( SCIPvarGetProbvarBound(&transvar, &transval, &transbndtype) ); 4394 4395 lb = SCIPvarGetLbLocal(transvar); 4396 ub = SCIPvarGetUbLocal(transvar); 4397 4398 /* check for infeasibility */ 4399 if( SCIPsetIsFeasEQ(set, lb, ub) && !SCIPsetIsFeasEQ(set, lb, transval) ) 4400 { 4401 SCIPsetDebugMsg(set, " -> <%s> is fixed to %g, can not change bound to %g -> cutoff\n", 4402 SCIPvarGetName(transvar), lb, transval); 4403 4404 cutoff = TRUE; 4405 break; 4406 } 4407 4408 /* check for redundancy */ 4409 if( SCIPsetIsFeasEQ(set, lb, ub) && SCIPsetIsFeasEQ(set, lb, transval) ) 4410 { 4411 SCIPsetDebugMsg(set, " -> <%s> is already fixed to %g -> redundant bound change\n", 4412 SCIPvarGetName(transvar), lb); 4413 4414 redundantvars[nredundantvars] = v; 4415 ++nredundantvars; 4416 } 4417 } 4418 4419 if( !cutoff && nredundantvars > 0 ) 4420 { 4421 for( int v = 0; v < nredundantvars; ++v ) 4422 { 4423 /* replace the redundant variable by the last stored variable */ 4424 child->vars[redundantvars[v]] = child->vars[child->nvars-1]; 4425 child->varbounds[redundantvars[v]] = child->varbounds[child->nvars-1]; 4426 child->varboundtypes[redundantvars[v]] = child->varboundtypes[child->nvars-1]; 4427 --child->nvars; 4428 } 4429 } 4430 4431 /* free buffer memory */ 4432 SCIPsetFreeBufferArray(set, &redundantvars); 4433 } 4434 else if( child->nconss == 0 ) 4435 { 4436 redundant = TRUE; 4437 SCIPsetDebugMsg(set, " -> redundant node found.\n"); 4438 } 4439 4440 if( cutoff ) 4441 { 4442 cutoffchilds[ncutoffchilds] = childid; 4443 ++ncutoffchilds; 4444 } 4445 else if( redundant ) 4446 { 4447 redchilds[nredchilds] = childid; 4448 ++nredchilds; 4449 } 4450 } 4451 4452 SCIPsetDebugMsg(set, "-> found %d redundant and %d infeasible nodes\n", nredchilds, ncutoffchilds); 4453 4454 /* delete all nodes that can be cut off */ 4455 while( ncutoffchilds > 0 ) 4456 { 4457 /* delete the node and the induced subtree */ 4458 SCIP_CALL( deleteChildrenBelow(reopt->reopttree, set, blkmem, cutoffchilds[ncutoffchilds-1], TRUE, TRUE) ); 4459 4460 /* find the position in the childid array */ 4461 c = 0; 4462 while( reoptnode->childids[c] != cutoffchilds[ncutoffchilds-1] && c < reoptnode->nchilds ) 4463 ++c; 4464 assert(reoptnode->childids[c] == cutoffchilds[ncutoffchilds-1]); 4465 4466 /* replace the ID at position c by the last ID */ 4467 reoptnode->childids[c] = reoptnode->childids[reoptnode->nchilds-1]; 4468 --reoptnode->nchilds; 4469 4470 /* decrease the number of nodes to cutoff */ 4471 --ncutoffchilds; 4472 } 4473 4474 /* replace all redundant nodes their child nodes or cutoff the node if it is a leaf */ 4475 while( nredchilds > 0 ) 4476 { 4477 /* find the position in the childid array */ 4478 c = 0; 4479 while( reoptnode->childids[c] != redchilds[nredchilds-1] && c < reoptnode->nchilds ) 4480 ++c; 4481 assert(reoptnode->childids[c] == redchilds[nredchilds-1]); 4482 4483 /* the node is a leaf and we can cutoff them */ 4484 if( reopt->reopttree->reoptnodes[redchilds[nredchilds-1]]->nchilds == 0 ) 4485 { 4486 /* delete the node and the induced subtree */ 4487 SCIP_CALL( deleteChildrenBelow(reopt->reopttree, set, blkmem, redchilds[nredchilds-1], TRUE, TRUE) ); 4488 4489 /* replace the ID at position c by the last ID */ 4490 reoptnode->childids[c] = reoptnode->childids[reoptnode->nchilds-1]; 4491 --reoptnode->nchilds; 4492 4493 /* decrease the number of redundant nodes */ 4494 --nredchilds; 4495 } 4496 else 4497 { 4498 int ncc; 4499 4500 /* replace the ID at position c by the last ID */ 4501 reoptnode->childids[c] = reoptnode->childids[reoptnode->nchilds-1]; 4502 --reoptnode->nchilds; 4503 4504 ncc = reopt->reopttree->reoptnodes[redchilds[nredchilds-1]]->nchilds; 4505 4506 /* check the memory */ 4507 SCIP_CALL( reoptnodeCheckMemory(reopt->reopttree->reoptnodes[id], set, blkmem, 0, reoptnode->nchilds+ncc, 0) ); 4508 4509 /* add all IDs of child nodes to the current node */ 4510 for( int cc = 0; cc < ncc; ++cc ) 4511 { 4512 reoptnode->childids[reoptnode->nchilds] = reopt->reopttree->reoptnodes[redchilds[nredchilds-1]]->childids[cc]; 4513 ++reoptnode->nchilds; 4514 } 4515 4516 /* delete the redundant node */ 4517 SCIP_CALL( reopttreeDeleteNode(reopt->reopttree, set, blkmem, redchilds[nredchilds-1], TRUE) ); 4518 SCIP_CALL( SCIPqueueInsertUInt(reopt->reopttree->openids, redchilds[nredchilds-1]) ); 4519 4520 /* decrease the number of redundant nodes */ 4521 --nredchilds; 4522 4523 /* update the flag to rerun this method */ 4524 *runagain = TRUE; 4525 } 4526 } 4527 4528 /* free buffer arrays */ 4529 SCIPsetFreeBufferArray(set, &redchilds); 4530 SCIPsetFreeBufferArray(set, &cutoffchilds); 4531 4532 return SCIP_OKAY; 4533 } 4534 4535 /** return the number of all nodes in the subtree induced by the reoptimization node stored at @p id */ 4536 static 4537 int reopttreeGetNNodes( 4538 SCIP_REOPTTREE* reopttree, /**< reopttree */ 4539 unsigned int id /**< id of stored node */ 4540 ) 4541 { 4542 int nnodes = 0; 4543 4544 assert(reopttree != NULL); 4545 assert(id < reopttree->reoptnodessize); 4546 4547 for( int i = 0; i < reopttree->reoptnodes[id]->nchilds; ++i ) 4548 nnodes += reopttreeGetNNodes(reopttree, reopttree->reoptnodes[id]->childids[i]); 4549 4550 return nnodes + 1; 4551 } 4552 4553 /** returns the number of leaf nodes of the induced subtree */ 4554 static 4555 int reoptGetNLeaves( 4556 SCIP_REOPT* reopt, /**< reoptimization data structure */ 4557 unsigned int id /**< id of stored node */ 4558 ) 4559 { 4560 int nleaves = 0; 4561 4562 assert(reopt != NULL); 4563 assert(id < reopt->reopttree->reoptnodessize); 4564 assert(reopt->reopttree->reoptnodes[id] != NULL); 4565 4566 /* iterate over all child nods and check whether they are leaves or not */ 4567 for( int i = 0; i < reopt->reopttree->reoptnodes[id]->nchilds; ++i ) 4568 { 4569 unsigned int childid; 4570 4571 childid = reopt->reopttree->reoptnodes[id]->childids[i]; 4572 assert(childid < reopt->reopttree->reoptnodessize); 4573 4574 if( reopt->reopttree->reoptnodes[childid]->nchilds == 0 ) 4575 ++nleaves; 4576 else 4577 nleaves += reoptGetNLeaves(reopt, childid); 4578 } 4579 4580 return nleaves; 4581 } 4582 4583 /** returns all leaves of the subtree induced by the node stored at @p id*/ 4584 static 4585 SCIP_RETCODE reoptGetLeaves( 4586 SCIP_REOPT* reopt, /**< reoptimization data structure*/ 4587 unsigned int id, /**< id of stored node */ 4588 unsigned int* leaves, /**< array of leave nodes */ 4589 int leavessize, /**< size of leaves array */ 4590 int* nleaves /**< pointer to store the number of leave nodes */ 4591 ) 4592 { 4593 assert(reopt != NULL); 4594 assert(leavessize > 0 && leaves != NULL); 4595 assert((*nleaves) >= 0); 4596 assert(id < reopt->reopttree->reoptnodessize); 4597 assert(reopt->reopttree->reoptnodes[id] != NULL); 4598 4599 for( int i = 0, l = 0; i < reopt->reopttree->reoptnodes[id]->nchilds; ++i ) 4600 { 4601 unsigned int childid; 4602 4603 assert(*nleaves <= leavessize); 4604 4605 childid = reopt->reopttree->reoptnodes[id]->childids[i]; 4606 assert(childid < reopt->reopttree->reoptnodessize); 4607 4608 if( reopt->reopttree->reoptnodes[childid]->nchilds == 0 ) 4609 { 4610 leaves[l] = reopt->reopttree->reoptnodes[id]->childids[i]; 4611 ++l; 4612 ++(*nleaves); 4613 } 4614 else 4615 { 4616 int nleaves2 = 0; 4617 4618 SCIP_CALL( reoptGetLeaves(reopt, childid, &leaves[l], leavessize - l, &nleaves2) ); 4619 l += nleaves2; 4620 (*nleaves) += nleaves2; 4621 } 4622 } 4623 4624 return SCIP_OKAY; 4625 } 4626 4627 /** after restarting the reoptimization and an after compressing the search tree we have to delete all stored information */ 4628 static 4629 SCIP_RETCODE reoptResetTree( 4630 SCIP_REOPT* reopt, /**< reoptimization data structure */ 4631 SCIP_SET* set, /**< global SCIP settings */ 4632 BMS_BLKMEM* blkmem, /**< block memory */ 4633 SCIP_Bool softreset /**< mark the nodes to overwriteable (TRUE) or delete them completely (FALSE) */ 4634 ) 4635 { 4636 assert(reopt != NULL); 4637 assert(set != NULL); 4638 assert(blkmem != NULL); 4639 4640 /* clear the tree */ 4641 SCIP_CALL( clearReoptnodes(reopt->reopttree, set, blkmem, softreset) ); 4642 assert(reopt->reopttree->nreoptnodes == 0); 4643 4644 /* reset the dual constraint */ 4645 if( reopt->dualreds != NULL ) 4646 reopt->dualreds->nvars = 0; 4647 4648 reopt->currentnode = -1; 4649 4650 return SCIP_OKAY; 4651 } 4652 4653 /** restart the reoptimization by removing all stored information about nodes and increase the number of restarts */ 4654 static 4655 SCIP_RETCODE reoptRestart( 4656 SCIP_REOPT* reopt, /**< reoptimization data structure */ 4657 SCIP_SET* set, /**< global SCIP settings */ 4658 BMS_BLKMEM* blkmem /**< block memory */ 4659 ) 4660 { 4661 assert(reopt != NULL); 4662 assert(reopt->reopttree != NULL); 4663 assert(set != NULL); 4664 assert(blkmem != NULL); 4665 4666 /* clear the tree */ 4667 SCIP_CALL( reoptResetTree(reopt, set, blkmem, FALSE) ); 4668 assert(reopt->reopttree->nreoptnodes == 0); 4669 4670 /* allocate memory for the root node */ 4671 SCIP_CALL( createReoptnode(reopt->reopttree, set, blkmem, 0) ); 4672 4673 reopt->nglbrestarts += 1; 4674 4675 if( reopt->firstrestart == -1 ) 4676 reopt->firstrestart = reopt->run; 4677 4678 reopt->lastrestart = reopt->run; 4679 4680 return SCIP_OKAY; 4681 } 4682 4683 /** save the new objective function */ 4684 static 4685 SCIP_RETCODE reoptSaveNewObj( 4686 SCIP_REOPT* reopt, /**< reoptimization data */ 4687 SCIP_SET* set, /**< global SCIP settings */ 4688 BMS_BLKMEM* blkmem, /**< block memory */ 4689 SCIP_VAR** origvars, /**< original problem variables */ 4690 int norigvars /**< number of original problem variables */ 4691 ) 4692 { 4693 int probidx; 4694 4695 assert(reopt != NULL); 4696 assert(set != NULL); 4697 assert(blkmem != NULL); 4698 assert(origvars != NULL); 4699 assert(norigvars >= 0); 4700 4701 /* check memory */ 4702 SCIP_CALL( ensureRunSize(reopt, set, reopt->run, blkmem) ); 4703 4704 /* get memory and check whether we have to resize all previous objectives */ 4705 if( reopt->nobjvars < norigvars ) 4706 { 4707 for( int i = 0; i < reopt->run-1; ++i ) 4708 { 4709 SCIP_ALLOC( BMSreallocMemoryArray(&reopt->objs[i], norigvars) ); /*lint !e866*/ 4710 for( int v = reopt->nobjvars-1; v < norigvars; ++v ) 4711 reopt->objs[i][v] = 0.0; 4712 } 4713 reopt->nobjvars = norigvars; 4714 } 4715 SCIP_ALLOC( BMSallocClearMemoryArray(&reopt->objs[reopt->run-1], reopt->nobjvars) ); /*lint !e866*/ 4716 4717 /* save coefficients */ 4718 for( int v = 0; v < norigvars; ++v ) 4719 { 4720 assert(SCIPvarIsOriginal(origvars[v])); 4721 4722 probidx = SCIPvarGetIndex(origvars[v]); 4723 4724 /* it can happen that the index is greater than the number of problem variables, 4725 * i.e., not all created variables were added 4726 */ 4727 if( probidx >= reopt->nobjvars ) 4728 { 4729 int newsize = SCIPsetCalcMemGrowSize(set, probidx+1); 4730 for( int i = 0; i < reopt->run; ++i ) 4731 { 4732 SCIP_ALLOC( BMSreallocMemoryArray(&reopt->objs[i], newsize) ); /*lint !e866*/ 4733 for( int j = reopt->nobjvars; j < newsize; ++j ) 4734 reopt->objs[i][j] = 0.0; 4735 } 4736 reopt->nobjvars = newsize; 4737 } 4738 assert(0 <= probidx && probidx < reopt->nobjvars); 4739 4740 reopt->objs[reopt->run-1][probidx] = SCIPvarGetObj(origvars[v]); 4741 4742 /* update flag to remember if the objective function has changed */ 4743 if( !reopt->objhaschanged && reopt->run >= 2 4744 && ! SCIPsetIsEQ(set, reopt->objs[reopt->run-2][probidx], reopt->objs[reopt->run-1][probidx]) ) 4745 reopt->objhaschanged = TRUE; 4746 4747 /* mark this objective as the first non empty */ 4748 if( reopt->firstobj == -1 && reopt->objs[reopt->run-1][probidx] != 0 ) 4749 reopt->firstobj = reopt->run-1; 4750 } 4751 4752 /* calculate similarity to last objective */ 4753 if( reopt->run-1 >= 1 ) 4754 { 4755 /* calculate similarity to last objective */ 4756 reopt->simtolastobj = reoptSimilarity(reopt, set, reopt->run-1, reopt->run-2, origvars, norigvars); 4757 4758 if( reopt->simtolastobj == SCIP_INVALID ) /*lint !e777*/ 4759 return SCIP_INVALIDRESULT; 4760 4761 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_HIGH, NULL, "new objective has similarity of %g compared to previous.\n", 4762 reopt->simtolastobj); 4763 } 4764 4765 SCIPsetDebugMsg(set, "saved obj for run %d.\n", reopt->run); 4766 4767 return SCIP_OKAY; 4768 } 4769 4770 /** orders the variable by inference score */ 4771 static 4772 SCIP_RETCODE getInferenceOrder( 4773 SCIP_SET* set, /**< global SCIP settings */ 4774 SCIP_STAT* stat, /**< dynamic problem statistics */ 4775 int* perm, /**< array of indices that need to be permuted */ 4776 SCIP_VAR** vars, /**< variable array to permute */ 4777 SCIP_Real* bounds, /**< bound array to permute in the same order */ 4778 SCIP_BOUNDTYPE* boundtypes, /**< boundtype array to permute in the same order */ 4779 int nvars /**< number of variables */ 4780 ) 4781 { 4782 SCIP_Real* infscore; 4783 4784 assert(set != NULL); 4785 assert(perm != NULL); 4786 assert(vars != NULL); 4787 assert(bounds != NULL); 4788 assert(boundtypes != NULL); 4789 assert(nvars >= 0); 4790 4791 /* allocate buffer for the scores */ 4792 SCIP_CALL( SCIPsetAllocBufferArray(set, &infscore, nvars) ); 4793 4794 for( int v = 0; v < nvars; ++v ) 4795 { 4796 if( boundtypes[v] == SCIP_BOUNDTYPE_UPPER ) 4797 { 4798 infscore[v] = 0.75 * SCIPvarGetAvgInferences(vars[v], stat, SCIP_BRANCHDIR_UPWARDS) 4799 + 0.25 * SCIPvarGetAvgInferences(vars[v], stat, SCIP_BRANCHDIR_DOWNWARDS); 4800 } 4801 else 4802 { 4803 infscore[v] = 0.25 * SCIPvarGetAvgInferences(vars[v], stat, SCIP_BRANCHDIR_UPWARDS) 4804 + 0.75 * SCIPvarGetAvgInferences(vars[v], stat, SCIP_BRANCHDIR_DOWNWARDS); 4805 } 4806 } 4807 4808 /* permute indices by inference score */ 4809 SCIPsortDownRealInt(infscore, perm, nvars); 4810 4811 /* free buffer */ 4812 SCIPsetFreeBufferArray(set, &infscore); 4813 4814 return SCIP_OKAY; 4815 } 4816 4817 /** create a global constraint to separate the given solution */ 4818 static 4819 SCIP_RETCODE separateSolution( 4820 SCIP_REOPT* reopt, /**< reoptimization data structure */ 4821 BMS_BLKMEM* blkmem, /**< block memory */ 4822 SCIP_SET* set, /**< global SCIP settings */ 4823 SCIP_STAT* stat, /**< dynamic SCIP statistics */ 4824 SCIP_SOL* sol, /**< solution to separate */ 4825 SCIP_VAR** vars, /**< array of original problem variables */ 4826 int nvars /**< number of original problem variables */ 4827 ) 4828 { 4829 SCIP_VAR** origvars; 4830 SCIP_Real* vals; 4831 int nintvars; 4832 int nbinvars; 4833 int w; 4834 4835 assert(reopt != NULL); 4836 assert(sol != NULL); 4837 assert(blkmem != NULL); 4838 assert(set != NULL); 4839 assert(stat != NULL); 4840 assert(vars != NULL); 4841 assert(nvars != 0); 4842 assert(SCIPsolIsOriginal(sol)); 4843 4844 /* allocate buffer memory */ 4845 SCIP_CALL( SCIPsetAllocBufferArray(set, &origvars, nvars) ); 4846 SCIP_CALL( SCIPsetAllocBufferArray(set, &vals, nvars) ); 4847 4848 nbinvars = 0; 4849 nintvars = 0; 4850 w = 0; 4851 4852 /* get the solution values of the variables */ 4853 for( int v = 0; v < nvars; ++v ) 4854 { 4855 assert(SCIPvarIsOriginal(vars[v])); 4856 assert(nbinvars + nintvars == w); 4857 4858 /* we do not want to create cuts for continous variables */ 4859 if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ) 4860 continue; 4861 4862 if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY ) 4863 ++nbinvars; 4864 if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vars[v]) == SCIP_VARTYPE_IMPLINT ) 4865 ++nintvars; 4866 4867 origvars[v] = vars[v]; 4868 assert(origvars[v] != NULL); 4869 assert(SCIPvarIsOriginal(origvars[v])); 4870 4871 vals[w] = SCIPsolGetVal(sol, set, stat, origvars[v]); 4872 ++w; 4873 } 4874 4875 SCIP_CALL( addGlobalCut(reopt, blkmem, set, origvars, vals, NULL, w, nbinvars, nintvars) ); 4876 4877 /* free buffer memory */ 4878 SCIPsetFreeBufferArray(set, &vals); 4879 SCIPsetFreeBufferArray(set, &origvars); 4880 4881 return SCIP_OKAY; 4882 } 4883 4884 /* 4885 * public methods 4886 */ 4887 4888 /* ---------------- methods of general reoptimization ---------------- */ 4889 4890 /* In debug mode, the following methods are implemented as function calls to ensure 4891 * type validity. 4892 * In optimized mode, the methods are implemented as defines to improve performance. 4893 * However, we want to have them in the library anyways, so we have to undef the defines. 4894 */ 4895 4896 #undef SCIPreoptGetNRestartsGlobal 4897 #undef SCIPreoptGetNRestartsLocal 4898 #undef SCIPreoptGetNTotalRestartsLocal 4899 #undef SCIPreoptGetFirstRestarts 4900 #undef SCIPreoptGetLastRestarts 4901 #undef SCIPreoptGetNFeasNodes 4902 #undef SCIPreoptGetNTotalFeasNodes 4903 #undef SCIPreoptGetNPrunedNodes 4904 #undef SCIPreoptGetNTotalPrunedNodes 4905 #undef SCIPreoptGetNCutoffReoptnodes 4906 #undef SCIPreoptGetNTotalCutoffReoptnodes 4907 #undef SCIPreoptGetNInfNodes 4908 #undef SCIPreoptGetNTotalInfNodes 4909 #undef SCIPreoptGetNInfSubtrees 4910 4911 4912 /** returns the number of global restarts */ 4913 int SCIPreoptGetNRestartsGlobal( 4914 SCIP_REOPT* reopt /**< reoptimization data structure */ 4915 ) 4916 { 4917 assert(reopt != NULL); 4918 4919 return reopt->nglbrestarts; 4920 } 4921 4922 /** returns the number of local restarts in the current run */ 4923 int SCIPreoptGetNRestartsLocal( 4924 SCIP_REOPT* reopt /**< reoptimization data structure */ 4925 ) 4926 { 4927 assert(reopt != NULL); 4928 4929 return reopt->nlocrestarts; 4930 } 4931 4932 /** returns the number of local restarts over all runs */ 4933 int SCIPreoptGetNTotalRestartsLocal( 4934 SCIP_REOPT* reopt /**< reoptimization data structure */ 4935 ) 4936 { 4937 assert(reopt != NULL); 4938 4939 return reopt->ntotallocrestarts; 4940 } 4941 4942 /** returns the number of iteration with the first global restarts */ 4943 int SCIPreoptGetFirstRestarts( 4944 SCIP_REOPT* reopt /**< reoptimization data structure */ 4945 ) 4946 { 4947 assert(reopt != NULL); 4948 4949 return reopt->firstrestart; 4950 } 4951 4952 /** returns the number of iteration with the last global restarts */ 4953 int SCIPreoptGetLastRestarts( 4954 SCIP_REOPT* reopt /**< reoptimization data structure */ 4955 ) 4956 { 4957 assert(reopt != NULL); 4958 4959 return reopt->lastrestart; 4960 } 4961 4962 /** returns the number of stored nodes providing an improving feasible LP solution in the current run */ 4963 int SCIPreoptGetNFeasNodes( 4964 SCIP_REOPT* reopt /**< reoptimization data structure */ 4965 ) 4966 { 4967 assert(reopt != NULL); 4968 4969 return reopt->reopttree->nfeasnodes; 4970 } 4971 4972 /** returns the number of stored nodes providing an improving feasible LP solution over all runs */ 4973 int SCIPreoptGetNTotalFeasNodes( 4974 SCIP_REOPT* reopt /**< reoptimization data structure */ 4975 ) 4976 { 4977 assert(reopt != NULL); 4978 4979 return reopt->reopttree->ntotalfeasnodes; 4980 } 4981 4982 /** returns the number of stored nodes that exceeded the cutoff bound in the current run */ 4983 int SCIPreoptGetNPrunedNodes( 4984 SCIP_REOPT* reopt /**< reoptimization data structure */ 4985 ) 4986 { 4987 assert(reopt != NULL); 4988 4989 return reopt->reopttree->nprunednodes; 4990 } 4991 4992 /** returns the number of stored nodes that exceeded the cutoff bound over all runs */ 4993 int SCIPreoptGetNTotalPrunedNodes( 4994 SCIP_REOPT* reopt /**< reoptimization data structure */ 4995 ) 4996 { 4997 assert(reopt != NULL); 4998 4999 return reopt->reopttree->ntotalprunednodes; 5000 } 5001 5002 /** rerturns the number of reoptimized nodes that were cutoff in the same iteration in the current run */ 5003 int SCIPreoptGetNCutoffReoptnodes( 5004 SCIP_REOPT* reopt /**< reoptimization data structure */ 5005 ) 5006 { 5007 assert(reopt != NULL); 5008 5009 return reopt->reopttree->ncutoffreoptnodes; 5010 } 5011 5012 /** rerturns the number of reoptimized nodes that were cutoff in the same iteration over all runs */ 5013 int SCIPreoptGetNTotalCutoffReoptnodes( 5014 SCIP_REOPT* reopt /**< reoptimization data structure */ 5015 ) 5016 { 5017 assert(reopt != NULL); 5018 5019 return reopt->reopttree->ntotalcutoffreoptnodes; 5020 } 5021 5022 /** returns the number of stored nodes with an infeasible LP in the current run */ 5023 int SCIPreoptGetNInfNodes( 5024 SCIP_REOPT* reopt /**< reoptimization data structure */ 5025 ) 5026 { 5027 assert(reopt != NULL); 5028 5029 return reopt->reopttree->ninfnodes; 5030 } 5031 5032 /** returns the number of stored nodes with an infeasible LP over all runs */ 5033 int SCIPreoptGetNTotalInfNodes( 5034 SCIP_REOPT* reopt /**< reoptimization data structure */ 5035 ) 5036 { 5037 assert(reopt != NULL); 5038 5039 return reopt->reopttree->ntotalinfnodes; 5040 } 5041 5042 /** constructor for the reoptimization data */ 5043 SCIP_RETCODE SCIPreoptCreate( 5044 SCIP_REOPT** reopt, /**< pointer to reoptimization data structure */ 5045 SCIP_SET* set, /**< global SCIP settings */ 5046 BMS_BLKMEM* blkmem /**< block memory */ 5047 ) 5048 { 5049 SCIP_EVENTHDLR* eventhdlr; 5050 5051 assert(reopt != NULL); 5052 5053 SCIP_ALLOC( BMSallocMemory(reopt) ); 5054 (*reopt)->runsize = DEFAULT_MEM_RUN; 5055 (*reopt)->run = 0; 5056 (*reopt)->simtolastobj = -2.0; 5057 (*reopt)->simtofirstobj = -2.0; 5058 (*reopt)->firstobj = -1; 5059 (*reopt)->currentnode = -1; 5060 (*reopt)->lastbranched = -1; 5061 (*reopt)->dualreds = NULL; 5062 (*reopt)->glbconss = NULL; 5063 (*reopt)->nglbconss = 0; 5064 (*reopt)->allocmemglbconss = 0; 5065 (*reopt)->ncheckedsols = 0; 5066 (*reopt)->nimprovingsols = 0; 5067 (*reopt)->noptsolsbyreoptsol = 0; 5068 (*reopt)->nglbrestarts = 0; 5069 (*reopt)->nlocrestarts = 0; 5070 (*reopt)->ntotallocrestarts = 0; 5071 (*reopt)->firstrestart = -1; 5072 (*reopt)->lastrestart = 0; 5073 (*reopt)->nobjvars = 0; 5074 (*reopt)->objhaschanged = FALSE; 5075 (*reopt)->consadded = FALSE; 5076 (*reopt)->addedconss = NULL; 5077 (*reopt)->naddedconss = 0; 5078 (*reopt)->addedconsssize = 0; 5079 (*reopt)->glblb = NULL; 5080 (*reopt)->glbub = NULL; 5081 (*reopt)->nactiveconss = 0; 5082 (*reopt)->nmaxactiveconss = 0; 5083 (*reopt)->activeconss = NULL; 5084 (*reopt)->activeconssset = NULL; 5085 5086 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*reopt)->varhistory, (*reopt)->runsize) ); 5087 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*reopt)->prevbestsols, (*reopt)->runsize) ); 5088 SCIP_ALLOC( BMSallocMemoryArray(&(*reopt)->objs, (*reopt)->runsize) ); 5089 5090 for( int i = 0; i < (*reopt)->runsize; ++i ) 5091 { 5092 (*reopt)->objs[i] = NULL; 5093 (*reopt)->prevbestsols[i] = NULL; 5094 (*reopt)->varhistory[i] = NULL; 5095 } 5096 5097 /* clocks */ 5098 SCIP_CALL( SCIPclockCreate(&(*reopt)->savingtime, SCIP_CLOCKTYPE_DEFAULT) ); 5099 5100 /* create and initialize SCIP_SOLTREE */ 5101 SCIP_ALLOC( BMSallocMemory(&(*reopt)->soltree) ); 5102 SCIP_CALL( createSolTree((*reopt)->soltree, blkmem) ); 5103 5104 /* create and initialize SCIP_REOPTTREE */ 5105 SCIP_ALLOC( BMSallocMemory(&(*reopt)->reopttree) ); 5106 SCIP_CALL( createReopttree((*reopt)->reopttree, set, blkmem) ); 5107 5108 /* create a random number generator */ 5109 SCIP_CALL( SCIPrandomCreate(&(*reopt)->randnumgen, blkmem, (unsigned int)SCIPsetInitializeRandomSeed(set, DEFAULT_RANDSEED)) ); 5110 5111 /* create event handler for node events */ 5112 eventhdlr = NULL; 5113 5114 /* include event handler into SCIP */ 5115 SCIP_CALL( SCIPeventhdlrCreate(&eventhdlr, set, EVENTHDLR_NAME, EVENTHDLR_DESC, NULL, NULL, NULL, NULL, 5116 eventInitsolReopt, eventExitsolReopt, NULL, eventExecReopt, NULL) ); 5117 SCIP_CALL( SCIPsetIncludeEventhdlr(set, eventhdlr) ); 5118 assert(eventhdlr != NULL); 5119 5120 return SCIP_OKAY; 5121 } 5122 5123 /* release all variables and constraints captured during reoptimization */ 5124 SCIP_RETCODE SCIPreoptReleaseData( 5125 SCIP_REOPT* reopt, /**< pointer to reoptimization data structure */ 5126 SCIP_SET* set, /**< global SCIP settings */ 5127 BMS_BLKMEM* blkmem /**< block memory */ 5128 ) 5129 { 5130 /* release all added constraints and free the data */ 5131 if( reopt->addedconss != NULL ) 5132 { 5133 for( int c = 0; c < reopt->naddedconss; ++c ) 5134 { 5135 assert(reopt->addedconss[c] != NULL); 5136 5137 SCIP_CALL( SCIPconsRelease(&reopt->addedconss[c], blkmem, set) ); 5138 } 5139 5140 BMSfreeBlockMemoryArray(blkmem, &reopt->addedconss, reopt->addedconsssize); 5141 reopt->naddedconss = 0; 5142 reopt->addedconsssize = 0; 5143 } 5144 5145 SCIP_CALL( cleanActiveConss(reopt, set, blkmem) ); 5146 5147 return SCIP_OKAY; 5148 } 5149 5150 /** frees reoptimization data */ 5151 SCIP_RETCODE SCIPreoptFree( 5152 SCIP_REOPT** reopt, /**< reoptimization data structure */ 5153 SCIP_SET* set, /**< global SCIP settings */ 5154 SCIP_PRIMAL* origprimal, /**< original primal */ 5155 BMS_BLKMEM* blkmem /**< block memory */ 5156 ) 5157 { 5158 assert(reopt != NULL); 5159 assert(*reopt != NULL); 5160 assert(set != NULL); 5161 assert(origprimal != NULL || set->stage == SCIP_STAGE_INIT); 5162 assert(blkmem != NULL); 5163 5164 /* free random number generator */ 5165 SCIPrandomFree(&(*reopt)->randnumgen, blkmem); 5166 5167 /* free reopttree */ 5168 SCIP_CALL( freeReoptTree((*reopt)->reopttree, set, blkmem) ); 5169 5170 /* free solutions and variable histories */ 5171 if( set->stage >= SCIP_STAGE_PROBLEM ) 5172 { 5173 for( int p = (*reopt)->run-1; p >= 0; --p ) 5174 { 5175 if( (*reopt)->soltree->sols[p] != NULL ) 5176 { 5177 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->soltree->sols[p], (*reopt)->soltree->solssize[p]); /*lint !e866*/ 5178 (*reopt)->soltree->sols[p] = NULL; 5179 } 5180 5181 if( set->reopt_storevarhistory && (*reopt)->varhistory[p] != NULL ) 5182 { 5183 for( int v = SCIPgetNOrigVars(set->scip)-1; v >= 0; --v ) 5184 { 5185 SCIPhistoryFree(&(*reopt)->varhistory[p][v], blkmem); 5186 } 5187 5188 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->varhistory[p], SCIPgetNOrigVars(set->scip)); 5189 (*reopt)->varhistory[p] = NULL; 5190 } 5191 5192 /* we have to free all optimal solution separatly, because those solutions are not stored in the 5193 * solution reopt_sepabestsol = TRUE 5194 */ 5195 if( set->reopt_sepabestsol && (*reopt)->prevbestsols[p] != NULL ) 5196 { 5197 SCIP_CALL( SCIPsolFree(&(*reopt)->prevbestsols[p], blkmem, origprimal) ); 5198 } 5199 5200 if( (*reopt)->objs[p] != NULL ) 5201 { 5202 BMSfreeMemoryArray(&(*reopt)->objs[p]); 5203 } 5204 } 5205 } 5206 5207 /* free solution tree */ 5208 SCIP_CALL( freeSolTree((*reopt), set, origprimal, blkmem) ); 5209 5210 if( (*reopt)->dualreds != NULL ) 5211 { 5212 if( (*reopt)->dualreds->varssize > 0 ) 5213 { 5214 assert(!(*reopt)->dualreds->linear); 5215 5216 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->dualreds->boundtypes, (*reopt)->dualreds->varssize); 5217 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->dualreds->vals, (*reopt)->dualreds->varssize); 5218 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->dualreds->vars, (*reopt)->dualreds->varssize); 5219 BMSfreeBlockMemory(blkmem, &(*reopt)->dualreds); 5220 (*reopt)->dualreds = NULL; 5221 } 5222 } 5223 5224 if( (*reopt)->glbconss != NULL && (*reopt)->allocmemglbconss > 0 ) 5225 { 5226 /* free all constraint */ 5227 for( int c = 0; c < (*reopt)->allocmemglbconss; ++c ) 5228 { 5229 if( (*reopt)->glbconss[c] != NULL ) 5230 { 5231 if( (*reopt)->glbconss[c]->varssize > 0 ) 5232 { 5233 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->glbconss[c]->boundtypes, (*reopt)->glbconss[c]->varssize); 5234 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->glbconss[c]->vals, (*reopt)->glbconss[c]->varssize); 5235 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->glbconss[c]->vars, (*reopt)->glbconss[c]->varssize); 5236 (*reopt)->glbconss[c]->varssize = 0; 5237 } 5238 BMSfreeBlockMemory(blkmem, &(*reopt)->glbconss[c]); /*lint !e866*/ 5239 --(*reopt)->nglbconss; 5240 } 5241 } 5242 assert((*reopt)->nglbconss == 0); 5243 5244 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->glbconss, (*reopt)->allocmemglbconss); 5245 (*reopt)->allocmemglbconss = 0; 5246 } 5247 5248 /* clocks */ 5249 SCIPclockFree(&(*reopt)->savingtime); 5250 5251 /* the hashmap need not to be exist, e.g., if the problem was solved during presolving */ 5252 if( (*reopt)->activeconssset != NULL ) 5253 { 5254 SCIPhashsetFree(&(*reopt)->activeconssset, blkmem); 5255 } 5256 BMSfreeBlockMemoryArrayNull(blkmem, &(*reopt)->activeconss, (*reopt)->nmaxactiveconss); 5257 5258 if( (*reopt)->glblb != NULL ) 5259 { 5260 SCIPhashmapFree(&(*reopt)->glblb); 5261 SCIPhashmapFree(&(*reopt)->glbub); 5262 (*reopt)->glblb = NULL; 5263 (*reopt)->glbub = NULL; 5264 } 5265 else 5266 assert((*reopt)->glbub == NULL); 5267 5268 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->varhistory, (*reopt)->runsize); 5269 BMSfreeBlockMemoryArray(blkmem, &(*reopt)->prevbestsols, (*reopt)->runsize); 5270 BMSfreeMemoryArray(&(*reopt)->objs); 5271 BMSfreeMemory(reopt); 5272 5273 return SCIP_OKAY; 5274 } 5275 5276 /** returns the number of constraints added by the reoptimization plug-in */ 5277 int SCIPreoptGetNAddedConss( 5278 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5279 SCIP_NODE* node /**< node of the search tree */ 5280 ) 5281 { 5282 unsigned int id; 5283 5284 assert(reopt != NULL); 5285 assert(node != NULL); 5286 5287 id = SCIPnodeGetReoptID(node); 5288 assert(id < reopt->reopttree->reoptnodessize); 5289 5290 /* set the id to -1 if the node is not part of the reoptimization tree */ 5291 if( SCIPnodeGetDepth(node) > 0 && id == 0 ) 5292 return SCIPnodeGetNAddedConss(node); 5293 5294 if( id >= 1 && reopt->reopttree->reoptnodes[id]->nconss > 0 ) 5295 return MAX(SCIPnodeGetNAddedConss(node), reopt->reopttree->reoptnodes[id]->nconss); /*lint !e666*/ 5296 else 5297 return SCIPnodeGetNAddedConss(node); 5298 } 5299 5300 /** add a solution to the solution tree */ 5301 SCIP_RETCODE SCIPreoptAddSol( 5302 SCIP_REOPT* reopt, /**< reoptimization data */ 5303 SCIP_SET* set, /**< global SCIP settings */ 5304 SCIP_STAT* stat, /**< dynamic problem statistics */ 5305 SCIP_PRIMAL* origprimal, /**< original primal */ 5306 BMS_BLKMEM* blkmem, /**< block memory */ 5307 SCIP_SOL* sol, /**< solution to add */ 5308 SCIP_Bool bestsol, /**< is the current solution an optimal solution? */ 5309 SCIP_Bool* added, /**< pointer to store the information if the soltion was added */ 5310 SCIP_VAR** vars, /**< variable array */ 5311 int nvars, /**< number of variables */ 5312 int run /**< number of the current run (1,2,...) */ 5313 ) 5314 { 5315 SCIP_SOLNODE* solnode = NULL; 5316 SCIP_HEUR* heur; 5317 int insertpos; 5318 5319 assert(reopt != NULL); 5320 assert(set != NULL); 5321 assert(sol != NULL); 5322 assert(run > 0); 5323 5324 assert(reopt->soltree->sols[run-1] != NULL); 5325 5326 /* if the solution was found by reoptsols the solutions is already stored */ 5327 heur = SCIPsolGetHeur(sol); 5328 if( heur != NULL && strcmp(SCIPheurGetName(heur), "reoptsols") == 0 && bestsol ) 5329 ++reopt->noptsolsbyreoptsol; 5330 else if( bestsol ) 5331 reopt->noptsolsbyreoptsol = 0; 5332 5333 /* check memory */ 5334 SCIP_CALL( ensureSolsSize(reopt, set, blkmem, reopt->soltree->nsols[run-1]+1, run-1) ); 5335 5336 /* add solution to solution tree */ 5337 SCIP_CALL( soltreeAddSol(reopt, set, stat, origprimal, blkmem, vars, sol, &solnode, nvars, bestsol, added) ); 5338 5339 if( (*added) ) 5340 { 5341 assert(solnode != NULL); 5342 5343 /* add solution */ 5344 insertpos = reopt->soltree->nsols[run-1]; 5345 reopt->soltree->sols[run-1][insertpos] = solnode; 5346 ++reopt->soltree->nsols[run-1]; 5347 assert(reopt->soltree->nsols[run-1] <= set->reopt_savesols); 5348 } 5349 5350 return SCIP_OKAY; 5351 } 5352 5353 /** we want to store the optimal solution of each run in a separate array */ 5354 SCIP_RETCODE SCIPreoptAddOptSol( 5355 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5356 SCIP_SOL* sol, /**< solution to add */ 5357 BMS_BLKMEM* blkmem, /**< block memory */ 5358 SCIP_SET* set, /**< global SCIP settings */ 5359 SCIP_STAT* stat, /**< dynamic problem statistics */ 5360 SCIP_PRIMAL* origprimal, /**< original primal */ 5361 SCIP_VAR** vars, /**< original problem variables */ 5362 int nvars /**< number of original problem variables */ 5363 ) 5364 { 5365 /* cppcheck-suppress unassignedVariable */ 5366 SCIP_SOL* solcopy; 5367 5368 assert(reopt != NULL); 5369 assert(reopt->run-1 >= 0); 5370 assert(sol != NULL); 5371 assert(blkmem != NULL); 5372 assert(set != NULL); 5373 assert(stat != NULL); 5374 assert(origprimal != NULL); 5375 5376 SCIP_CALL( SCIPsolCopy(&solcopy, blkmem, set, stat, origprimal, sol) ); 5377 reopt->prevbestsols[reopt->run-1] = solcopy; 5378 5379 /* store a global constraint that cutsoff the solution */ 5380 if( set->reopt_sepabestsol ) 5381 { 5382 SCIP_CALL( separateSolution(reopt, blkmem, set, stat, sol, vars, nvars) ); 5383 } 5384 5385 return SCIP_OKAY; 5386 } 5387 5388 /** add a new iteration after changing the objective function */ 5389 SCIP_RETCODE SCIPreoptAddRun( 5390 SCIP_REOPT* reopt, /**< reoptimization data sturcture */ 5391 SCIP_SET* set, /**< global SCIP settings */ 5392 BMS_BLKMEM* blkmem, /**< block memory */ 5393 SCIP_VAR** origvars, /**< original problem variables */ 5394 int norigvars, /**< number of original variables */ 5395 int size /**< number of expected solutions */ 5396 ) 5397 { 5398 assert(reopt != NULL); 5399 assert(set != NULL); 5400 assert(blkmem != NULL); 5401 assert(origvars != NULL); 5402 5403 /* increase number of runs */ 5404 ++reopt->run; 5405 5406 /* check memory */ 5407 SCIP_CALL( ensureRunSize(reopt, set, reopt->run, blkmem) ); 5408 5409 /* allocate memory */ 5410 reopt->soltree->solssize[reopt->run-1] = size; 5411 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reopt->soltree->sols[reopt->run-1], size) ); /*lint !e866*/ 5412 5413 /* reset flag */ 5414 reopt->objhaschanged = FALSE; 5415 5416 /* save the objective function */ 5417 SCIP_CALL( reoptSaveNewObj(reopt, set, blkmem, origvars, norigvars) ); 5418 5419 resetStats(reopt); 5420 5421 return SCIP_OKAY; 5422 } 5423 5424 /** get the number of checked solutions during the reoptimization process */ 5425 int SCIPreoptGetNCheckedSols( 5426 SCIP_REOPT* reopt /**< reoptimization data structure */ 5427 ) 5428 { 5429 assert(reopt != NULL); 5430 5431 return reopt->ncheckedsols; 5432 } 5433 5434 /** update the number of checked solutions during the reoptimization process */ 5435 void SCIPreoptAddNCheckedSols( 5436 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5437 int ncheckedsols /**< number of updated solutions */ 5438 ) 5439 { 5440 assert(reopt != NULL); 5441 5442 reopt->ncheckedsols += ncheckedsols; 5443 } 5444 5445 /** get the number of checked solutions during the reoptimization process */ 5446 int SCIPreoptGetNImprovingSols( 5447 SCIP_REOPT* reopt /**< reoptimization data structure */ 5448 ) 5449 { 5450 assert(reopt != NULL); 5451 5452 return reopt->nimprovingsols; 5453 } 5454 5455 /** update the number of checked solutions during the reoptimization process */ 5456 void SCIPreoptAddNImprovingSols( 5457 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5458 int nimprovingsols /**< number of improving solutions */ 5459 ) 5460 { 5461 assert(reopt != NULL); 5462 5463 reopt->nimprovingsols += nimprovingsols; 5464 } 5465 5466 /** returns number of solutions stored in the solution tree of a given run */ 5467 int SCIPreoptGetNSolsRun( 5468 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5469 int run /**< number of the run (1,2,..) */ 5470 ) 5471 { 5472 assert(reopt != NULL); 5473 assert(0 < run && run <= reopt->runsize); 5474 5475 if( reopt->soltree->sols[run-1] == NULL ) 5476 return 0; 5477 else 5478 return reopt->soltree->nsols[run-1]; 5479 } 5480 5481 /** returns number of all solutions of all runs */ 5482 int SCIPreoptGetNSols( 5483 SCIP_REOPT* reopt /**< reoptimization data structure */ 5484 ) 5485 { 5486 int nsols = 0; 5487 5488 assert(reopt != NULL); 5489 5490 for( int r = 0; r < reopt->run; ++r ) 5491 nsols += reopt->soltree->nsols[r]; 5492 5493 return nsols; 5494 } 5495 5496 /** return the stored solutions of a given run */ 5497 SCIP_RETCODE SCIPreoptGetSolsRun( 5498 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5499 int run, /**< number of the run (1,2,...) */ 5500 SCIP_SOL** sols, /**< array of solutions to fill */ 5501 int solssize, /**< length of the array */ 5502 int* nsols /**< pointer to store the number of added solutions */ 5503 ) 5504 { 5505 assert(reopt != NULL); 5506 assert(run > 0 && run <= reopt->run); 5507 assert(sols != NULL); 5508 5509 assert(solssize > 0); 5510 assert(nsols != NULL); 5511 *nsols = 0; 5512 5513 for( int s = 0; s < reopt->soltree->nsols[run-1]; ++s ) 5514 { 5515 if( !reopt->soltree->sols[run-1][s]->updated ) 5516 ++(*nsols); 5517 } 5518 5519 if( solssize < (*nsols) ) 5520 return SCIP_OKAY; 5521 5522 (*nsols) = 0; 5523 for( int s = 0; s < reopt->soltree->nsols[run-1]; ++s ) 5524 { 5525 if( !reopt->soltree->sols[run-1][s]->updated ) 5526 { 5527 sols[*nsols] = reopt->soltree->sols[run-1][s]->sol; 5528 reopt->soltree->sols[run-1][s]->updated = TRUE; 5529 ++(*nsols); 5530 } 5531 } 5532 5533 return SCIP_OKAY; 5534 } 5535 5536 /** returns the number of saved solutions overall runs */ 5537 int SCIPreoptGetNSavedSols( 5538 SCIP_REOPT* reopt /**< reoptimization data structure */ 5539 ) 5540 { 5541 int nsavedsols = 0; 5542 5543 assert(reopt != NULL); 5544 assert(reopt->soltree->root != NULL); 5545 5546 if( reopt->soltree->root->child != NULL ) 5547 nsavedsols = soltreeNInducedSols(reopt->soltree->root); 5548 5549 return nsavedsols; 5550 } 5551 5552 /** check if the reoptimization process should be (locally) restarted. 5553 * 5554 * First, we check whether the current node is the root node, e.g., node == NULL. in this case, we do not need to calculate 5555 * the similarity again. we trigger a restart if 5556 * 1. the objective function has changed too much 5557 * 2. the number of stored nodes is exceeded 5558 * 3. the last n optimal solutions were found by heur_reoptsols (in this case, the stored tree was only needed to 5559 * prove the optimality and this can be probably faster by solving from scratch) 5560 * 5561 * If the current node is different to the root node we calculate the local similarity, i.e., exclude all variable 5562 * that are already fixed by bounding. 5563 */ 5564 SCIP_RETCODE SCIPreoptCheckRestart( 5565 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5566 SCIP_SET* set, /**< global SCIP settings */ 5567 BMS_BLKMEM* blkmem, /**< block memory */ 5568 SCIP_NODE* node, /**< current node of the branch and bound tree (or NULL) */ 5569 SCIP_VAR** transvars, /**< transformed problem variables */ 5570 int ntransvars, /**< number of transformed problem variables */ 5571 SCIP_Bool* restart /**< pointer to store if the reoptimization process should be restarted */ 5572 ) 5573 { 5574 SCIP_Real sim = 1.0; 5575 5576 assert(reopt != NULL); 5577 assert(set != NULL); 5578 assert(blkmem != NULL); 5579 assert(transvars != NULL); 5580 assert(ntransvars >= 0); 5581 assert(restart != NULL); 5582 5583 *restart = FALSE; 5584 5585 /* check if the whole reoptimization process should start from scratch */ 5586 if( node == NULL ) 5587 { 5588 /* compute the similarity to the objective function of the first run after restarting */ 5589 if( reopt->run > 1 && set->reopt_objsimdelay > -1.0 ) 5590 { 5591 sim = reoptSimilarity(reopt, set, reopt->run-1, MAX(0, reopt->lastrestart-1), transvars, ntransvars); 5592 5593 if( sim == SCIP_INVALID ) /*lint !e777*/ 5594 return SCIP_INVALIDRESULT; 5595 } 5596 5597 /* check similarity */ 5598 if( SCIPsetIsFeasLT(set, sim, set->reopt_objsimdelay) ) 5599 { 5600 SCIPsetDebugMsg(set, "-> restart reoptimization (objective functions are not similar enough)\n"); 5601 *restart = TRUE; 5602 } 5603 /* check size of the reoptimization tree */ 5604 else if( reopt->reopttree->nreoptnodes > set->reopt_maxsavednodes ) 5605 { 5606 SCIPsetDebugMsg(set, "-> restart reoptimization (node limit reached)\n"); 5607 *restart = TRUE; 5608 } 5609 /* check if the tree was only needed to prove optimality */ 5610 else if( reopt->noptsolsbyreoptsol >= set->reopt_forceheurrestart ) 5611 { 5612 SCIPsetDebugMsg(set, "-> restart reoptimization (found last %d optimal solutions by <reoptsols>)\n", 5613 reopt->noptsolsbyreoptsol); 5614 reopt->noptsolsbyreoptsol = 0; 5615 *restart = TRUE; 5616 } 5617 5618 if( *restart ) 5619 { 5620 /* trigger a restart */ 5621 SCIP_CALL( reoptRestart(reopt, set, blkmem) ); 5622 } 5623 } 5624 /* check for a local restart, ie, start the solving process of an inner node from scatch */ 5625 else 5626 { 5627 SCIP_CALL( reoptCheckLocalRestart(reopt, set, blkmem, node, transvars, ntransvars, restart) ); 5628 } 5629 return SCIP_OKAY; 5630 } 5631 5632 /** returns the similarity to the previous objective function, if no exist return -2.0 */ 5633 SCIP_Real SCIPreoptGetSimToPrevious( 5634 SCIP_REOPT* reopt /**< reoptimization data structure */ 5635 ) 5636 { 5637 assert(reopt != NULL); 5638 return reopt->simtolastobj; 5639 } 5640 5641 /** returns the similarity to the first objective different to the zero-function function, if no exist return -2.0 */ 5642 SCIP_Real SCIPreoptGetSimToFirst( 5643 SCIP_REOPT* reopt /**< reoptimization data structure */ 5644 ) 5645 { 5646 assert(reopt != NULL); 5647 return reopt->simtofirstobj; 5648 } 5649 5650 /** return the similarity between two of objective functions of two given runs */ 5651 SCIP_Real SCIPreoptGetSimilarity( 5652 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5653 SCIP_SET* set, /**< global SCIP settings */ 5654 int run1, /**< number of the first run */ 5655 int run2, /**< number of the second run */ 5656 SCIP_VAR** origvars, /**< original problem variables */ 5657 int norigvars /**< number of original problem variables */ 5658 ) 5659 { 5660 assert(reopt != NULL); 5661 assert(run1 > 0 && run1 <= reopt->run); 5662 assert(run2 > 0 && run2 <= reopt->run); 5663 assert(origvars != NULL); 5664 assert(norigvars >= 0); 5665 5666 return reoptSimilarity(reopt, set, run1-1, run2-1, origvars, norigvars); 5667 } 5668 5669 /** returns the best solution of the last run */ 5670 SCIP_SOL* SCIPreoptGetLastBestSol( 5671 SCIP_REOPT* reopt /**< reoptimization data structure */ 5672 ) 5673 { 5674 assert(reopt != NULL); 5675 assert(reopt->prevbestsols != NULL); 5676 5677 if( reopt->run-2 < 0 ) 5678 return NULL; 5679 else 5680 return reopt->prevbestsols[reopt->run-2]; 5681 } 5682 5683 /** returns the node of the reoptimization tree corresponding to the unique @p id */ 5684 SCIP_REOPTNODE* SCIPreoptGetReoptnode( 5685 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5686 unsigned int id /**< unique id */ 5687 ) 5688 { 5689 assert(reopt != NULL); 5690 assert(reopt->reopttree != NULL); 5691 assert(id < reopt->reopttree->reoptnodessize); 5692 assert(reopt->reopttree->reoptnodes[id] != NULL); 5693 5694 return reopt->reopttree->reoptnodes[id]; 5695 } 5696 5697 /** returns the coefficient of variable with index @p idx in run @p run */ 5698 SCIP_Real SCIPreoptGetOldObjCoef( 5699 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5700 int run, /**< number of the run (1,2,...) */ 5701 int idx /**< index of original variable */ 5702 ) 5703 { 5704 assert(reopt != NULL); 5705 assert(0 < run && run <= reopt->runsize); 5706 5707 return reopt->objs[run-1][idx]; 5708 } 5709 5710 /** return the best solution of a given run. 5711 * 5712 * @note the returned solution is part of the original space. 5713 */ 5714 SCIP_SOL* SCIPreoptGetBestSolRun( 5715 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5716 int run /**< number of the run (1,2,...) */ 5717 ) 5718 { 5719 assert(reopt != NULL); 5720 assert(0 < run && run <= reopt->run); 5721 5722 return reopt->prevbestsols[run-1]; 5723 } 5724 5725 /** reset solving specific parameters */ 5726 SCIP_RETCODE SCIPreoptReset( 5727 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5728 SCIP_SET* set, /**< global SCIP settings */ 5729 BMS_BLKMEM* blkmem /**< block memory */ 5730 ) 5731 { 5732 assert(reopt != NULL); 5733 assert(set != NULL); 5734 assert(blkmem != NULL); 5735 5736 /* clean addedconss array */ 5737 for( int c = 0; c < reopt->naddedconss; ++c ) 5738 { 5739 SCIP_CONS* cons; 5740 5741 cons = reopt->addedconss[c]; 5742 assert(cons != NULL); 5743 5744 #ifdef SCIP_MORE_DEBUG 5745 SCIPsetDebugMsg(set, "release cons <%s> from reoptimization data\n", SCIPconsGetName(cons)); 5746 #endif 5747 5748 SCIP_CALL( SCIPconsRelease(&cons, blkmem, set) ); 5749 reopt->addedconss[c] = NULL; 5750 } 5751 5752 reopt->naddedconss = 0; 5753 reopt->consadded = FALSE; 5754 reopt->objhaschanged = FALSE; 5755 5756 return SCIP_OKAY; 5757 } 5758 5759 /** reset marks of stored solutions to not updated */ 5760 void SCIPreoptResetSolMarks( 5761 SCIP_REOPT* reopt /**< reoptimization data structure */ 5762 ) 5763 { 5764 SCIP_SOLNODE* child; 5765 5766 assert(reopt != NULL); 5767 assert(reopt->soltree != NULL); 5768 assert(reopt->soltree->root != NULL); 5769 5770 child = reopt->soltree->root->child; 5771 5772 /* traverse through the list */ 5773 while( child != NULL ) 5774 { 5775 soltreeResetMarks(child); 5776 child = child->sibling; 5777 } 5778 } 5779 5780 /** returns the number of stored nodes in the subtree induced by @p node */ 5781 int SCIPreoptGetNNodes( 5782 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5783 SCIP_NODE* node /**< node of the search tree */ 5784 ) 5785 { 5786 unsigned int id; 5787 5788 assert(reopt != NULL); 5789 5790 if( node == NULL || SCIPnodeGetDepth(node) == 0 ) 5791 return reopt->reopttree->nreoptnodes; 5792 5793 id = SCIPnodeGetReoptID(node); 5794 assert(id < reopt->reopttree->reoptnodessize); 5795 5796 /* set the id to -1 if the node is not part of the reoptimization tree */ 5797 if( SCIPnodeGetDepth(node) > 0 && id == 0 ) 5798 return 0; 5799 5800 assert(0 < id && id < reopt->reopttree->reoptnodessize); 5801 5802 return reopttreeGetNNodes(reopt->reopttree, id); 5803 } 5804 5805 /* ---------------- methods of general reoptimization nodes ---------------- */ 5806 5807 /** In debug mode, the following methods are implemented as function calls to ensure 5808 * type validity. 5809 * In optimized mode, the methods are implemented as defines to improve performance. 5810 * However, we want to have them in the library anyways, so we have to undef the defines. 5811 */ 5812 5813 #undef SCIPreoptnodeGetNVars 5814 #undef SCIPreoptnodeGetNConss 5815 #undef SCIPreoptnodeGetNDualBoundChgs 5816 #undef SCIPreoptnodeGetNChildren 5817 #undef SCIPreoptnodeGetLowerbound 5818 #undef SCIPreoptnodeGetType 5819 5820 /** returns the number of bound changes stored in the reopttree at ID id */ 5821 int SCIPreoptnodeGetNVars( 5822 SCIP_REOPTNODE* reoptnode /**< node of the reopttree */ 5823 ) 5824 { 5825 assert(reoptnode != NULL); 5826 5827 return reoptnode->nvars + reoptnode->nafterdualvars; 5828 } 5829 5830 /** returns the number of bound changes at the node stored at ID id */ 5831 int SCIPreoptnodeGetNConss( 5832 SCIP_REOPTNODE* reoptnode /**< node of the reoptimization tree */ 5833 ) 5834 { 5835 assert(reoptnode != NULL); 5836 5837 return reoptnode->nconss; 5838 } 5839 5840 /** returns the number of stored bound changes based on dual information in the reopttree at ID id */ 5841 int SCIPreoptnodeGetNDualBoundChgs( 5842 SCIP_REOPTNODE* reoptnode /**< node of the reoptimization tree */ 5843 ) 5844 { 5845 assert(reoptnode != NULL); 5846 5847 if( reoptnode->dualredscur == NULL ) 5848 return 0; 5849 else 5850 return reoptnode->dualredscur->nvars; 5851 } 5852 5853 /** returns the number of child nodes of @p reoptnode */ 5854 int SCIPreoptnodeGetNChildren( 5855 SCIP_REOPTNODE* reoptnode /**< node of the reoptimization tree */ 5856 ) 5857 { 5858 assert(reoptnode != NULL); 5859 5860 return reoptnode->nchilds; 5861 } 5862 5863 /** return the lower bound stored at @p ID id */ 5864 SCIP_Real SCIPreoptnodeGetLowerbound( 5865 SCIP_REOPTNODE* reoptnode /**< node of the reoptimization tree */ 5866 ) 5867 { 5868 assert(reoptnode != NULL); 5869 5870 return reoptnode->lowerbound; 5871 } 5872 5873 /** returns the type of the @p reoptnode */ 5874 SCIP_REOPTTYPE SCIPreoptnodeGetType( 5875 SCIP_REOPTNODE* reoptnode /**< node of the reoptimization tree */ 5876 ) 5877 { 5878 assert(reoptnode != NULL); 5879 5880 return (SCIP_REOPTTYPE)reoptnode->reopttype; 5881 } 5882 5883 /** returns all added constraints at ID id */ 5884 void SCIPreoptnodeGetConss( 5885 SCIP_REOPTNODE* reoptnode, /**< node of the reoptimization tree */ 5886 SCIP_VAR*** vars, /**< 2-dim array of variables */ 5887 SCIP_Real** bounds, /**< 2-dim array of bounds */ 5888 SCIP_BOUNDTYPE** boundtypes, /**< 2-dim array of boundtypes */ 5889 int mem, /**< allocated memory for constraints */ 5890 int* nconss, /**< pointer to store the number of constraints */ 5891 int* nvars /**< pointer to store the number of variables */ 5892 ) 5893 { 5894 assert(reoptnode != NULL); 5895 assert(vars != NULL); 5896 assert(bounds != NULL); 5897 assert(boundtypes != NULL); 5898 assert(nvars != NULL); 5899 assert(nconss != NULL); 5900 5901 (*nconss) = reoptnode->nconss; 5902 5903 if( mem < *nconss ) 5904 return; 5905 5906 for( int c = 0; c < *nconss; ++c ) 5907 { 5908 assert(vars[c] != NULL); 5909 assert(bounds[c] != NULL); 5910 5911 vars[c] = reoptnode->conss[c]->vars; 5912 bounds[c] = reoptnode->conss[c]->vals; 5913 boundtypes[c] = reoptnode->conss[c]->boundtypes; 5914 nvars[c] = reoptnode->conss[c]->nvars; 5915 } 5916 } 5917 5918 /** set the parent id */ 5919 void SCIPreoptnodeSetParentID( 5920 SCIP_REOPTNODE* reoptnode, /**< node of the reopttree */ 5921 unsigned int parentid /**< id of the parent node */ 5922 ) 5923 { 5924 assert(reoptnode != NULL); 5925 assert(parentid <= 536870911); /* id can be at most 2^29 - 1 */ 5926 5927 reoptnode->parentID = parentid; 5928 } 5929 5930 /** returns the number of leaf nodes of the subtree induced by @p node (of the whole tree if node == NULL) */ 5931 int SCIPreoptGetNLeaves( 5932 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5933 SCIP_NODE* node /**< node of the search tree (or NULL) */ 5934 ) 5935 { 5936 int nleaves = 0; 5937 unsigned int id; 5938 5939 assert(reopt != NULL); 5940 5941 id = (node == NULL) ? 0 : SCIPnodeGetReoptID(node); 5942 assert(id < reopt->reopttree->reoptnodessize); 5943 5944 /* return if the node is not part of the reoptimization tree */ 5945 if( node != NULL && SCIPnodeGetDepth(node) > 0 && id == 0 ) 5946 return nleaves; 5947 5948 for( int i = 0; i < reopt->reopttree->reoptnodes[id]->nchilds; ++i ) 5949 { 5950 unsigned int childid; 5951 5952 childid = reopt->reopttree->reoptnodes[id]->childids[i]; /*lint !e713*/ 5953 assert(childid < reopt->reopttree->reoptnodessize); 5954 5955 if( reopt->reopttree->reoptnodes[childid]->nchilds == 0 ) 5956 ++nleaves; 5957 else 5958 nleaves += reoptGetNLeaves(reopt, childid); 5959 } 5960 5961 return nleaves; 5962 } 5963 5964 /** save information that given node is infeasible */ 5965 SCIP_RETCODE SCIPreoptAddInfNode( 5966 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5967 SCIP_SET* set, /**< global SCIP settings */ 5968 BMS_BLKMEM* blkmem, /**< block memory */ 5969 SCIP_NODE* node /**< node of the search tree */ 5970 ) 5971 { 5972 assert(reopt != NULL); 5973 assert(set != NULL); 5974 assert(blkmem != NULL); 5975 assert(node != NULL); 5976 5977 if( set->reopt_sepaglbinfsubtrees ) 5978 { 5979 SCIP_CALL( saveGlobalCons(reopt, set, blkmem, node, REOPT_CONSTYPE_CUT) ); 5980 } 5981 5982 ++reopt->reopttree->ninfnodes; 5983 ++reopt->reopttree->ntotalinfnodes; 5984 5985 return SCIP_OKAY; 5986 } 5987 5988 /** check the reason for cut off a node and if necessary store the node */ 5989 SCIP_RETCODE SCIPreoptCheckCutoff( 5990 SCIP_REOPT* reopt, /**< reoptimization data structure */ 5991 SCIP_SET* set, /**< global SCIP settings */ 5992 BMS_BLKMEM* blkmem, /**< block memory */ 5993 SCIP_NODE* node, /**< node of the search tree */ 5994 SCIP_EVENTTYPE eventtype, /**< eventtype */ 5995 SCIP_LP* lp, /**< LP data */ 5996 SCIP_LPSOLSTAT lpsolstat, /**< solution status of the LP */ 5997 SCIP_Bool isrootnode, /**< the node is the root */ 5998 SCIP_Bool isfocusnode, /**< the node is the current focus node */ 5999 SCIP_Real lowerbound, /**< lower bound of the node */ 6000 int effectiverootdepth /**< effective root depth */ 6001 ) 6002 { 6003 SCIP_Bool strongbranched; 6004 6005 assert(reopt != NULL); 6006 assert(set != NULL); 6007 assert(blkmem != NULL); 6008 assert(lp != NULL); 6009 assert(node != NULL); 6010 assert(eventtype == SCIP_EVENTTYPE_NODEBRANCHED || eventtype == SCIP_EVENTTYPE_NODEFEASIBLE || eventtype == SCIP_EVENTTYPE_NODEINFEASIBLE); 6011 6012 if( reopt->lastseennode == SCIPnodeGetNumber(node) ) 6013 return SCIP_OKAY; 6014 6015 /* we do not want to store probing node */ 6016 if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE ) 6017 return SCIP_OKAY; 6018 6019 reopt->lastseennode = SCIPnodeGetNumber(node); 6020 6021 SCIPsetDebugMsg(set, "catch event %" SCIP_EVENTTYPE_FORMAT " for node %lld (type:%d)\n", eventtype, SCIPnodeGetNumber(node), SCIPnodeGetType(node)); 6022 6023 /* case 1: the current node is the root node 6024 * we can skip if the root is (in)feasible or branched w/o bound 6025 * changes based on dual information. 6026 * 6027 * case 2: we need to store the current node if it contains 6028 * bound changes based on dual information or is a leave node 6029 */ 6030 if( isrootnode ) 6031 { 6032 if( SCIPreoptGetNDualBndchgs(reopt, node) > 0 ) 6033 { 6034 goto CHECK; 6035 } 6036 else if( eventtype == SCIP_EVENTTYPE_NODEBRANCHED ) 6037 { 6038 /* store or update the information */ 6039 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_TRANSIT, FALSE, isrootnode, lowerbound) ); 6040 } 6041 else if( eventtype == SCIP_EVENTTYPE_NODEFEASIBLE ) 6042 { 6043 /* delete saved dual information which would lead to split the node in a further iteration */ 6044 SCIP_CALL( SCIPreoptResetDualBndchgs(reopt, node, blkmem) ); 6045 6046 /* store or update the information */ 6047 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_FEASIBLE, FALSE, isrootnode, lowerbound) ); 6048 } 6049 else if( eventtype == SCIP_EVENTTYPE_NODEINFEASIBLE ) 6050 { 6051 /* delete saved dual information which would lead to split the node in a further iteration */ 6052 SCIP_CALL( SCIPreoptResetDualBndchgs(reopt, node, blkmem) ); 6053 6054 if( SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OBJLIMIT ) 6055 { 6056 SCIP_Real cutoffbound = SCIPlpGetCutoffbound(lp); 6057 lowerbound = MIN(lowerbound, cutoffbound); 6058 } 6059 6060 /* store or update the information */ 6061 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, reopt->currentnode == 1 ? SCIP_REOPTTYPE_INFSUBTREE : SCIP_REOPTTYPE_PRUNED, FALSE, 6062 isrootnode, lowerbound) ); 6063 } 6064 6065 assert(reopt->currentnode == -1); 6066 assert(reopt->dualreds == NULL || reopt->dualreds->nvars == 0); 6067 6068 return SCIP_OKAY; 6069 } 6070 6071 CHECK: 6072 6073 if( effectiverootdepth == SCIPnodeGetDepth(node) ) 6074 strongbranched = SCIPreoptGetNDualBndchgs(reopt, node) > 0 ? TRUE : FALSE; 6075 else 6076 strongbranched = SCIPnodeGetNDualBndchgs(node) > 0 ? TRUE : FALSE; 6077 6078 SCIPsetDebugMsg(set, "check the reason of cutoff for node %lld:\n", SCIPnodeGetNumber(node)); 6079 SCIPsetDebugMsg(set, " -> focusnode : %s\n", isfocusnode ? "yes" : "no"); 6080 SCIPsetDebugMsg(set, " -> depth : %d (eff. %d)\n", SCIPnodeGetDepth(node), effectiverootdepth); 6081 SCIPsetDebugMsg(set, " -> strong branched : %s\n", strongbranched ? "yes" : "no"); 6082 SCIPsetDebugMsg(set, " -> LP lpsolstat : %d\n", lpsolstat); 6083 6084 switch( eventtype ) 6085 { 6086 case SCIP_EVENTTYPE_NODEFEASIBLE: 6087 /* current node has to be the eventnode */ 6088 assert(isfocusnode); 6089 6090 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_FEASIBLE); 6091 6092 /* delete strong branching information of some exists */ 6093 deleteLastDualBndchgs(reopt); 6094 6095 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_FEASIBLE, FALSE, isrootnode, lowerbound) ); 6096 break; 6097 6098 case SCIP_EVENTTYPE_NODEINFEASIBLE: 6099 /* We have to check if the current node is the event node. 6100 * if the current node is not the event node, we have to save this node, else we have to 6101 * look at LP lpsolstat and decide. 6102 */ 6103 if( isfocusnode ) 6104 { 6105 /* An after-branch heuristic says NODEINFEASIBLE, maybe the cutoff bound is reached. 6106 * because the node is already branched we have all children and can delete this node. 6107 */ 6108 if( SCIPnodeGetNumber(node) == reopt->lastbranched ) 6109 { 6110 deleteLastDualBndchgs(reopt); 6111 break; 6112 } 6113 6114 /* If the node is strong branched, we possibly detect an infeasible subtree; 6115 * otherwise, the whole node is either infeasible or exceeds the cutoff bound. 6116 */ 6117 if( strongbranched ) 6118 { 6119 /* 1. the LP is infeasible: the (sub-)node is infeasible and can be discarded 6120 * because the LP proves infeasibility. We have to store an infeasible subtree separated by a constraint. 6121 * 2. the LP exceeds the objective limit or was not solved, we have to store the node and can delete the 6122 * strong branching information 6123 */ 6124 if( lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE ) 6125 { 6126 /* add a dummy variable, because the bound changes were not global in the sense of effective root depth */ 6127 if( SCIPnodeGetDepth(node) > effectiverootdepth ) 6128 { 6129 SCIP_CALL( SCIPreoptAddDualBndchg(reopt, set, blkmem, node, NULL, 0.0, 1.0) ); 6130 } 6131 6132 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_INFSUBTREE); 6133 SCIPsetDebugMsg(set, " -> new constype : %d\n", REOPT_CONSTYPE_INFSUBTREE); 6134 6135 /* save the node as a strong branched node */ 6136 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_INFSUBTREE, FALSE, isrootnode, lowerbound) ); 6137 } 6138 else 6139 { 6140 assert( lpsolstat == SCIP_LPSOLSTAT_OBJLIMIT || lpsolstat == SCIP_LPSOLSTAT_OPTIMAL || lpsolstat == SCIP_LPSOLSTAT_NOTSOLVED); 6141 6142 /* delete strong branching information if some exists */ 6143 deleteLastDualBndchgs(reopt); 6144 6145 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_PRUNED); 6146 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_PRUNED, FALSE, isrootnode, lowerbound) ); 6147 } 6148 } 6149 else 6150 { 6151 /* 1. the LP is infeasible: the whole node is infeasible and can be discarded 6152 * 2. the LP was not solved or exceeds the objective limit, we have to store the node 6153 */ 6154 if( lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE ) 6155 { 6156 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_INFSUBTREE); 6157 SCIP_CALL( SCIPreoptAddInfNode(reopt, set, blkmem, node) ); 6158 } 6159 else 6160 { 6161 assert(lpsolstat == SCIP_LPSOLSTAT_NOTSOLVED || lpsolstat == SCIP_LPSOLSTAT_OBJLIMIT 6162 || lpsolstat == SCIP_LPSOLSTAT_OPTIMAL); 6163 6164 if( SCIPreoptGetNAddedConss(reopt, node) > 0 ) 6165 { 6166 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_LOGICORNODE); 6167 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_LOGICORNODE, FALSE, isrootnode, lowerbound) ); 6168 } 6169 else 6170 { 6171 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_PRUNED); 6172 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_PRUNED, FALSE, isrootnode, lowerbound) ); 6173 } 6174 } 6175 } 6176 } 6177 else 6178 { 6179 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_PRUNED); 6180 6181 /* if the node was created by branch_nodereopt, nothing happens */ 6182 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_PRUNED, FALSE, isrootnode, lowerbound) ); 6183 } 6184 break; 6185 6186 case SCIP_EVENTTYPE_NODEBRANCHED: 6187 /* current node has to be the eventnode */ 6188 assert(isfocusnode); 6189 6190 reopt->lastbranched = SCIPnodeGetNumber(node); 6191 6192 /* we have to check the depth of the current node. if the depth is equal to the effective 6193 * root depth, then all information about bound changes based on dual information already exists, 6194 * else we have to look at the domchg-data-structure. 6195 */ 6196 if (SCIPnodeGetDepth(node) == effectiverootdepth) 6197 { 6198 /* Save the node if there are added constraints, because this means the node is a copy create by the 6199 * reoptimization plug-in and contains at least one logic-or-constraint */ 6200 if( strongbranched ) 6201 { 6202 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_STRBRANCHED); 6203 SCIPsetDebugMsg(set, " -> new constype : %d\n", REOPT_CONSTYPE_DUALREDS); 6204 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_STRBRANCHED, FALSE, isrootnode, lowerbound) ); 6205 } 6206 else if( SCIPreoptGetNAddedConss(reopt, node) > 0 ) 6207 { 6208 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_LOGICORNODE); 6209 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_LOGICORNODE, FALSE, isrootnode, lowerbound) ); 6210 } 6211 else 6212 { 6213 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_TRANSIT); 6214 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_TRANSIT, FALSE, isrootnode, lowerbound) ); 6215 } 6216 } 6217 else 6218 { 6219 /* we only branch on binary variables and var == NULL indicates memory allocation w/o saving information. 6220 * 6221 * we have to do this in the following order: 6222 * 1) all bound-changes are local, thats way we have to mark the node to include bound changes based 6223 * on dual information. 6224 * 2) save or update the node. 6225 */ 6226 if( strongbranched ) 6227 { 6228 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_STRBRANCHED); 6229 SCIPsetDebugMsg(set, " -> new constype : %d\n", REOPT_CONSTYPE_DUALREDS); 6230 SCIP_CALL( SCIPreoptAddDualBndchg(reopt, set, blkmem, node, NULL, 0.0, 1.0) ); 6231 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_STRBRANCHED, FALSE, isrootnode, lowerbound) ); 6232 } 6233 else if( SCIPreoptGetNAddedConss(reopt, node) > 0 ) 6234 { 6235 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_LOGICORNODE); 6236 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_LOGICORNODE, FALSE, isrootnode, lowerbound) ); 6237 } 6238 else 6239 { 6240 SCIPsetDebugMsg(set, " -> new reopttype : %d\n", SCIP_REOPTTYPE_TRANSIT); 6241 SCIP_CALL( addNode(reopt, set, lp, blkmem, node, SCIP_REOPTTYPE_TRANSIT, FALSE, isrootnode, lowerbound) ); 6242 } 6243 } 6244 break; 6245 6246 default: 6247 break; 6248 } 6249 6250 assert(reopt->currentnode == -1); 6251 assert(reopt->dualreds == NULL || reopt->dualreds->nvars == 0); 6252 6253 return SCIP_OKAY; /*lint !e438*/ 6254 } 6255 6256 /** store bound change based on dual information */ 6257 SCIP_RETCODE SCIPreoptAddDualBndchg( 6258 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6259 SCIP_SET* set, /**< global SCIP settings */ 6260 BMS_BLKMEM* blkmem, /**< block memory */ 6261 SCIP_NODE* node, /**< node of the search tree */ 6262 SCIP_VAR* var, /**< variable */ 6263 SCIP_Real newval, /**< new bound */ 6264 SCIP_Real oldval /**< old bound */ 6265 ) 6266 { 6267 SCIP_Real constant = 0.0; 6268 SCIP_Real scalar = 1.0; 6269 6270 assert(reopt != NULL); 6271 assert(node != NULL); 6272 6273 /* If var == NULL, we save all information by calling SCIPreoptNodeFinished(). 6274 * In that case, all bound changes were not global and we can find them within the 6275 * domchg data structure. 6276 * Otherwise, we allocate memory and store the information. 6277 */ 6278 if( var != NULL ) 6279 { 6280 SCIP_BOUNDTYPE boundtype; 6281 int resizelength; 6282 int allocmem; 6283 6284 if( SCIPsetFindBranchrule(set, "relpscost") != NULL ) 6285 { 6286 SCIP_CALL( SCIPsetGetIntParam(set, "branching/relpscost/maxlookahead", &resizelength) ); 6287 } 6288 else 6289 resizelength = 1; 6290 6291 if( reopt->dualreds == NULL || reopt->dualreds->varssize == 0 ) 6292 allocmem = DEFAULT_MEM_DUALCONS; 6293 else 6294 allocmem = reopt->dualreds->nvars + resizelength; 6295 6296 /* allocate memory of necessary */ 6297 SCIP_CALL( checkMemDualCons(reopt, set, blkmem, allocmem) ); 6298 6299 assert(reopt->dualreds->varssize > 0); 6300 assert(reopt->dualreds->nvars >= 0); 6301 assert(reopt->currentnode == -1 || reopt->dualreds->nvars > 0); 6302 assert((reopt->dualreds->nvars > 0 && reopt->currentnode == SCIPnodeGetNumber(node)) 6303 || reopt->dualreds->nvars == 0); 6304 6305 reopt->currentnode = SCIPnodeGetNumber(node); 6306 6307 /* transform into the original space and then save the bound change */ 6308 SCIP_CALL(SCIPvarGetOrigvarSum(&var, &scalar, &constant)); 6309 newval = (newval - constant) / scalar; 6310 oldval = (oldval - constant) / scalar; 6311 6312 assert(SCIPvarIsOriginal(var)); 6313 6314 if( SCIPsetIsEQ(set, oldval, newval) ) 6315 { 6316 SCIPerrorMessage("cannot store equal bounds: old = %g, new = %g\n", oldval, newval); 6317 return SCIP_INVALIDDATA; 6318 } 6319 6320 if( SCIPsetIsLT(set, newval, oldval) ) 6321 boundtype = SCIP_BOUNDTYPE_UPPER; 6322 else 6323 boundtype = SCIP_BOUNDTYPE_LOWER; 6324 6325 reopt->dualreds->vars[reopt->dualreds->nvars] = var; 6326 reopt->dualreds->vals[reopt->dualreds->nvars] = newval; 6327 reopt->dualreds->boundtypes[reopt->dualreds->nvars] = boundtype; 6328 ++reopt->dualreds->nvars; 6329 6330 SCIPsetDebugMsg(set, ">> store %s bound change of <%s>: %g -> %g\n", 6331 (boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper"), SCIPvarGetName(var), oldval, newval); 6332 6333 reopt->dualreds->linear = FALSE; 6334 } 6335 else 6336 { 6337 assert(reopt->currentnode == -1); 6338 assert(reopt->dualreds == NULL || reopt->dualreds->nvars == 0); 6339 6340 reopt->currentnode = SCIPnodeGetNumber(node); 6341 } 6342 6343 return SCIP_OKAY; 6344 } 6345 6346 /** returns the number of bound changes based on dual information */ 6347 int SCIPreoptGetNDualBndchgs( 6348 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6349 SCIP_NODE* node /**< node of the search tree */ 6350 ) 6351 { 6352 int ndualbndchgs = 0; 6353 6354 assert(reopt != NULL); 6355 assert(node != NULL); 6356 6357 if( SCIPnodeGetNumber(node) == reopt->currentnode ) 6358 { 6359 assert(reopt->dualreds != NULL); 6360 ndualbndchgs = reopt->dualreds->nvars; 6361 } 6362 6363 return ndualbndchgs; 6364 } 6365 6366 /** returns the child nodes of @p node that need to be reoptimized next or NULL if @p node is a leaf */ 6367 SCIP_RETCODE SCIPreoptGetChildIDs( 6368 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6369 SCIP_SET* set, /**< global SCIP settings */ 6370 BMS_BLKMEM* blkmem, /**< block memory */ 6371 SCIP_NODE* node, /**< node of the search tree */ 6372 unsigned int* childs, /**< array to store the child ids */ 6373 int childssize, /**< size of the childs array */ 6374 int* nchilds /**< pointer to store the number of child nodes */ 6375 ) 6376 { 6377 SCIP_Bool runagain; 6378 unsigned int id; 6379 6380 assert(reopt != NULL); 6381 assert(childssize > 0 && childs != NULL); 6382 assert(nchilds != NULL); 6383 6384 (*nchilds) = 0; 6385 6386 if( node == NULL ) 6387 id = 0; 6388 else 6389 id = SCIPnodeGetReoptID(node); 6390 6391 assert(id >= 1 || SCIPnodeGetDepth(node) == 0); 6392 assert(id < reopt->reopttree->reoptnodessize); 6393 assert(reopt->reopttree->reoptnodes[id] != NULL); 6394 6395 /* check if there are redundant bound changes or infeasible nodes */ 6396 runagain = TRUE; 6397 while( runagain && reopt->reopttree->reoptnodes[id]->nchilds > 0 ) 6398 { 6399 SCIP_CALL( dryBranch(reopt, set, blkmem, &runagain, id) ); 6400 } 6401 6402 /* return the list of child nodes if some exists; otherwise return NULL */ 6403 if( reopt->reopttree->reoptnodes[id]->childids != NULL && reopt->reopttree->reoptnodes[id]->nchilds > 0 ) 6404 { 6405 (*nchilds) = reopt->reopttree->reoptnodes[id]->nchilds; 6406 6407 if( childssize < *nchilds ) 6408 return SCIP_OKAY; 6409 6410 for( int c = 0; c < *nchilds; ++c ) 6411 childs[c] = reopt->reopttree->reoptnodes[id]->childids[c]; 6412 } 6413 6414 return SCIP_OKAY; 6415 } 6416 6417 /** returns all leaves of the subtree induced by @p node */ 6418 SCIP_RETCODE SCIPreoptGetLeaves( 6419 SCIP_REOPT* reopt, /**< reoptimization data */ 6420 SCIP_NODE* node, /**< node of the search tree */ 6421 unsigned int* leaves, /**< array to the the ids */ 6422 int leavessize, /**< size of leaves array */ 6423 int* nleaves /**< pointer to store the number of leave node */ 6424 ) 6425 { 6426 unsigned int id; 6427 6428 assert(reopt != NULL); 6429 assert(leavessize > 0 && leaves != NULL); 6430 assert((*nleaves) >= 0); 6431 6432 /* if the given node is we start from the root */ 6433 if( node == NULL ) 6434 id = 0; 6435 else 6436 id = SCIPnodeGetReoptID(node); 6437 6438 /* return if the node is not part of the reoptimization tree */ 6439 if( id == 0 && node != NULL ) 6440 { 6441 (*nleaves) = 0; 6442 return SCIP_OKAY; 6443 } 6444 6445 assert(id < reopt->reopttree->reoptnodessize); 6446 assert(reopt->reopttree->reoptnodes[id] != NULL); 6447 6448 for( int i = 0; i < leavessize; ++i ) 6449 leaves[i] = 0; 6450 6451 /* we traverse through all child nodes of the given node an collect all leave nodes of the subtrees induced by them */ 6452 for( int i = 0; i < reopt->reopttree->reoptnodes[id]->nchilds; ++i ) 6453 { 6454 unsigned int childid; 6455 6456 assert(*nleaves + 1 <= leavessize); 6457 6458 childid = reopt->reopttree->reoptnodes[id]->childids[i]; 6459 assert(childid < reopt->reopttree->reoptnodessize); 6460 6461 /* the node is already a leave */ 6462 if( reopt->reopttree->reoptnodes[childid]->nchilds == 0 ) 6463 { 6464 leaves[(*nleaves)] = reopt->reopttree->reoptnodes[id]->childids[i]; 6465 ++(*nleaves); 6466 } 6467 /* go into the tree induced by the current child node */ 6468 else 6469 { 6470 int nleaves2 = 0; 6471 6472 SCIP_CALL( reoptGetLeaves(reopt, childid, &leaves[*nleaves], leavessize - (*nleaves), &nleaves2) ); 6473 (*nleaves) += nleaves2; 6474 } 6475 } 6476 6477 return SCIP_OKAY; 6478 } 6479 6480 /** add all unprocessed nodes to the reoptimization tree */ 6481 SCIP_RETCODE SCIPreoptSaveOpenNodes( 6482 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6483 SCIP_SET* set, /**< global SCIP settings */ 6484 SCIP_LP* lp, /**< current LP */ 6485 BMS_BLKMEM* blkmem, /**< block memory */ 6486 SCIP_NODE** leaves, /**< array of open leave nodes */ 6487 int nleaves, /**< number of open leave nodes */ 6488 SCIP_NODE** childs, /**< array of open children nodes */ 6489 int nchilds, /**< number of open leave nodes */ 6490 SCIP_NODE** siblings, /**< array of open sibling nodes */ 6491 int nsiblings /**< number of open leave nodes */ 6492 ) 6493 { 6494 assert(reopt != NULL); 6495 assert(set != NULL); 6496 assert(blkmem != NULL); 6497 assert(nleaves >= 0); 6498 assert(nleaves == 0 || leaves != NULL); 6499 assert(nchilds >= 0); 6500 assert(nchilds == 0 || childs != NULL); 6501 assert(nsiblings >= 0); 6502 assert(nsiblings == 0 || siblings != NULL); 6503 6504 SCIPsetDebugMsg(set, "save unprocessed nodes (%d leaves, %d children, %d siblings)\n", nleaves, nchilds, nsiblings); 6505 6506 /* save open leaves */ 6507 for( int n = 0; n < nleaves; ++n ) 6508 { 6509 SCIP_CALL( addNode(reopt, set, lp, blkmem, leaves[n], SCIP_REOPTTYPE_PRUNED, FALSE, FALSE, 6510 SCIPnodeGetLowerbound(leaves[n])) ); 6511 } 6512 6513 /* save open children */ 6514 for( int n = 0; n < nchilds; ++n ) 6515 { 6516 SCIP_CALL( addNode(reopt, set, lp, blkmem, childs[n], SCIP_REOPTTYPE_PRUNED, FALSE, FALSE, 6517 SCIPnodeGetLowerbound(childs[n])) ); 6518 } 6519 6520 /* save open siblings */ 6521 for( int n = 0; n < nsiblings; ++n ) 6522 { 6523 SCIP_CALL( addNode(reopt, set, lp, blkmem, siblings[n], SCIP_REOPTTYPE_PRUNED, FALSE, FALSE, 6524 SCIPnodeGetLowerbound(siblings[n])) ); 6525 } 6526 6527 return SCIP_OKAY; 6528 } 6529 6530 /** merges the variable history of the current run with the stored history */ 6531 SCIP_RETCODE SCIPreoptMergeVarHistory( 6532 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6533 SCIP_SET* set, /**< global SCIP settings */ 6534 SCIP_STAT* stat, /**< dynamic problem statistics */ 6535 SCIP_VAR** vars, /**< original problem variables */ 6536 int nvars /**< number of original problem variables */ 6537 ) 6538 { 6539 SCIP_VAR* transvar; 6540 SCIP_Real avginference[2]; 6541 SCIP_Real avgcutoff[2]; 6542 SCIP_Real bestsim; 6543 int bestrun; 6544 int idx; 6545 6546 assert(reopt != NULL); 6547 assert(stat != NULL); 6548 assert(nvars >= 0); 6549 6550 if( !set->reopt_storevarhistory ) 6551 return SCIP_OKAY; 6552 6553 SCIPsetDebugMsg(set, "start merging variable histories:\n"); 6554 6555 bestrun = reopt->run-2; 6556 bestsim = reopt->simtolastobj; 6557 6558 /* find the run with the most similar objective */ 6559 for( int r = reopt->run-3; r >= 0 && reopt->objhaschanged && set->reopt_usepscost; --r ) 6560 { 6561 SCIP_Real sim; 6562 sim = reoptSimilarity(reopt, set, r, reopt->run-1, vars, nvars); 6563 6564 if( sim == SCIP_INVALID ) /*lint !e777*/ 6565 return SCIP_INVALIDRESULT; 6566 6567 if( SCIPsetIsGT(set, sim, bestsim) ) 6568 { 6569 bestsim = sim; 6570 bestrun = r; 6571 } 6572 } 6573 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_NORMAL, NULL, "run %d has best similarity=%g\n", bestrun, bestsim); 6574 6575 /* iterate through all variables and scale the histories */ 6576 for( int v = 0; v < nvars; ++v ) 6577 { 6578 assert(SCIPvarIsOriginal(vars[v])); 6579 6580 transvar = SCIPvarGetTransVar(vars[v]); 6581 assert(transvar != NULL); 6582 6583 /* skip variable that are not active */ 6584 if( !SCIPvarIsActive(transvar) ) 6585 continue; 6586 6587 idx = SCIPvarGetIndex(vars[v]); 6588 assert(0 <= idx && idx <= nvars); 6589 6590 /* set the updated history for both directions */ 6591 for( int d = 0; d <= 1; ++d ) 6592 { 6593 if( set->reopt_usepscost && !SCIPsetIsZero(set, reopt->varhistory[bestrun][idx]->pscostcount[d]) 6594 && SCIPsetIsGT(set, bestsim, 0.985) ) /* 0.985 is a magic number determined in some experiments */ 6595 { 6596 transvar->history->pscostcount[d] = 1.0; 6597 transvar->history->pscostweightedmean[d] = reopt->varhistory[bestrun][idx]->pscostweightedmean[d]; 6598 transvar->history->pscostvariance[d] = 0.0; 6599 SCIPsetDebugMsg(set, "-> <%s> pscosts %4s: count=%g weightedmean=%g variance=%g\n", SCIPvarGetName(transvar), 6600 (d == 0 ? "down" : "up"), transvar->history->pscostcount[d], transvar->history->pscostweightedmean[d], 6601 transvar->history->pscostvariance[d]); 6602 } 6603 6604 SCIPhistoryIncNBranchings(transvar->history, (SCIP_BRANCHDIR)d, 1); 6605 6606 /* inference score */ 6607 avginference[d] = SCIPhistoryGetAvgInferences(reopt->varhistory[reopt->run-2][idx], (SCIP_BRANCHDIR)d); 6608 SCIPhistoryIncInferenceSum(transvar->history, (SCIP_BRANCHDIR)d, avginference[d]); 6609 6610 /* cutoff score */ 6611 avgcutoff[d] = SCIPhistoryGetAvgCutoffs(reopt->varhistory[reopt->run-2][idx], (SCIP_BRANCHDIR)d); 6612 SCIPhistoryIncCutoffSum(transvar->history, (SCIP_BRANCHDIR)d, avgcutoff[d]); 6613 6614 SCIPsetDebugMsg(set, "-> <%s> %4s scores: inf=%g cutoff=%g\n", SCIPvarGetName(transvar), 6615 (d == 0 ? "down" : "up"), avginference[d], avgcutoff[d]); 6616 } 6617 } 6618 6619 return SCIP_OKAY; 6620 } 6621 6622 /** updates the variable history */ 6623 SCIP_RETCODE SCIPreoptUpdateVarHistory( 6624 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6625 SCIP_SET* set, /**< global SCIP settings */ 6626 SCIP_STAT* stat, /**< dynamic problem statistics */ 6627 BMS_BLKMEM* blkmem, /**< block memory */ 6628 SCIP_VAR** vars, /**< original variable array */ 6629 int nvars /**< number of original variables */ 6630 ) 6631 { 6632 assert(reopt != NULL); 6633 assert(stat != NULL); 6634 assert(blkmem != NULL); 6635 assert(nvars >= 0); 6636 6637 if( !set->reopt_storevarhistory ) 6638 return SCIP_OKAY; 6639 6640 SCIPsetDebugMsg(set, "updating variable history\n"); 6641 6642 if( reopt->varhistory[reopt->run-1] == NULL ) 6643 { 6644 /* allocate memory */ 6645 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &reopt->varhistory[reopt->run-1], nvars) ); 6646 6647 for( int v = 0; v < nvars; ++v ) 6648 { 6649 SCIP_CALL( SCIPhistoryCreate(&(reopt->varhistory[reopt->run-1][v]), blkmem) ); 6650 } 6651 } 6652 6653 /* update the history and scale them */ 6654 for( int v = 0; v < nvars; ++v ) 6655 { 6656 SCIP_VAR* transvar; 6657 int idx; 6658 6659 assert(SCIPvarIsOriginal(vars[v])); 6660 idx = SCIPvarGetIndex(vars[v]); 6661 assert(idx >= 0 && idx < nvars); 6662 6663 transvar = SCIPvarGetTransVar(vars[v]); 6664 assert(transvar != NULL); 6665 6666 if( !SCIPvarIsActive(transvar) ) 6667 continue; 6668 6669 /* we store the complete history */ 6670 SCIPhistoryReset(reopt->varhistory[reopt->run-1][idx]); 6671 SCIPhistoryUnite(reopt->varhistory[reopt->run-1][idx], transvar->history, FALSE); 6672 } 6673 6674 return SCIP_OKAY; 6675 } 6676 6677 /** reset the complete tree and set the given search frontier */ 6678 SCIP_RETCODE SCIPreoptApplyCompression( 6679 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6680 SCIP_SET* set, /**< global SCIP settings */ 6681 BMS_BLKMEM* blkmem, /**< block memory */ 6682 SCIP_REOPTNODE** representatives, /**< array of representatives */ 6683 int nrepresentatives, /**< number of representatives */ 6684 SCIP_Bool* success /**< pointer to store if the method was successful */ 6685 ) 6686 { 6687 SCIP_REOPTTREE* reopttree; 6688 unsigned int id; 6689 6690 assert(reopt != NULL); 6691 assert(set != NULL); 6692 assert(blkmem != NULL); 6693 assert(representatives != NULL); 6694 assert(nrepresentatives > 0); 6695 6696 reopttree = reopt->reopttree; 6697 6698 /* reset the current search tree */ 6699 SCIP_CALL( reoptResetTree(reopt, set, blkmem, FALSE) ); 6700 assert(reopttree->nreoptnodes == 0); 6701 6702 /* create a new root node */ 6703 id = 0; 6704 SCIP_CALL( createReoptnode(reopttree, set, blkmem, id) ); 6705 6706 /* set the reopttype */ 6707 reopttree->reoptnodes[0]->reopttype = (unsigned int)SCIP_REOPTTYPE_TRANSIT; 6708 6709 /* add all representatives */ 6710 for( int r = 0; r < nrepresentatives; ++r ) 6711 { 6712 /* get an empty slot*/ 6713 id = SCIPqueueRemoveUInt(reopttree->openids); 6714 assert(1 <= id && id < reopttree->reoptnodessize); 6715 assert(reopttree->reoptnodes[id] == NULL); 6716 6717 SCIP_CALL( createReoptnode(reopttree, set, blkmem, id) ); 6718 assert(reopttree->reoptnodes[id] != NULL); 6719 6720 /* set the new node 6721 * 1. copy all variables, bounds, and boundtypes 6722 * 2. copy all constraints 6723 * 3. set the parent relation 6724 */ 6725 if( representatives[r]->nvars > 0 ) 6726 { 6727 assert(representatives[r]->nvars <= representatives[r]->varssize); 6728 6729 for( int v = 0; v < representatives[r]->nvars; ++v ) 6730 { 6731 SCIP_CALL( SCIPreoptnodeAddBndchg(reopttree->reoptnodes[id], set, blkmem, representatives[r]->vars[v], 6732 representatives[r]->varbounds[v], representatives[r]->varboundtypes[v]) ); 6733 } 6734 } 6735 6736 if( representatives[r]->nconss > 0 ) 6737 { 6738 assert(representatives[r]->nconss <= representatives[r]->consssize); 6739 6740 for( int c = 0; c < representatives[r]->nconss; ++c ) 6741 { 6742 SCIP_CALL( SCIPreoptnodeAddCons(reopttree->reoptnodes[id], set, blkmem, representatives[r]->conss[c]->vars, 6743 representatives[r]->conss[c]->vals, representatives[r]->conss[c]->boundtypes, 6744 representatives[r]->conss[c]->lhs, representatives[r]->conss[c]->rhs, 6745 representatives[r]->conss[c]->nvars, representatives[r]->conss[c]->constype, 6746 representatives[r]->conss[c]->linear) ); 6747 } 6748 } 6749 6750 reopttree->reoptnodes[id]->parentID = representatives[r]->parentID; /*lint !e732*/ 6751 6752 assert(reopttree->reoptnodes[id]->parentID == 0); 6753 assert(reopttree->reoptnodes[id]->nvars >= 0); 6754 assert(reopttree->reoptnodes[id]->nvars <= reopttree->reoptnodes[id]->varssize); 6755 assert(reopttree->reoptnodes[id]->nconss >= 0); 6756 6757 /* set the reopttype */ 6758 if( reopttree->reoptnodes[id]->nconss == 0 ) 6759 reopttree->reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_LEAF; 6760 else 6761 reopttree->reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_LOGICORNODE; 6762 6763 /* add the representative as a child of the root */ 6764 SCIP_CALL( reoptAddChild(reopttree, set, blkmem, 0, id) ); 6765 } 6766 6767 SCIPsetDebugMsg(set, "-> new tree consists of %d nodes, the root has %d child nodes.\n", 6768 reopttree->nreoptnodes, reopttree->reoptnodes[0]->nchilds); 6769 6770 (*success) = TRUE; 6771 6772 return SCIP_OKAY; 6773 } 6774 6775 /** transforms a set of dual reductions into a linear constraint */ 6776 static 6777 SCIP_RETCODE transformDualredsToLinear( 6778 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6779 SCIP_SET* set, /**< global SCIP settings */ 6780 BMS_BLKMEM* blkmem, /**< block memory */ 6781 SCIP_REOPTCONSDATA* consdata, /**< reoptimization constraint data that should represent to set of solutions 6782 * pruned by the dual reductions */ 6783 SCIP_REOPTCONSDATA* dualreds /**< set of dual reductions */ 6784 ) 6785 { 6786 assert(reopt != NULL); 6787 assert(set != NULL); 6788 assert(blkmem != NULL); 6789 assert(consdata != NULL); 6790 assert(dualreds != NULL); 6791 6792 /* we have to transform the set of bound changes into a linear constraint */ 6793 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &consdata->vars, dualreds->vars, dualreds->nvars) ); 6794 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &consdata->vals, dualreds->nvars) ); 6795 consdata->boundtypes = NULL; 6796 6797 consdata->varssize = dualreds->nvars; 6798 consdata->nvars = dualreds->nvars; 6799 consdata->constype = REOPT_CONSTYPE_DUALREDS; 6800 consdata->linear = TRUE; 6801 6802 /* set lhs and rhs */ 6803 consdata->lhs = 1.0; 6804 consdata->rhs = SCIPsetInfinity(set); 6805 6806 for( int v = 0; v < consdata->nvars; ++v ) 6807 { 6808 assert(consdata->vars[v] != NULL); 6809 6810 /* the bound is 0.0, the variable has to appear with a coefficient +1.0 in the constraint, sides do not change */ 6811 if( SCIPsetIsEQ(set, dualreds->vals[v], 0.0) ) 6812 { 6813 assert(dualreds->boundtypes[v] == SCIP_BOUNDTYPE_UPPER); 6814 consdata->vals[v] = 1.0; 6815 } 6816 /* the bound is 1.0, the variable has to appear with a coefficient -1.0 in the constraint, we subtract -1.0 from lhs 6817 * logicor: sum x_i + ~y_i >= 1 6818 * <==> sum x_i + (1-y_i) >= 1 6819 * <==> sum x_i - y_i >= 0 6820 */ 6821 else 6822 { 6823 assert(SCIPsetIsEQ(set, dualreds->vals[v], 1.0)); 6824 assert(dualreds->boundtypes[v] == SCIP_BOUNDTYPE_LOWER); 6825 6826 consdata->vals[v] = -1.0; 6827 consdata->lhs -= 1.0; 6828 } 6829 } 6830 6831 return SCIP_OKAY; 6832 } 6833 6834 6835 /** transforms a set of dual reductions into a bounddisjuction constraint */ 6836 static 6837 SCIP_RETCODE transformDualredsToBounddisjunction( 6838 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6839 SCIP_SET* set, /**< global SCIP settings */ 6840 BMS_BLKMEM* blkmem, /**< block memory */ 6841 SCIP_REOPTCONSDATA* consdata, /**< reoptimization constraint data that should represent to set of solutions 6842 * pruned by the dual reductions */ 6843 SCIP_REOPTCONSDATA* dualreds /**< set of dual reductions */ 6844 ) 6845 { 6846 assert(reopt != NULL); 6847 assert(set != NULL); 6848 assert(blkmem != NULL); 6849 assert(consdata != NULL); 6850 assert(dualreds != NULL); 6851 6852 /* we have to transform the set of bound changes into a linear constraint */ 6853 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &consdata->vars, dualreds->vars, dualreds->nvars) ); 6854 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &consdata->vals, dualreds->vals, dualreds->nvars) ); 6855 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &consdata->boundtypes, dualreds->boundtypes, dualreds->nvars) ); 6856 6857 consdata->varssize = dualreds->nvars; 6858 consdata->nvars = dualreds->nvars; 6859 consdata->constype = REOPT_CONSTYPE_DUALREDS; 6860 consdata->linear = FALSE; 6861 6862 /* set lhs and rhs */ 6863 consdata->lhs = SCIP_UNKNOWN; 6864 consdata->rhs = SCIP_UNKNOWN; 6865 6866 for( int v = 0; v < consdata->nvars; ++v ) 6867 { 6868 SCIP_Real glbbd; 6869 6870 assert(consdata->vars[v] != NULL); 6871 6872 /* we do the followung to transformations: 6873 * (a) x <= val ==> (x >= val+1) 6874 * (b) x >= val ==> (x <= val-1) 6875 */ 6876 if( consdata->boundtypes[v] == SCIP_BOUNDTYPE_UPPER ) 6877 { 6878 glbbd = SCIPvarGetUbGlobal(consdata->vars[v]); 6879 consdata->vals[v] = MIN(consdata->vals[v]+1.0, glbbd); 6880 } 6881 else 6882 { 6883 assert(dualreds->boundtypes[v] == SCIP_BOUNDTYPE_LOWER); 6884 glbbd = SCIPvarGetLbGlobal(consdata->vars[v]); 6885 consdata->vals[v] = MAX(glbbd, consdata->vals[v]-1.0); 6886 } 6887 consdata->boundtypes[v] = (SCIP_BOUNDTYPE)(SCIP_BOUNDTYPE_UPPER - consdata->boundtypes[v]); /*lint !e656*/ 6888 } 6889 6890 return SCIP_OKAY; 6891 } 6892 6893 /** splits the root into several nodes and moves the child nodes of the root to one of the created nodes */ 6894 SCIP_RETCODE SCIPreoptSplitRoot( 6895 SCIP_REOPT* reopt, /**< reoptimization data structure */ 6896 SCIP_TREE* tree, /**< branch and bound tree */ 6897 SCIP_SET* set, /**< global SCIP settings */ 6898 SCIP_STAT* stat, /**< dynamic SCIP statistics */ 6899 BMS_BLKMEM* blkmem, /**< block memory */ 6900 int* ncreatedchilds, /**< pointer to store the number of created nodes */ 6901 int* naddedconss /**< pointer to store the number added constraints */ 6902 ) 6903 { 6904 SCIP_REOPTTREE* reopttree; 6905 SCIP_REOPTNODE** reoptnodes; 6906 SCIP_REOPTCONSDATA* consdata; 6907 SCIP_VAR** vars; 6908 SCIP_Real* bounds; 6909 SCIP_BOUNDTYPE* boundtypes; 6910 int* perm = NULL; 6911 unsigned int id; 6912 int nbndchgs; 6913 int nchilds; 6914 int nvars = 0; 6915 int v; 6916 6917 assert(reopt != NULL); 6918 assert(set != NULL); 6919 assert(stat != NULL); 6920 assert(blkmem != NULL); 6921 6922 reopttree = reopt->reopttree; 6923 assert(reopttree != NULL); 6924 6925 reoptnodes = reopttree->reoptnodes; 6926 assert(reoptnodes != NULL); 6927 assert(reoptnodes[0] != NULL); 6928 assert(reoptnodes[0]->dualreds); 6929 assert(reoptnodes[0]->reopttype == (unsigned int)SCIP_REOPTTYPE_STRBRANCHED); 6930 6931 nchilds = reoptnodes[0]->nchilds; 6932 6933 assert(reoptnodes[0]->dualredscur != NULL); 6934 nbndchgs = reoptnodes[0]->dualredscur->nvars; 6935 6936 (*ncreatedchilds) = 0; 6937 (*naddedconss) = 0; 6938 6939 /* create a node with all variables fixed, i.e., reconstruct the root of the last iteration */ 6940 6941 /* ensure that two free slots are available */ 6942 SCIP_CALL( reopttreeCheckMemory(reopttree, set, blkmem) ); 6943 id = SCIPqueueRemoveUInt(reopttree->openids); 6944 6945 assert(0 < id && id < reopt->reopttree->reoptnodessize); 6946 assert(reoptnodes[id] == NULL || reoptnodes[id]->nvars == 0); 6947 6948 /* 1. create the node 6949 * 2. add all bound changes 6950 * 3. move all child nodes to id 6951 * 4. add id as a child of the root node 6952 */ 6953 SCIP_CALL( createReoptnode(reopttree, set, blkmem, id) ); 6954 reoptnodes[id]->parentID = 0; 6955 reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_TRANSIT; 6956 6957 /* check memory */ 6958 SCIP_CALL( reoptnodeCheckMemory(reoptnodes[id], set, blkmem, nbndchgs, nchilds, 0) ); 6959 assert(reoptnodes[id]->varssize >= nbndchgs); 6960 assert(reoptnodes[id]->nvars == 0); 6961 assert(reoptnodes[id]->vars != NULL); 6962 assert(reoptnodes[id]->varbounds != NULL); 6963 assert(reoptnodes[id]->varboundtypes != NULL); 6964 6965 /* create a permutation array */ 6966 if( !set->reopt_usesplitcons ) 6967 { 6968 assert(perm == NULL); 6969 SCIP_CALL( SCIPsetAllocBufferArray(set, &perm, nbndchgs) ); 6970 } 6971 6972 /* copy bounds */ 6973 for( v = 0; v < nbndchgs; ++v ) 6974 { 6975 reoptnodes[id]->vars[v] = reoptnodes[0]->dualredscur->vars[v]; 6976 reoptnodes[id]->varbounds[v] = reoptnodes[0]->dualredscur->vals[v]; 6977 reoptnodes[id]->varboundtypes[v] = reoptnodes[0]->dualredscur->boundtypes[v]; 6978 ++reoptnodes[id]->nvars; 6979 6980 /* fill a permutation array */ 6981 if( !set->reopt_usesplitcons ) 6982 perm[v] = v; /*lint !e613*/ 6983 } 6984 assert(reoptnodes[id]->nvars == reoptnodes[0]->dualredscur->nvars); 6985 6986 /* move the children */ 6987 SCIP_CALL( reoptMoveIDs(reopttree, set, blkmem, 0, id) ); 6988 assert(reoptnodes[0]->nchilds == 0); 6989 6990 /* add the new reoptimization node as a child of the root node */ 6991 SCIP_CALL( reoptAddChild(reopttree, set, blkmem, 0, id) ); 6992 6993 ++(*ncreatedchilds); 6994 6995 if( set->reopt_usesplitcons ) 6996 { 6997 int nbinvars = 0; 6998 #ifndef NDEBUG 6999 int nintvars = 0; 7000 int ncontvars = 0; 7001 #endif 7002 7003 assert(*ncreatedchilds == 1); 7004 7005 /* ensure that there is a free slots */ 7006 SCIP_CALL( reopttreeCheckMemory(reopttree, set, blkmem) ); 7007 id = SCIPqueueRemoveUInt(reopttree->openids); 7008 assert(0 < id && id < reopt->reopttree->reoptnodessize); 7009 7010 /* 1. create the node 7011 * 2. add the constraint to ensure that at least one 7012 * variable gets different 7013 * 3. add id as a child of the root node 7014 */ 7015 SCIP_CALL( createReoptnode(reopttree, set, blkmem, id) ); 7016 reoptnodes[id]->parentID = 0; 7017 reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_LOGICORNODE; 7018 7019 /* check memory for added constraints */ 7020 SCIP_CALL( reoptnodeCheckMemory(reoptnodes[id], set, blkmem, 0, 0, 1) ); 7021 7022 /* create the constraint */ 7023 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &reoptnodes[id]->conss[0]) ); 7024 consdata = reoptnodes[id]->conss[0]; 7025 7026 /* count number of binary, integer, and continuous varibales */ 7027 for( v = 0; v < nbndchgs; ++v ) 7028 { 7029 switch( SCIPvarGetType(reoptnodes[0]->dualredscur->vars[v]) ) { 7030 case SCIP_VARTYPE_BINARY: 7031 ++nbinvars; 7032 break; 7033 case SCIP_VARTYPE_INTEGER: 7034 case SCIP_VARTYPE_IMPLINT: 7035 #ifndef NDEBUG 7036 ++nintvars; 7037 #endif 7038 break; 7039 case SCIP_VARTYPE_CONTINUOUS: 7040 #ifndef NDEBUG 7041 ++ncontvars; 7042 #endif 7043 break; 7044 default: 7045 SCIPerrorMessage("Cannot handle vartype %d\n", SCIPvarGetType(reoptnodes[0]->dualredscur->vars[v])); 7046 return SCIP_INVALIDDATA; 7047 } 7048 } 7049 7050 /* we create a linear constraint, since all variables are binary */ 7051 if( nbinvars == nbndchgs ) 7052 { 7053 SCIP_CALL( transformDualredsToLinear(reopt, set, blkmem, consdata, reoptnodes[0]->dualredscur) ); 7054 } 7055 /* we create a bounddisjunction constraint, since at least one variable is (implicit) integer or continuous */ 7056 else 7057 { 7058 assert(nintvars > 0 || ncontvars > 0); 7059 SCIP_CALL( transformDualredsToBounddisjunction(reopt, set, blkmem, consdata, reoptnodes[0]->dualredscur) ); 7060 } 7061 ++reoptnodes[id]->nconss; 7062 7063 /* add id as a child of the root node */ 7064 SCIP_CALL( reoptAddChild(reopttree, set, blkmem, 0, id) ); 7065 ++(*ncreatedchilds); 7066 7067 ++(*naddedconss); 7068 } 7069 else 7070 { 7071 assert(*ncreatedchilds == 1); 7072 assert(perm != NULL); 7073 7074 vars = reoptnodes[0]->dualredscur->vars; 7075 bounds = reoptnodes[0]->dualredscur->vals; 7076 boundtypes = reoptnodes[0]->dualredscur->boundtypes; 7077 nvars = reoptnodes[0]->dualredscur->nvars; 7078 assert(perm[0] == 0 && perm[nvars-1] == nvars-1); 7079 7080 /* calculate the order of the variables */ 7081 switch (set->reopt_varorderinterdiction) 7082 { 7083 /* default order */ 7084 case 'd': 7085 break; 7086 7087 /* inference order */ 7088 case 'i': 7089 SCIP_CALL( getInferenceOrder(set, stat, perm, vars, bounds, boundtypes, nvars) ); 7090 break; 7091 7092 /* random order */ 7093 case 'r': 7094 SCIPrandomPermuteIntArray(reopt->randnumgen, perm, 0, nvars-1); 7095 break; 7096 7097 default: 7098 return SCIP_INVALIDDATA; 7099 } 7100 7101 /* create nvars nodes in the fashion of interdiction branching */ 7102 for( int c = 0; c < nvars; ++c ) 7103 { 7104 /* ensure that two free slots are available */ 7105 SCIP_CALL( reopttreeCheckMemory(reopttree, set, blkmem) ); 7106 id = SCIPqueueRemoveUInt(reopttree->openids); 7107 7108 assert(0 < id && id < reopt->reopttree->reoptnodessize); 7109 assert(reoptnodes[id] == NULL || reoptnodes[id]->nvars == 0); 7110 7111 /* 1. create the node 7112 * 2. fix the first v bound changes to vals[v] and v+1 to vals[v] +/- 1 (depending on the bound- and vartype) 7113 * 4. add the ID id as a child of the root node 7114 */ 7115 SCIP_CALL( createReoptnode(reopttree, set, blkmem, id) ); 7116 reoptnodes[id]->parentID = 0; 7117 reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_TRANSIT; 7118 7119 /* check memory */ 7120 SCIP_CALL( reoptnodeCheckMemory(reoptnodes[id], set, blkmem, c+1, 0, 0) ); 7121 assert(reoptnodes[id]->varssize >= perm[c]+1); 7122 assert(reoptnodes[id]->nvars == 0); 7123 assert(reoptnodes[id]->vars != NULL); 7124 assert(reoptnodes[id]->varbounds != NULL); 7125 assert(reoptnodes[id]->varboundtypes != NULL); 7126 7127 /* the permutation is the identity */ 7128 if( set->reopt_varorderinterdiction == 'd' ) 7129 { 7130 /* copy first c bound changes */ 7131 for( v = 0; v < c; ++v ) 7132 { 7133 reoptnodes[id]->vars[v] = vars[v]; 7134 reoptnodes[id]->varbounds[v] = bounds[v]; 7135 reoptnodes[id]->varboundtypes[v] = boundtypes[v]; 7136 } 7137 } 7138 else 7139 { 7140 /* copy first c bound changes */ 7141 for( v = 0; v < c; ++v ) 7142 { 7143 reoptnodes[id]->vars[v] = vars[perm[v]]; 7144 reoptnodes[id]->varbounds[v] = bounds[perm[v]]; 7145 reoptnodes[id]->varboundtypes[v] = boundtypes[perm[v]]; 7146 } 7147 } 7148 reoptnodes[id]->nvars += c; 7149 7150 /* set bound change v+1 (= c) to vals[v] +/- 1 (depending on the bound- and vartype) */ 7151 assert(v == c); 7152 reoptnodes[id]->vars[c] = vars[perm[c]]; 7153 reoptnodes[id]->varbounds[c] = bounds[perm[c]]; 7154 if( SCIPvarGetType(vars[perm[c]]) != SCIP_VARTYPE_CONTINUOUS ) 7155 { 7156 if( boundtypes[perm[c]] == SCIP_BOUNDTYPE_LOWER ) 7157 reoptnodes[id]->varbounds[c] -= 1.0; 7158 else 7159 reoptnodes[id]->varbounds[c] += 1.0; 7160 } 7161 reoptnodes[id]->varboundtypes[c] = (boundtypes[perm[c]] == SCIP_BOUNDTYPE_UPPER ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER); 7162 ++reoptnodes[id]->nvars; 7163 7164 /* add dummy1 as a child of the root node */ 7165 SCIP_CALL( reoptAddChild(reopttree, set, blkmem, 0, id) ); 7166 7167 ++(*ncreatedchilds); 7168 } 7169 7170 assert(*ncreatedchilds == nvars+1); 7171 7172 SCIPsetFreeBufferArray(set, &perm); 7173 perm = NULL; 7174 } 7175 assert(perm == NULL); 7176 7177 /* free the current dualredscur and assign dualredsnex */ 7178 assert(reoptnodes[0]->dualredscur->vars != NULL); 7179 assert(reoptnodes[0]->dualredscur->vals != NULL); 7180 assert(reoptnodes[0]->dualredscur->boundtypes != NULL); 7181 7182 /* free the current dualredscur and assign dualredsnex */ 7183 SCIP_CALL( reoptnodeUpdateDualConss(reoptnodes[0], blkmem) ); 7184 7185 /* change the reopttype of the root node */ 7186 SCIPnodeSetReopttype(SCIPtreeGetRootNode(tree), SCIP_REOPTTYPE_TRANSIT); 7187 7188 return SCIP_OKAY; 7189 } 7190 7191 /** reset the stored information abound bound changes based on dual information */ 7192 SCIP_RETCODE SCIPreoptResetDualBndchgs( 7193 SCIP_REOPT* reopt, /**< reoptimization data structure */ 7194 SCIP_NODE* node, /**< node of the search tree */ 7195 BMS_BLKMEM* blkmem /**< block memory */ 7196 ) 7197 { 7198 unsigned int id; 7199 7200 assert(reopt != NULL); 7201 assert(node != NULL); 7202 7203 id = SCIPnodeGetReoptID(node); 7204 assert(id < reopt->reopttree->reoptnodessize); 7205 7206 /* return if the node is not part of the reoptimization tree */ 7207 if( SCIPnodeGetDepth(node) > 0 && id == 0 ) 7208 return SCIP_OKAY; 7209 7210 /* reset the dual constraint */ 7211 SCIP_CALL( reoptnodeResetDualConss(reopt->reopttree->reoptnodes[id], blkmem) ); 7212 7213 return SCIP_OKAY; 7214 } 7215 7216 /** return the branching path stored of the given node in the reoptimization tree */ 7217 void SCIPreoptnodeGetPath( 7218 SCIP_REOPT* reopt, /**< reoptimization data structure */ 7219 SCIP_REOPTNODE* reoptnode, /**< node of the reoptimization tree */ 7220 SCIP_VAR** vars, /**< array for variables */ 7221 SCIP_Real* vals, /**< array for values */ 7222 SCIP_BOUNDTYPE* boundtypes, /**< array for bound types */ 7223 int varssize, /**< size of arrays vars, vals, and boundtypes */ 7224 int* nbndchgs, /**< pointer to store the number of bound changes */ 7225 int* nbndchgsafterdual /**< pointer to store the number of bound changes applied after 7226 * the first dual reduction at the given node */ 7227 ) 7228 { 7229 int v; 7230 int nvars2; 7231 int nafterdualvars2; 7232 7233 assert(reopt != NULL); 7234 assert(reoptnode != NULL); 7235 assert(vars != NULL); 7236 assert(vals != NULL); 7237 assert(boundtypes != NULL); 7238 7239 (*nbndchgs) = reoptnode->nvars; 7240 (*nbndchgsafterdual) = reoptnode->nafterdualvars; 7241 7242 /* return if the size of the given array is not large enough */ 7243 if( varssize == 0 || varssize < *nbndchgs + *nbndchgsafterdual ) 7244 return; 7245 7246 /* add all bound changes made by branching (including dual reductions) */ 7247 for( v = 0; v < *nbndchgs; ++v ) 7248 { 7249 vars[v] = reoptnode->vars[v]; 7250 vals[v] = reoptnode->varbounds[v]; 7251 boundtypes[v] = reoptnode->varboundtypes[v]; 7252 } 7253 7254 /* add all bound changes made applied after a dual reduction */ 7255 for( ; v < *nbndchgs + *nbndchgsafterdual; ++v ) 7256 { 7257 vars[v] = reoptnode->afterdualvars[v-(*nbndchgs)]; 7258 vals[v] = reoptnode->afterdualvarbounds[v-(*nbndchgs)]; 7259 boundtypes[v] = reoptnode->afterdualvarboundtypes[v-(*nbndchgs)]; 7260 } 7261 7262 /* go along the root path within the reoptimization tree */ 7263 if( reoptnode->parentID != 0 ) 7264 { 7265 SCIP_REOPTNODE* parent; 7266 7267 parent = reopt->reopttree->reoptnodes[reoptnode->parentID]; 7268 SCIPreoptnodeGetPath(reopt, parent, &vars[v], &vals[v], &boundtypes[v], varssize, &nvars2, &nafterdualvars2); 7269 7270 (*nbndchgs) += nvars2; 7271 (*nbndchgsafterdual) += nafterdualvars2; 7272 } 7273 } 7274 7275 /** delete a node stored in the reoptimization tree */ 7276 SCIP_RETCODE SCIPreoptDeleteNode( 7277 SCIP_REOPT* reopt, /**< reoptimization data structure */ 7278 SCIP_SET* set, /**< global SCIP settings */ 7279 unsigned int id, /**< id of a stored node */ 7280 BMS_BLKMEM* blkmem /**< block memory */ 7281 ) 7282 { 7283 assert(reopt != NULL); 7284 assert(reopt->reopttree != NULL); 7285 assert(id < reopt->reopttree->reoptnodessize); 7286 assert(reopt->reopttree->reoptnodes[id] != NULL); 7287 assert(blkmem != NULL); 7288 7289 SCIP_CALL( reopttreeDeleteNode(reopt->reopttree, set, blkmem, id, TRUE) ); 7290 SCIP_CALL( SCIPqueueInsertUInt(reopt->reopttree->openids, id) ); 7291 7292 return SCIP_OKAY; 7293 } 7294 7295 /** reactivate the given @p reoptnode and split them into several nodes if necessary */ 7296 SCIP_RETCODE SCIPreoptApply( 7297 SCIP_REOPT* reopt, /**< reoptimization data structure */ 7298 SCIP* scip, /**< SCIP data structure */ 7299 SCIP_SET* set, /**< global SCIP settings */ 7300 SCIP_STAT* stat, /**< dynamic problem statistics */ 7301 SCIP_PROB* transprob, /**< transformed problem */ 7302 SCIP_PROB* origprob, /**< original problem */ 7303 SCIP_TREE* tree, /**< branching tree */ 7304 SCIP_LP* lp, /**< current LP */ 7305 SCIP_BRANCHCAND* branchcand, /**< branching candidate */ 7306 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 7307 SCIP_CLIQUETABLE* cliquetable, /**< clique table */ 7308 BMS_BLKMEM* blkmem, /**< block memory */ 7309 SCIP_REOPTNODE* reoptnode, /**< node of the reoptimization tree to reactivate */ 7310 unsigned int id, /**< id of the node to reactivate */ 7311 SCIP_Real estimate, /**< estimate of the child nodes that should be created */ 7312 SCIP_NODE** childnodes, /**< array to store the created child nodes */ 7313 int* ncreatedchilds, /**< pointer to store number of created child nodes */ 7314 int* naddedconss, /**< pointer to store number of generated constraints */ 7315 int childnodessize, /**< available size of childnodes array */ 7316 SCIP_Bool* success /**< pointer store the result */ 7317 ) 7318 { 7319 assert(reopt != NULL); 7320 assert(scip != NULL); 7321 assert(set != NULL); 7322 assert(stat != NULL); 7323 assert(transprob != NULL); 7324 assert(origprob != NULL); 7325 assert(tree != NULL); 7326 assert(lp != NULL); 7327 assert(branchcand != NULL); 7328 assert(eventqueue != NULL); 7329 assert(cliquetable != NULL); 7330 assert(blkmem != NULL); 7331 assert(reoptnode != NULL); 7332 assert(childnodes != NULL); 7333 assert(reopt->reopttree != NULL); 7334 assert(id < reopt->reopttree->reoptnodessize); 7335 assert(success != NULL); 7336 7337 SCIPsetDebugMsg(set, "reactivating node at id %u:\n", id); 7338 7339 *success = FALSE; 7340 7341 /* check if we need to split the node */ 7342 if( reoptnode->reopttype == (unsigned int)SCIP_REOPTTYPE_STRBRANCHED 7343 || reoptnode->reopttype == (unsigned int)SCIP_REOPTTYPE_INFSUBTREE ) 7344 { 7345 assert(reoptnode->dualreds); 7346 7347 /* we want use a constraint to split the node into two disjoint node */ 7348 if( set->reopt_usesplitcons ) 7349 { 7350 if( reoptnode->reopttype == (unsigned int)SCIP_REOPTTYPE_INFSUBTREE ) 7351 { 7352 assert(reoptnode->dualredscur != NULL); 7353 assert(reoptnode->dualredscur->constype == REOPT_CONSTYPE_INFSUBTREE); 7354 (*ncreatedchilds) = 1; 7355 } 7356 else 7357 { 7358 assert(reoptnode->dualredscur != NULL); 7359 assert(reoptnode->dualredscur->constype == REOPT_CONSTYPE_DUALREDS); 7360 (*ncreatedchilds) = 2; 7361 } 7362 7363 /* in both cases we add exactly one constraint */ 7364 (*naddedconss) = 1; 7365 7366 if( childnodessize < *ncreatedchilds ) 7367 return SCIP_OKAY; 7368 7369 /* generate the nodes */ 7370 for( int c = 0; c < *ncreatedchilds; ++c ) 7371 { 7372 /* create the child node */ 7373 SCIP_CALL( SCIPnodeCreateChild(&childnodes[c], blkmem, set, stat, tree, 1.0, estimate) ); 7374 7375 /* change all bounds; convert the bound changes after the first based on dual reductions into branching 7376 * for second node only. if we generate only one node, i.e., the pruned part, we do not need this 7377 * changes anyway. 7378 */ 7379 SCIP_CALL( changeAncestorBranchings(reopt, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue, 7380 cliquetable, blkmem, childnodes[c], id, c == 1) ); 7381 7382 /* add all local constraints */ 7383 SCIP_CALL( addLocalConss(scip, reopt, set, stat, blkmem, childnodes[c], id) ); 7384 7385 /* we can use the old lowerbound if the objective function has not changed */ 7386 if( !reopt->objhaschanged && SCIPsetIsGT(set, reopt->reopttree->reoptnodes[id]->lowerbound, estimate) ) 7387 SCIPnodeSetEstimate(childnodes[c], set, reopt->reopttree->reoptnodes[id]->lowerbound); 7388 7389 if( c == 0 ) 7390 { 7391 /* in both cases the node generated first represents the pruned is currently not part of the reoptimization tree */ 7392 SCIPnodeSetReopttype(childnodes[c], SCIP_REOPTTYPE_NONE); 7393 7394 /* add the constraint to the node */ 7395 assert(reopt->reopttree->reoptnodes[id]->dualredscur != NULL); 7396 SCIP_CALL( addSplitcons(reopt, scip, set, stat, blkmem, transprob, origprob, tree, lp, branchcand, 7397 eventqueue, cliquetable, childnodes[c], id) ); 7398 7399 /* fixBounds() does the same, but in this case we go not into it */ 7400 if( reoptnode->dualredscur->constype == REOPT_CONSTYPE_INFSUBTREE ) 7401 { 7402 assert(reoptnode->dualredscur->nvars > 0); 7403 assert(reoptnode->dualredscur->varssize > 0); 7404 7405 /* delete dualredscur and move dualredsnex -> dualredscur */ 7406 SCIP_CALL( reoptnodeUpdateDualConss(reoptnode, blkmem) ); 7407 } 7408 7409 /* the added constraint could be deleted due to propagation, thus, we store the node in the reoptimization 7410 * tree. the node has to stored anyway, because of the constraint representing the dual reductions 7411 */ 7412 SCIP_CALL( addNode(reopt, set, lp, blkmem, childnodes[c], SCIP_REOPTTYPE_LOGICORNODE, FALSE, FALSE, 7413 -SCIPsetInfinity(set)) ); 7414 } 7415 else 7416 { 7417 /* if we reach this lines of code, the current node represents the original node including all bound 7418 * changes based in dual information. 7419 */ 7420 assert(reoptnode->dualredscur->constype == REOPT_CONSTYPE_DUALREDS); 7421 if( reoptnode->nconss == 0 ) 7422 SCIPnodeSetReopttype(childnodes[c], SCIP_REOPTTYPE_TRANSIT); 7423 else 7424 SCIPnodeSetReopttype(childnodes[c], SCIP_REOPTTYPE_LOGICORNODE); 7425 7426 /* fix all bound changes based on dual information and convert them into branchings */ 7427 assert(reopt->reopttree->reoptnodes[id]->dualredscur != NULL); 7428 SCIP_CALL( fixBounds(reopt, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue, cliquetable, 7429 blkmem, childnodes[c], id, TRUE) ); 7430 7431 /* set the unique id the id of the original node */ 7432 SCIPnodeSetReoptID(childnodes[c], id); 7433 } 7434 } 7435 7436 /* reset the stored dual constraints */ 7437 SCIP_CALL( reoptnodeUpdateDualConss(reopt->reopttree->reoptnodes[id], blkmem) ); 7438 7439 /* set the reoptimization type */ 7440 if( reopt->reopttree->reoptnodes[id]->dualreds ) 7441 reopt->reopttree->reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_STRBRANCHED; 7442 else 7443 reopt->reopttree->reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_TRANSIT; 7444 7445 *success = TRUE; 7446 } 7447 else 7448 { 7449 SCIP_VAR** vars; 7450 SCIP_Real* bounds; 7451 SCIP_BOUNDTYPE* boundtypes; 7452 int* perm = NULL; 7453 int nvars; 7454 7455 vars = reoptnode->dualredscur->vars; 7456 bounds = reoptnode->dualredscur->vals; 7457 boundtypes = reoptnode->dualredscur->boundtypes; 7458 nvars = reoptnode->dualredscur->nvars; 7459 7460 *ncreatedchilds = nvars+1; 7461 *naddedconss = 0; 7462 7463 /* check if there is enough memory allocated */ 7464 if( childnodessize < *ncreatedchilds ) 7465 return SCIP_OKAY; 7466 7467 /* create and fill permutation array */ 7468 SCIP_CALL( SCIPsetAllocBufferArray(set, &perm, nvars) ); 7469 for( int c = 0; c < nvars; ++c ) 7470 perm[c] = c; 7471 7472 /* calculate the order of the variables */ 7473 switch (set->reopt_varorderinterdiction) 7474 { 7475 /* default order */ 7476 case 'd': 7477 break; 7478 7479 /* inference order */ 7480 case 'i': 7481 SCIP_CALL( getInferenceOrder(set, stat, perm, vars, bounds, boundtypes, nvars) ); 7482 break; 7483 7484 /* random order */ 7485 case 'r': 7486 SCIPrandomPermuteIntArray(reopt->randnumgen, perm, 0, nvars-1); 7487 break; 7488 7489 default: 7490 return SCIP_INVALIDDATA; 7491 } 7492 7493 assert(reopt->reopttree->reoptnodes[id] != NULL); 7494 reoptnode = reopt->reopttree->reoptnodes[id]; 7495 7496 /* enough that the node need to split */ 7497 assert(reoptnode->dualreds); 7498 7499 /* iterate over all nodes and change the necessary bounds (nodes[0] corresponds to the original one) 7500 * we need to do this in the reverse order because we want to transform the bound changes based on dual information 7501 * into branching decisions at nodes[0]. 7502 */ 7503 for( int c = nvars; c >= 0; --c ) 7504 { 7505 /* create the child node */ 7506 SCIP_CALL( SCIPnodeCreateChild(&childnodes[c], blkmem, set, stat, tree, 1.0, estimate) ); 7507 7508 #ifdef SCIP_MORE_DEBUG 7509 SCIPsetDebugMsg(set, " change bounds at node %lld\n", SCIPnodeGetNumber(childnodes[c])); 7510 #endif 7511 7512 /* change all bounds */ 7513 SCIP_CALL( changeAncestorBranchings(reopt, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue, 7514 cliquetable, blkmem, childnodes[c], id, FALSE) ); 7515 7516 /* reconstruct the original node and the pruned part, respectively */ 7517 if( c == 0 ) 7518 { 7519 /* fix bound changes based on dual information and convert all these bound changes to normal bound changes */ 7520 SCIP_CALL( fixBounds(reopt, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue, cliquetable, 7521 blkmem, childnodes[c], id, TRUE) ); 7522 7523 /* set the reopttype of the node */ 7524 SCIPnodeSetReopttype(childnodes[c], SCIP_REOPTTYPE_TRANSIT); 7525 7526 /* set the unique id */ 7527 SCIPnodeSetReoptID(childnodes[c], id); 7528 } 7529 else 7530 { 7531 /* fix the first c bound changes and negate the (c+1)th */ 7532 SCIP_CALL( fixInterdiction(reopt, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue, cliquetable, 7533 blkmem, childnodes[c], id, perm, vars, bounds, boundtypes, nvars, c) ); 7534 } 7535 7536 /* add all local constraints */ 7537 SCIP_CALL( addLocalConss(scip, reopt, set, stat, blkmem, childnodes[c], id) ); 7538 7539 /* we can use the old lowerbound if the objective function has not changed */ 7540 if( !reopt->objhaschanged && SCIPsetIsGT(set, reopt->reopttree->reoptnodes[id]->lowerbound, estimate) ) 7541 SCIPnodeSetEstimate(childnodes[c], set, reopt->reopttree->reoptnodes[id]->lowerbound); 7542 } 7543 7544 /* free buffer array */ 7545 SCIPsetFreeBufferArray(set, &perm); 7546 7547 /* reset the stored dual constraints */ 7548 SCIP_CALL( reoptnodeUpdateDualConss(reopt->reopttree->reoptnodes[id], blkmem) ); 7549 7550 /* set the reoptimization type to transit */ 7551 if( reopt->reopttree->reoptnodes[id]->dualreds ) 7552 reopt->reopttree->reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_STRBRANCHED; 7553 else 7554 reopt->reopttree->reoptnodes[id]->reopttype = (unsigned int)SCIP_REOPTTYPE_TRANSIT; 7555 7556 *success = TRUE; 7557 } 7558 } 7559 else 7560 { 7561 /* we need the create exactly one node to reconstruct the node itself and no additional constraint */ 7562 (*ncreatedchilds) = 1; 7563 (*naddedconss) = 0; 7564 7565 if( childnodessize < *ncreatedchilds ) 7566 return SCIP_OKAY; 7567 7568 /* create the child node */ 7569 SCIP_CALL( SCIPnodeCreateChild(&childnodes[0], blkmem, set, stat, tree, 1.0, estimate) ); 7570 7571 /* change all bounds */ 7572 assert(reoptnode->nafterdualvars == 0); 7573 SCIP_CALL( changeAncestorBranchings(reopt, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue, 7574 cliquetable, blkmem, childnodes[0], id, FALSE) ); 7575 7576 /* add all local constraints */ 7577 SCIP_CALL( addLocalConss(scip, reopt, set, stat, blkmem, childnodes[0], id) ); 7578 7579 /* we can use the old lowerbound if the objective function has not changed */ 7580 if( !reopt->objhaschanged && SCIPsetIsGT(set, reopt->reopttree->reoptnodes[id]->lowerbound, estimate) ) 7581 SCIPnodeSetEstimate(childnodes[0], set, reopt->reopttree->reoptnodes[id]->lowerbound); 7582 7583 /* set the reopttype */ 7584 assert(reoptnode->reopttype != (unsigned int)SCIP_REOPTTYPE_INFSUBTREE 7585 && reoptnode->reopttype != (unsigned int)SCIP_REOPTTYPE_STRBRANCHED); 7586 SCIPnodeSetReopttype(childnodes[0], (SCIP_REOPTTYPE)reoptnode->reopttype); 7587 7588 /* set the unique id */ 7589 SCIPnodeSetReoptID(childnodes[0], id); 7590 7591 *success = TRUE; 7592 } 7593 7594 return SCIP_OKAY; 7595 } 7596 7597 /** returns the time needed to store the nodes for reoptimization */ 7598 SCIP_Real SCIPreoptGetSavingtime( 7599 SCIP_REOPT* reopt /**< reoptimization data structure */ 7600 ) 7601 { 7602 assert(reopt != NULL); 7603 7604 return SCIPclockGetTime(reopt->savingtime); 7605 } 7606 7607 /** add the stored constraints globally to the problem */ 7608 SCIP_RETCODE SCIPreoptApplyGlbConss( 7609 SCIP* scip, /**< SCIP data structure */ 7610 SCIP_REOPT* reopt, /**< reoptimization data structure */ 7611 SCIP_SET* set, /**< global SCIP settings */ 7612 SCIP_STAT* stat, /**< dynamic problem statistics */ 7613 BMS_BLKMEM* blkmem /**< block memory */ 7614 ) 7615 { 7616 char name[SCIP_MAXSTRLEN]; 7617 7618 assert(scip != NULL); 7619 assert(reopt != NULL); 7620 assert(set != NULL); 7621 assert(stat != NULL); 7622 assert(blkmem != NULL); 7623 7624 if( reopt->glbconss == NULL || reopt->nglbconss == 0 ) 7625 return SCIP_OKAY; 7626 7627 for( int c = reopt->nglbconss-1; c >= 0; --c ) 7628 { 7629 SCIP_CONS* cons; 7630 SCIP_VAR** consvars; 7631 int nbinvars; 7632 int nintvars; 7633 7634 assert(reopt->glbconss[c] != NULL); 7635 assert(reopt->glbconss[c]->nvars > 0); 7636 7637 cons = NULL; 7638 consvars = NULL; 7639 nbinvars = 0; 7640 nintvars = 0; 7641 7642 /* check if we can use a logic-or or if we have to use a bounddisjuction constraint */ 7643 for( int v = 0; v < reopt->glbconss[c]->nvars; ++v ) 7644 { 7645 if( SCIPvarGetType(reopt->glbconss[c]->vars[v]) == SCIP_VARTYPE_BINARY ) 7646 ++nbinvars; 7647 else if( SCIPvarGetType(reopt->glbconss[c]->vars[v]) == SCIP_VARTYPE_INTEGER 7648 || SCIPvarGetType(reopt->glbconss[c]->vars[v]) == SCIP_VARTYPE_IMPLINT ) 7649 ++nintvars; 7650 else 7651 { 7652 SCIPerrorMessage("Expected variable type binary or (impl.) integer for variable <%s> in global constraint at pos. %d.\n", 7653 SCIPvarGetName(reopt->glbconss[c]->vars[v]), c); 7654 return SCIP_INVALIDDATA; 7655 } 7656 } 7657 7658 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "glb_%s_%d_%d", reopt->glbconss[c]->constype == REOPT_CONSTYPE_CUT ? "cut" : "inf", reopt->run, c); 7659 7660 /* @todo use active representatives */ 7661 7662 /* all variables are binary, we can create a logic-or constraint */ 7663 if( nbinvars == reopt->glbconss[c]->nvars ) 7664 { 7665 SCIPsetDebugMsg(set, "-> add logic-or constraints with %d binvars\n", nbinvars); 7666 7667 /* allocate buffer */ 7668 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, reopt->glbconss[c]->nvars) ); 7669 7670 for( int v = 0; v < reopt->glbconss[c]->nvars; ++v ) 7671 { 7672 consvars[v] = reopt->glbconss[c]->vars[v]; 7673 assert(SCIPvarIsOriginal(consvars[v])); 7674 7675 /* negate the variable if it was fixed to 1 */ 7676 if( SCIPsetIsFeasEQ(set, reopt->glbconss[c]->vals[v], 0.0) ) 7677 { 7678 assert(reopt->glbconss[c]->boundtypes[v] == SCIP_BOUNDTYPE_UPPER); 7679 SCIP_CALL( SCIPvarNegate(consvars[v], blkmem, set, stat, &consvars[v]) ); 7680 } 7681 } 7682 7683 /* create the logic-or constraint */ 7684 SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, name, reopt->glbconss[c]->nvars, 7685 consvars, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); 7686 7687 /* free buffer */ 7688 SCIPfreeBufferArray(scip, &consvars); 7689 } 7690 /* not all variables are binary, we need a bounddisjunction constraint */ 7691 else 7692 { 7693 assert(reopt->glbconss[c]->nvars == nbinvars + 2*nintvars); 7694 7695 SCIPsetDebugMsg(set, "-> add bounddisjuction constraints with %d binvars, %d intvars\n", nbinvars, (int) (2*nintvars)); 7696 7697 /* create the bounddisjuction constraint */ 7698 SCIP_CALL( SCIPcreateConsBasicBounddisjunction(scip, &cons, name, reopt->glbconss[c]->nvars, reopt->glbconss[c]->vars, 7699 reopt->glbconss[c]->boundtypes, reopt->glbconss[c]->vals) ); 7700 } 7701 7702 #ifdef SCIP_DEBUG_CONSS 7703 SCIPdebugPrintCons(scip, cons, NULL); 7704 #endif 7705 7706 SCIP_CALL( SCIPaddCons(scip, cons) ); 7707 7708 /* remember the constraint for re-activation */ 7709 assert(!SCIPhashsetExists(reopt->activeconssset, (void*)cons)); 7710 SCIP_CALL( SCIPhashsetInsert(reopt->activeconssset, blkmem, (void*)cons) ); 7711 SCIP_CALL( ensureActiveconssSize(reopt, set, blkmem, reopt->nactiveconss + 1) ); 7712 assert(reopt->nactiveconss < reopt->nmaxactiveconss); 7713 reopt->activeconss[reopt->nactiveconss++] = cons; 7714 7715 /* don't release the constraint because we would need to capture the constraint anyway */ 7716 7717 /* mark the constraint as empty */ 7718 reopt->glbconss[c]->nvars = 0; 7719 } 7720 7721 SCIPsetDebugMsg(set, "added %d gobal constraints\n", reopt->nglbconss); 7722 7723 /* reset number of global constraints */ 7724 reopt->nglbconss = 0; 7725 7726 return SCIP_OKAY; 7727 } 7728 7729 /** add the stored cuts to the separation storage */ 7730 SCIP_RETCODE SCIPreoptApplyCuts( 7731 SCIP_REOPT* reopt, /**< reoptimization data structure */ 7732 SCIP_NODE* node, /**< current focus node */ 7733 SCIP_SEPASTORE* sepastore, /**< separation storage */ 7734 SCIP_CUTPOOL* cutpool, /**< global cutpool */ 7735 BMS_BLKMEM* blkmem, /**< block memory */ 7736 SCIP_SET* set, /**< global SCIP settings */ 7737 SCIP_STAT* stat, /**< dynamic problem statistics */ 7738 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 7739 SCIP_EVENTFILTER* eventfilter, /**< event filter */ 7740 SCIP_LP* lp, /**< current LP */ 7741 SCIP_Bool root /**< bool whether the current node is the root */ 7742 ) 7743 { 7744 SCIP_REOPTNODE* reoptnode; 7745 SCIP_Bool infeasible; 7746 unsigned int id; 7747 int ncuts; 7748 7749 assert(reopt != NULL); 7750 assert(node != NULL); 7751 assert(sepastore != NULL); 7752 assert(blkmem != NULL); 7753 assert(set != NULL); 7754 assert(stat != NULL); 7755 assert(eventqueue != NULL); 7756 assert(eventfilter != NULL); 7757 assert(lp != NULL); 7758 7759 id = SCIPnodeGetReoptID(node); 7760 assert(id < reopt->reopttree->reoptnodessize); 7761 7762 /* skip nodes that are node part of the reoptimization tree */ 7763 if( id == 0 && SCIPnodeGetDepth(node) > 0 ) 7764 return SCIP_OKAY; 7765 7766 reoptnode = reopt->reopttree->reoptnodes[id]; 7767 assert(reoptnode != NULL); 7768 7769 ncuts = 0; 7770 for( int c = reoptnode->nconss-1; c >= 0; --c ) 7771 { 7772 SCIP_REOPTCONSDATA* cons; 7773 7774 cons = reoptnode->conss[c]; 7775 assert(cons != NULL); 7776 7777 if( cons->constype == REOPT_CONSTYPE_CUT ) 7778 { 7779 SCIP_ROW* cut; 7780 SCIP_COL** cols; 7781 SCIP_Real* vals; 7782 char cutname[SCIP_MAXSTRLEN]; 7783 int ncols; 7784 7785 SCIP_CALL( SCIPsetAllocBufferArray(set, &cols, cons->nvars) ); 7786 SCIP_CALL( SCIPsetAllocBufferArray(set, &vals, cons->nvars) ); 7787 7788 ncols = 0; 7789 for( int v = 0; v < cons->nvars; ++v ) 7790 { 7791 SCIP_VAR* transvar; 7792 7793 assert(SCIPvarIsOriginal(cons->vars[v])); 7794 7795 transvar = SCIPvarGetTransVar(cons->vars[v]); 7796 assert(transvar != NULL); 7797 assert(SCIPvarGetStatus(transvar) == SCIP_VARSTATUS_COLUMN); 7798 7799 vals[ncols] = cons->vals[v]; 7800 cols[ncols] = SCIPvarGetCol(transvar); 7801 assert(cols[ncols] != NULL); 7802 7803 ++ncols; 7804 } 7805 assert(ncols == cons->nvars); 7806 7807 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "reoptcut_%d_%d", id, ncuts); 7808 infeasible = FALSE; 7809 7810 if( id == 0 ) 7811 { 7812 SCIP_CALL( SCIProwCreate(&cut, blkmem, set, stat, cutname, ncols, cols, vals, cons->lhs, cons->rhs, 7813 SCIP_ROWORIGINTYPE_REOPT, NULL, FALSE, FALSE, TRUE) ); 7814 SCIP_CALL( SCIPcutpoolAddRow(cutpool, blkmem, set, stat, lp, cut) ); 7815 7816 SCIPsetDebugMsg(set, "add cut <%s> of size %d to cutpool, [lhs, rhs] = [%g,%g] to node %lld\n", cutname, 7817 ncols, cons->lhs, cons->rhs, SCIPnodeGetNumber(node)); 7818 } 7819 else 7820 { 7821 SCIP_CALL( SCIProwCreate(&cut, blkmem, set, stat, cutname, ncols, cols, vals, cons->lhs, cons->rhs, 7822 SCIP_ROWORIGINTYPE_REOPT, NULL, TRUE, TRUE, TRUE) ); 7823 SCIP_CALL( SCIPsepastoreAddCut(sepastore, blkmem, set, stat, eventqueue, eventfilter, lp, cut, FALSE, root, 7824 &infeasible) ); 7825 7826 SCIPsetDebugMsg(set, "add cut <%s> of size %d to sepastore, [lhs, rhs] = [%g,%g] to node %lld\n", cutname, 7827 ncols, cons->lhs, cons->rhs, SCIPnodeGetNumber(node)); 7828 } 7829 7830 SCIP_CALL( SCIProwRelease(&cut, blkmem, set, lp) ); 7831 7832 if( infeasible ) 7833 SCIPsetDebugMsg(set, "cut %d stored at node %" SCIP_LONGINT_FORMAT " (id: %u) is infeasible.\n", c, SCIPnodeGetNumber(node), id); 7834 else 7835 ++ncuts; 7836 7837 SCIPsetFreeBufferArray(set, &vals); 7838 SCIPsetFreeBufferArray(set, &cols); 7839 7840 BMSfreeBlockMemoryArrayNull(blkmem, &reoptnode->conss[c]->boundtypes, reoptnode->conss[c]->varssize); 7841 BMSfreeBlockMemoryArray(blkmem, &reoptnode->conss[c]->vals, reoptnode->conss[c]->varssize); 7842 BMSfreeBlockMemoryArray(blkmem, &reoptnode->conss[c]->vars, reoptnode->conss[c]->varssize); 7843 BMSfreeBlockMemory(blkmem, &reoptnode->conss[c]); /*lint !e866*/ 7844 --reoptnode->nconss; 7845 } 7846 else 7847 { 7848 #ifndef NDEBUG 7849 for( int i = c-1; i >= 0; --i ) 7850 assert(reoptnode->conss[i]->constype != REOPT_CONSTYPE_CUT); 7851 #endif 7852 break; 7853 } 7854 } 7855 7856 return SCIP_OKAY; 7857 } 7858 7859 /** check if the LP of the given node should be solved or not */ 7860 SCIP_Bool SCIPreoptGetSolveLP( 7861 SCIP_REOPT* reopt, /**< reoptimization data structure */ 7862 SCIP_SET* set, /**< global SCIP settings */ 7863 SCIP_NODE* node /**< node of the current search tree */ 7864 ) 7865 { 7866 unsigned int id; 7867 7868 assert(reopt != NULL); 7869 assert(node != NULL); 7870 7871 /* get the ID */ 7872 id = SCIPnodeGetReoptID(node); 7873 assert(id < reopt->reopttree->reoptnodessize); 7874 7875 /* return if the node is not part of the reoptimization tree */ 7876 if( SCIPnodeGetDepth(node) > 0 && id == 0 ) 7877 return TRUE; 7878 7879 /* return always true if the parameter is set to 1.0 */ 7880 if( SCIPsetIsGE(set, set->reopt_objsimrootlp, 1.0) ) 7881 return TRUE; 7882 7883 /* current node is the root */ 7884 if( id == 0 ) 7885 { 7886 if( reopt->reopttree->reoptnodes[0]->nchilds > 0 ) 7887 { 7888 /* the objective function has changed only slightly */ 7889 if( SCIPsetIsGE(set, reopt->simtolastobj, set->reopt_objsimrootlp) ) 7890 return FALSE; 7891 } 7892 } 7893 else 7894 { 7895 /* solve node LP if the node type is greater or equal to solvelp or there were too many bound changes at the current node */ 7896 if( reopt->reopttree->reoptnodes[id]->nvars < set->reopt_solvelpdiff && (int) SCIPnodeGetReopttype(node) < set->reopt_solvelp ) 7897 { 7898 assert(reopt->reopttree->reoptnodes[id]->nchilds > 0); 7899 return FALSE; 7900 } 7901 } 7902 7903 return TRUE; 7904 } 7905 7906 /** initialize an empty node */ 7907 void SCIPreoptnodeInit( 7908 SCIP_REOPTNODE* reoptnode, /**< node of the reopttree */ 7909 SCIP_SET* set /**< global SCIP settings */ 7910 ) 7911 { 7912 assert(reoptnode != NULL); 7913 assert(set != NULL); 7914 7915 reoptnode->conss = NULL; 7916 reoptnode->nconss = 0; 7917 reoptnode->consssize = 0; 7918 reoptnode->childids = NULL; 7919 reoptnode->allocchildmem = 0; 7920 reoptnode->nchilds = 0; 7921 reoptnode->nvars = 0; 7922 reoptnode->nafterdualvars = 0; 7923 reoptnode->parentID = 0; 7924 reoptnode->dualreds = FALSE; 7925 reoptnode->reopttype = (unsigned int)SCIP_REOPTTYPE_NONE; 7926 reoptnode->varssize = 0; 7927 reoptnode->afterdualvarssize = 0; 7928 reoptnode->vars = NULL; 7929 reoptnode->varbounds = NULL; 7930 reoptnode->varboundtypes = NULL; 7931 reoptnode->afterdualvars = NULL; 7932 reoptnode->afterdualvarbounds = NULL; 7933 reoptnode->afterdualvarboundtypes = NULL; 7934 reoptnode->dualredscur = NULL; 7935 reoptnode->dualredsnex = NULL; 7936 reoptnode->lowerbound = -SCIPsetInfinity(set); 7937 } 7938 7939 /** reset the given reoptimization node */ 7940 SCIP_RETCODE SCIPreoptnodeReset( 7941 SCIP_REOPT* reopt, /**< reoptimization data structure */ 7942 SCIP_SET* set, /**< global SCIP settings */ 7943 BMS_BLKMEM* blkmem, /**< block memory */ 7944 SCIP_REOPTNODE* reoptnode /**< reoptimization node */ 7945 ) 7946 { 7947 assert(reopt != NULL); 7948 assert(set != NULL); 7949 assert(blkmem != NULL); 7950 assert(reoptnode != NULL); 7951 7952 SCIP_CALL( reoptnodeReset(reoptnode, set, blkmem) ); 7953 7954 return SCIP_OKAY; 7955 } 7956 7957 /** delete the given reoptimization node */ 7958 SCIP_RETCODE SCIPreoptnodeDelete( 7959 SCIP_REOPTNODE** reoptnode, /**< pointer of reoptnode */ 7960 BMS_BLKMEM* blkmem /**< block memory */ 7961 ) 7962 { 7963 assert(reoptnode != NULL); 7964 assert(blkmem != NULL); 7965 7966 SCIP_CALL( reoptnodeDelete(reoptnode, blkmem) ); 7967 7968 return SCIP_OKAY; 7969 } 7970 7971 /** add a variable to a given reoptnode */ 7972 SCIP_RETCODE SCIPreoptnodeAddBndchg( 7973 SCIP_REOPTNODE* reoptnode, /**< node of the reopttree */ 7974 SCIP_SET* set, /**< global SCIP settings */ 7975 BMS_BLKMEM* blkmem, /**< block memory */ 7976 SCIP_VAR* var, /**< variable to add */ 7977 SCIP_Real val, /**< value of the variable */ 7978 SCIP_BOUNDTYPE boundtype /**< boundtype of the variable */ 7979 ) 7980 { 7981 int nvars; 7982 7983 assert(reoptnode != NULL); 7984 assert(var != NULL); 7985 assert(blkmem != NULL); 7986 7987 nvars = reoptnode->nvars; 7988 7989 SCIP_CALL( reoptnodeCheckMemory(reoptnode, set, blkmem, nvars + 1, 0, 0) ); 7990 7991 reoptnode->vars[nvars] = var; 7992 reoptnode->varbounds[nvars] = val; 7993 reoptnode->varboundtypes[nvars] = boundtype; 7994 ++reoptnode->nvars; 7995 7996 return SCIP_OKAY; 7997 } 7998 7999 /** add a constraint to a given reoptnode */ 8000 SCIP_RETCODE SCIPreoptnodeAddCons( 8001 SCIP_REOPTNODE* reoptnode, /**< node of the reopttree */ 8002 SCIP_SET* set, /**< global SCIP settings */ 8003 BMS_BLKMEM* blkmem, /**< block memory */ 8004 SCIP_VAR** vars, /**< variables which are part of the constraint */ 8005 SCIP_Real* bounds, /**< bounds of the variables */ 8006 SCIP_BOUNDTYPE* boundtypes, /**< boundtypes of the variables (or NULL is the constraint is a cut) */ 8007 SCIP_Real lhs, /**< lhs of the constraint */ 8008 SCIP_Real rhs, /**< rhs of the constraint */ 8009 int nvars, /**< number of variables */ 8010 REOPT_CONSTYPE constype, /**< type of the constraint */ 8011 SCIP_Bool linear /**< the given constraint has a linear representation */ 8012 ) 8013 { 8014 int nconss; 8015 8016 assert(reoptnode != NULL); 8017 assert(set != NULL); 8018 assert(vars != NULL); 8019 assert(bounds != NULL); 8020 assert(constype == REOPT_CONSTYPE_CUT || boundtypes != NULL); 8021 assert(nvars > 0); 8022 assert(blkmem != NULL); 8023 8024 /* the constraint can be interpreted as a normal bound change */ 8025 if( nvars == 1 && constype != REOPT_CONSTYPE_CUT ) 8026 { 8027 assert(constype == REOPT_CONSTYPE_DUALREDS || constype == REOPT_CONSTYPE_INFSUBTREE); 8028 8029 SCIPsetDebugMsg(set, "-> constraint has size 1 -> save as normal bound change.\n"); 8030 8031 if( SCIPvarGetType(vars[0]) == SCIP_VARTYPE_BINARY ) 8032 { 8033 SCIP_CALL( SCIPreoptnodeAddBndchg(reoptnode, set, blkmem, vars[0], 1-bounds[0], 8034 1-bounds[0] == 1 ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER) ); 8035 } 8036 else 8037 { 8038 SCIP_Real newbound; 8039 SCIP_BOUNDTYPE newboundtype; 8040 8041 assert(SCIPvarGetType(vars[0]) == SCIP_VARTYPE_INTEGER); 8042 assert(boundtypes != NULL); 8043 8044 if( boundtypes[0] == SCIP_BOUNDTYPE_UPPER ) 8045 { 8046 newbound = bounds[0] + 1.0; 8047 assert(SCIPsetIsLE(set, newbound, SCIPvarGetUbLocal(vars[0]))); 8048 8049 newboundtype = SCIP_BOUNDTYPE_LOWER; 8050 } 8051 else 8052 { 8053 newbound = bounds[0] - 1.0; 8054 assert(SCIPsetIsGE(set, newbound, SCIPvarGetLbLocal(vars[0]))); 8055 8056 newboundtype = SCIP_BOUNDTYPE_UPPER; 8057 } 8058 8059 SCIP_CALL( SCIPreoptnodeAddBndchg(reoptnode, set, blkmem, vars[0], newbound, newboundtype) ); 8060 } 8061 } 8062 else 8063 { 8064 nconss = reoptnode->nconss; 8065 8066 SCIP_CALL( reoptnodeCheckMemory(reoptnode, set, blkmem, 0, 0, nconss+1) ); 8067 8068 /* create the constraint */ 8069 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &reoptnode->conss[nconss]) ); /*lint !e866*/ 8070 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reoptnode->conss[nconss]->vars, vars, nvars) ); 8071 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reoptnode->conss[nconss]->vals, bounds, nvars) ); 8072 if( boundtypes != NULL ) 8073 { 8074 assert(!linear); 8075 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &reoptnode->conss[nconss]->boundtypes, boundtypes, nvars) ); 8076 } 8077 else 8078 reoptnode->conss[nconss]->boundtypes = NULL; 8079 8080 reoptnode->conss[nconss]->varssize = nvars; 8081 reoptnode->conss[nconss]->nvars = nvars; 8082 reoptnode->conss[nconss]->lhs = lhs; 8083 reoptnode->conss[nconss]->rhs = rhs; 8084 reoptnode->conss[nconss]->constype = constype; 8085 reoptnode->conss[nconss]->linear = linear; 8086 ++reoptnode->nconss; 8087 } 8088 return SCIP_OKAY; 8089 } 8090 8091 /** add a constraint to the reoptimization data structure */ 8092 SCIP_RETCODE SCIPreoptAddCons( 8093 SCIP_REOPT* reopt, /**< reoptimization data structure */ 8094 SCIP_SET* set, /**< global SCIP settings */ 8095 BMS_BLKMEM* blkmem, /**< block memory */ 8096 SCIP_CONS* cons /**< constraint to add */ 8097 ) 8098 { 8099 assert(reopt != NULL); 8100 assert(set != NULL); 8101 assert(blkmem != NULL); 8102 assert(cons != NULL); 8103 8104 #ifdef SCIP_MORE_DEBUG 8105 SCIPsetDebugMsg(set, "add cons <%s> to reoptimization data\n", SCIPconsGetName(cons)); 8106 #endif 8107 8108 /* check memory */ 8109 if( reopt->addedconsssize == 0 ) 8110 { 8111 assert(reopt->addedconss == NULL); 8112 8113 reopt->addedconsssize = 10; 8114 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &reopt->addedconss, reopt->addedconsssize) ); 8115 } 8116 else if( reopt->naddedconss == reopt->addedconsssize ) 8117 { 8118 int newsize = SCIPsetCalcMemGrowSize(set, reopt->addedconsssize+1); 8119 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &reopt->addedconss, reopt->addedconsssize, newsize) ); 8120 8121 /* clear the array */ 8122 BMSclearMemoryArray(&reopt->addedconss[reopt->addedconsssize], newsize - reopt->addedconsssize); /*lint !e866 */ 8123 8124 reopt->addedconsssize = newsize; 8125 } 8126 assert(reopt->naddedconss < reopt->addedconsssize); 8127 assert(reopt->addedconss[reopt->naddedconss] == NULL); 8128 8129 reopt->addedconss[reopt->naddedconss] = cons; 8130 reopt->consadded = TRUE; 8131 ++reopt->naddedconss; 8132 8133 /* capture the constraint */ 8134 SCIPconsCapture(cons); 8135 8136 return SCIP_OKAY; 8137 } 8138 8139 /** save global lower and upper bounds 8140 * 8141 * @note this method should only be called once, i.e., after fishing presolving of the first problem 8142 */ 8143 SCIP_RETCODE SCIPreoptSaveGlobalBounds( 8144 SCIP_REOPT* reopt, /**< reoptimization data structure */ 8145 SCIP_PROB* transprob, /**< transformed problem data */ 8146 BMS_BLKMEM* blkmem /**< block memory */ 8147 ) 8148 { 8149 SCIP_VAR** vars; 8150 int nvars; 8151 8152 assert(reopt != NULL); 8153 assert(transprob != NULL); 8154 assert(reopt->glblb == NULL && reopt->glbub == NULL); 8155 8156 nvars = SCIPprobGetNVars(transprob); 8157 vars = SCIPprobGetVars(transprob); 8158 8159 /* create hashmaps */ 8160 SCIP_CALL( SCIPhashmapCreate(&reopt->glbub, blkmem, nvars) ); 8161 SCIP_CALL( SCIPhashmapCreate(&reopt->glblb, blkmem, nvars) ); 8162 8163 /* store the global bounds */ 8164 for( int i = 0; i < nvars; ++i ) 8165 { 8166 assert(!SCIPhashmapExists(reopt->glblb, (void*)vars[i])); 8167 assert(!SCIPhashmapExists(reopt->glbub, (void*)vars[i])); 8168 8169 SCIP_CALL( SCIPhashmapInsertReal(reopt->glblb, (void*)vars[i], SCIPvarGetLbGlobal(vars[i])) ); 8170 SCIP_CALL( SCIPhashmapInsertReal(reopt->glbub, (void*)vars[i], SCIPvarGetUbGlobal(vars[i])) ); 8171 } 8172 8173 return SCIP_OKAY; 8174 } 8175 8176 /** save active constraints 8177 * 8178 * @note this method can only called once, i.e., after fishing presolving of the first problem 8179 */ 8180 SCIP_RETCODE SCIPreoptSaveActiveConss( 8181 SCIP_REOPT* reopt, /**< reoptimization data structure */ 8182 SCIP_SET* set, /**< global SCIP settings */ 8183 SCIP_PROB* transprob, /**< transformed problem data */ 8184 BMS_BLKMEM* blkmem /**< block memory */ 8185 ) 8186 { 8187 SCIP_CONS** conss; 8188 int nconss; 8189 8190 assert(reopt != NULL); 8191 assert(transprob != NULL); 8192 assert(reopt->activeconss == NULL); 8193 assert(reopt->activeconssset == NULL); 8194 assert(reopt->nactiveconss == 0); 8195 assert(reopt->nmaxactiveconss == 0); 8196 8197 conss = transprob->conss; 8198 nconss = transprob->nconss; 8199 8200 SCIPsetDebugMsg(set, "save %d active conss\n", nconss); 8201 8202 /* create hashset and array */ 8203 SCIP_CALL( SCIPhashsetCreate(&reopt->activeconssset, blkmem, nconss) ); 8204 SCIP_CALL( ensureActiveconssSize(reopt, set, blkmem, nconss) ); 8205 8206 for( int i = 0; i < nconss; ++i ) 8207 { 8208 assert(SCIPconsIsActive(conss[i])); 8209 assert(!SCIPhashsetExists(reopt->activeconssset, (void*)conss[i])); 8210 8211 SCIPconsCapture(conss[i]); 8212 SCIP_CALL( SCIPhashsetInsert(reopt->activeconssset, blkmem, (void*)conss[i]) ); 8213 reopt->activeconss[reopt->nactiveconss++] = conss[i]; 8214 } 8215 8216 return SCIP_OKAY; 8217 } 8218 8219 /** installs global lower and upper bounds */ 8220 SCIP_RETCODE SCIPreoptInstallBounds( 8221 SCIP_REOPT* reopt, /**< reoptimization data structure */ 8222 SCIP_SET* set, /**< global SCIP settings */ 8223 SCIP_STAT* stat, /**< dynamic SCIP statistics */ 8224 SCIP_PROB* transprob, /**< transformed problem data */ 8225 SCIP_LP* lp, /**< current LP data */ 8226 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 8227 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 8228 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 8229 BMS_BLKMEM* blkmem /**< block memory */ 8230 ) 8231 { 8232 SCIP_VAR** vars; 8233 int nvars; 8234 8235 assert(reopt != NULL); 8236 assert(transprob != NULL); 8237 assert(reopt->glblb != NULL && reopt->glbub != NULL); 8238 assert(SCIPprobIsTransformed(transprob)); 8239 8240 nvars = SCIPprobGetNVars(transprob); 8241 vars = SCIPprobGetVars(transprob); 8242 8243 /* install global lower and upper bounds */ 8244 for( int i = 0; i < nvars; ++i ) 8245 { 8246 SCIP_Real lb; 8247 SCIP_Real ub; 8248 8249 assert(SCIPhashmapExists(reopt->glblb, (void*)vars[i])); 8250 assert(SCIPhashmapExists(reopt->glbub, (void*)vars[i])); 8251 8252 lb = SCIPhashmapGetImageReal(reopt->glblb, (void*)vars[i]); 8253 ub = SCIPhashmapGetImageReal(reopt->glbub, (void*)vars[i]); 8254 assert(lb < SCIP_INVALID && ub < SCIP_INVALID); 8255 8256 /* reset the global bounds back */ 8257 SCIP_CALL( SCIPvarChgLbGlobal(vars[i], blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, lb) ); 8258 SCIP_CALL( SCIPvarChgUbGlobal(vars[i], blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, ub) ); 8259 8260 /* reset the local bounds back */ 8261 SCIP_CALL( SCIPvarChgLbLocal(vars[i], blkmem, set, stat, lp, branchcand, eventqueue, lb) ); 8262 SCIP_CALL( SCIPvarChgUbLocal(vars[i], blkmem, set, stat, lp, branchcand, eventqueue, ub) ); 8263 } 8264 8265 return SCIP_OKAY; 8266 } 8267 8268 /** reactivate globally valid constraints that were deactivated and necessary to ensure correctness */ 8269 SCIP_RETCODE SCIPreoptResetActiveConss( 8270 SCIP_REOPT* reopt, /**< reoptimization data structure */ 8271 SCIP_SET* set, /**< global SCIP settings */ 8272 SCIP_STAT* stat /**< dynamic SCIP statistics */ 8273 ) 8274 { 8275 assert(reopt != NULL); 8276 assert(reopt->activeconss != NULL || reopt->nmaxactiveconss == 0); 8277 assert(reopt->activeconssset != NULL || reopt->nmaxactiveconss == 0); 8278 assert(reopt->nmaxactiveconss >= 0); 8279 8280 SCIPsetDebugMsg(set, "Reset %d active conss.\n", reopt->nactiveconss); 8281 8282 /* loop over all storeed active constraints and reactivate deactivated constraints */ 8283 for( int i = 0; i < reopt->nactiveconss; ++i ) 8284 { 8285 SCIP_CONS* cons; 8286 8287 assert(reopt->activeconss != NULL); 8288 cons = reopt->activeconss[i]; 8289 assert(cons != NULL); 8290 assert(SCIPhashsetExists(reopt->activeconssset, cons)); 8291 8292 /* it can happen that the constraint got globally deleted */ 8293 if( SCIPconsIsDeleted(cons) ) 8294 cons->deleted = FALSE; 8295 8296 /* to ensure that the constraint will be added to all the data structures we need to deactivate the 8297 * constraint first. 8298 */ 8299 if( SCIPconsIsActive(cons) ) 8300 { 8301 SCIP_CALL( SCIPconsDeactivate(cons, set, stat) ); 8302 } 8303 SCIP_CALL( SCIPconsActivate(cons, set, stat, -1, TRUE) ); 8304 } 8305 8306 return SCIP_OKAY; 8307 } 8308 8309 /** returns whether a constraint is necessary to ensure correctness and cannot be deleted */ 8310 SCIP_Bool SCIPreoptConsCanBeDeleted( 8311 SCIP_REOPT* reopt, /**< reoptimization data structure */ 8312 SCIP_CONS* cons /**< problem constraint */ 8313 ) 8314 { 8315 assert(reopt != NULL); 8316 assert(cons != NULL); 8317 8318 /* the hashset is not initialized, we can delete all constraints */ 8319 if( reopt->activeconss == NULL ) 8320 return TRUE; 8321 8322 return !SCIPhashsetExists(reopt->activeconssset, (void*)cons); 8323 } 8324