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 prob.c 26 * @ingroup OTHER_CFILES 27 * @brief Methods and datastructures for storing and manipulating the main problem 28 * @author Tobias Achterberg 29 */ 30 31 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 32 33 #include "scip/branch.h" 34 #include "scip/conflictstore.h" 35 #include "scip/cons.h" 36 #include "scip/event.h" 37 #include "scip/lp.h" 38 #include "scip/primal.h" 39 #include "scip/prob.h" 40 #include "scip/pub_cons.h" 41 #include "scip/pub_lp.h" 42 #include "scip/pub_message.h" 43 #include "scip/pub_misc.h" 44 #include "scip/pub_misc_sort.h" 45 #include "scip/pub_var.h" 46 #include "scip/set.h" 47 #include "scip/stat.h" 48 #include "scip/struct_cons.h" 49 #include "scip/struct_lp.h" 50 #include "scip/struct_prob.h" 51 #include "scip/struct_set.h" 52 #include "scip/struct_stat.h" 53 #include "scip/struct_var.h" 54 #include "scip/var.h" 55 #include <string.h> 56 57 58 #define OBJSCALE_MAXDNOM 1000000LL /**< maximal denominator in objective integral scaling */ 59 #define OBJSCALE_MAXSCALE 1000000.0 /**< maximal scalar to reach objective integrality */ 60 #define OBJSCALE_MAXFINALSCALE 1000.0 /**< maximal final value to apply as scaling */ 61 62 63 64 /* 65 * dymanic memory arrays 66 */ 67 68 /** resizes vars array to be able to store at least num entries */ 69 static 70 SCIP_RETCODE probEnsureVarsMem( 71 SCIP_PROB* prob, /**< problem data */ 72 SCIP_SET* set, /**< global SCIP settings */ 73 int num /**< minimal number of slots in array */ 74 ) 75 { 76 assert(prob != NULL); 77 assert(set != NULL); 78 79 if( num > prob->varssize ) 80 { 81 int newsize; 82 83 newsize = SCIPsetCalcMemGrowSize(set, num); 84 SCIP_ALLOC( BMSreallocMemoryArray(&prob->vars, newsize) ); 85 prob->varssize = newsize; 86 } 87 assert(num <= prob->varssize); 88 89 return SCIP_OKAY; 90 } 91 92 /** resizes fixedvars array to be able to store at least num entries */ 93 static 94 SCIP_RETCODE probEnsureFixedvarsMem( 95 SCIP_PROB* prob, /**< problem data */ 96 SCIP_SET* set, /**< global SCIP settings */ 97 int num /**< minimal number of slots in array */ 98 ) 99 { 100 assert(prob != NULL); 101 assert(set != NULL); 102 103 if( num > prob->fixedvarssize ) 104 { 105 int newsize; 106 107 newsize = SCIPsetCalcMemGrowSize(set, num); 108 SCIP_ALLOC( BMSreallocMemoryArray(&prob->fixedvars, newsize) ); 109 prob->fixedvarssize = newsize; 110 } 111 assert(num <= prob->fixedvarssize); 112 113 return SCIP_OKAY; 114 } 115 116 /** resizes deletedvars array to be able to store at least num entries */ 117 static 118 SCIP_RETCODE probEnsureDeletedvarsMem( 119 SCIP_PROB* prob, /**< problem data */ 120 SCIP_SET* set, /**< global SCIP settings */ 121 int num /**< minimal number of slots in array */ 122 ) 123 { 124 assert(prob != NULL); 125 assert(set != NULL); 126 127 if( num > prob->deletedvarssize ) 128 { 129 int newsize; 130 131 newsize = SCIPsetCalcMemGrowSize(set, num); 132 SCIP_ALLOC( BMSreallocMemoryArray(&prob->deletedvars, newsize) ); 133 prob->deletedvarssize = newsize; 134 } 135 assert(num <= prob->deletedvarssize); 136 137 return SCIP_OKAY; 138 } 139 140 /** resizes conss array to be able to store at least num entries */ 141 static 142 SCIP_RETCODE probEnsureConssMem( 143 SCIP_PROB* prob, /**< problem data */ 144 SCIP_SET* set, /**< global SCIP settings */ 145 int num /**< minimal number of slots in array */ 146 ) 147 { 148 assert(prob != NULL); 149 assert(set != NULL); 150 151 if( num > prob->consssize ) 152 { 153 int newsize; 154 155 newsize = SCIPsetCalcMemGrowSize(set, num); 156 SCIP_ALLOC( BMSreallocMemoryArray(&prob->conss, newsize) ); 157 /* resize sorted original constraints if they exist */ 158 if( prob->origcheckconss != NULL ) 159 { 160 SCIP_ALLOC( BMSreallocMemoryArray(&prob->origcheckconss, newsize) ); 161 } 162 prob->consssize = newsize; 163 } 164 assert(num <= prob->consssize); 165 166 return SCIP_OKAY; 167 } 168 169 /** returns whether the constraint has a name */ 170 static 171 SCIP_Bool consHasName( 172 SCIP_CONS* cons /**< constraint */ 173 ) 174 { 175 const char* name; 176 177 name = SCIPconsGetName(cons); 178 179 return (name != NULL && name[0] != '\0'); 180 } 181 182 /** returns whether the variable has a name */ 183 static 184 SCIP_Bool varHasName( 185 SCIP_VAR* var /**< variable */ 186 ) 187 { 188 const char* name; 189 190 name = SCIPvarGetName(var); 191 192 return (name != NULL && name[0] != '\0'); 193 } 194 195 196 197 /* 198 * problem creation 199 */ 200 201 /** creates problem data structure by copying the source problem 202 * 203 * If the problem type requires the use of variable pricers, these pricers should be activated with calls 204 * to SCIPactivatePricer(). These pricers are automatically deactivated, when the problem is freed. 205 */ 206 SCIP_RETCODE SCIPprobCopy( 207 SCIP_PROB** prob, /**< pointer to problem data structure */ 208 BMS_BLKMEM* blkmem, /**< block memory */ 209 SCIP_SET* set, /**< global SCIP settings */ 210 const char* name, /**< problem name */ 211 SCIP* sourcescip, /**< source SCIP data structure */ 212 SCIP_PROB* sourceprob, /**< source problem structure */ 213 SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of source variables corresponding 214 * target variables */ 215 SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of source constraints to the corresponding 216 * target constraints */ 217 SCIP_Bool original, /**< copy original or transformed problem? */ 218 SCIP_Bool global /**< create a global or a local copy? */ 219 ) 220 { 221 SCIP_PROBDATA* targetdata = NULL; 222 SCIP_RESULT result = SCIP_DIDNOTRUN; 223 224 assert(prob != NULL); 225 assert(set != NULL); 226 assert(blkmem != NULL); 227 assert(sourcescip != NULL); 228 assert(sourceprob != NULL); 229 assert(varmap != NULL); 230 assert(consmap != NULL); 231 232 /* create problem and initialize callbacks with NULL */ 233 SCIP_CALL( SCIPprobCreate(prob, blkmem, set, name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, FALSE) ); 234 235 /* call user copy callback method */ 236 if( sourceprob->probdata != NULL && sourceprob->probcopy != NULL ) 237 { 238 SCIP_CALL( sourceprob->probcopy(set->scip, sourcescip, sourceprob->probdata, varmap, consmap, &targetdata, original, global, &result) ); 239 240 /* evaluate result */ 241 if( result != SCIP_DIDNOTRUN && result != SCIP_SUCCESS ) 242 { 243 SCIPerrorMessage("probdata copying method returned invalid result <%d>\n", result); 244 return SCIP_INVALIDRESULT; 245 } 246 247 assert(targetdata == NULL || result == SCIP_SUCCESS); 248 249 /* if copying was successful, add data and callbacks */ 250 if( result == SCIP_SUCCESS ) 251 { 252 assert( targetdata != NULL ); 253 (*prob)->probdelorig = sourceprob->probdelorig; 254 (*prob)->probtrans = sourceprob->probtrans; 255 (*prob)->probdeltrans = sourceprob->probdeltrans; 256 (*prob)->probinitsol = sourceprob->probinitsol; 257 (*prob)->probexitsol = sourceprob->probexitsol; 258 (*prob)->probcopy = sourceprob->probcopy; 259 (*prob)->probdata = targetdata; 260 } 261 } 262 263 return SCIP_OKAY; 264 } 265 266 /** creates problem data structure 267 * If the problem type requires the use of variable pricers, these pricers should be activated with calls 268 * to SCIPactivatePricer(). These pricers are automatically deactivated, when the problem is freed. 269 */ 270 SCIP_RETCODE SCIPprobCreate( 271 SCIP_PROB** prob, /**< pointer to problem data structure */ 272 BMS_BLKMEM* blkmem, /**< block memory */ 273 SCIP_SET* set, /**< global SCIP settings */ 274 const char* name, /**< problem name */ 275 SCIP_DECL_PROBDELORIG ((*probdelorig)), /**< frees user data of original problem */ 276 SCIP_DECL_PROBTRANS ((*probtrans)), /**< creates user data of transformed problem by transforming original user data */ 277 SCIP_DECL_PROBDELTRANS((*probdeltrans)), /**< frees user data of transformed problem */ 278 SCIP_DECL_PROBINITSOL ((*probinitsol)), /**< solving process initialization method of transformed data */ 279 SCIP_DECL_PROBEXITSOL ((*probexitsol)), /**< solving process deinitialization method of transformed data */ 280 SCIP_DECL_PROBCOPY ((*probcopy)), /**< copies user data if you want to copy it to a subscip, or NULL */ 281 SCIP_PROBDATA* probdata, /**< user problem data set by the reader */ 282 SCIP_Bool transformed /**< is this the transformed problem? */ 283 ) 284 { 285 assert(prob != NULL); 286 287 SCIP_ALLOC( BMSallocMemory(prob) ); 288 SCIP_ALLOC( BMSduplicateMemoryArray(&(*prob)->name, name, strlen(name)+1) ); 289 290 (*prob)->probdata = probdata; 291 (*prob)->probcopy = probcopy; 292 (*prob)->probdelorig = probdelorig; 293 (*prob)->probtrans = probtrans; 294 (*prob)->probdeltrans = probdeltrans; 295 (*prob)->probinitsol = probinitsol; 296 (*prob)->probexitsol = probexitsol; 297 if( set->misc_usevartable ) 298 { 299 SCIP_CALL( SCIPhashtableCreate(&(*prob)->varnames, blkmem, 300 (set->misc_usesmalltables ? SCIP_HASHSIZE_NAMES_SMALL : SCIP_HASHSIZE_NAMES), 301 SCIPhashGetKeyVar, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) ); 302 } 303 else 304 (*prob)->varnames = NULL; 305 (*prob)->vars = NULL; 306 (*prob)->varssize = 0; 307 (*prob)->nvars = 0; 308 (*prob)->nbinvars = 0; 309 (*prob)->nintvars = 0; 310 (*prob)->nimplvars = 0; 311 (*prob)->ncontvars = 0; 312 (*prob)->ncolvars = 0; 313 (*prob)->fixedvars = NULL; 314 (*prob)->fixedvarssize = 0; 315 (*prob)->nfixedvars = 0; 316 (*prob)->deletedvars = NULL; 317 (*prob)->deletedvarssize = 0; 318 (*prob)->ndeletedvars = 0; 319 (*prob)->nobjvars = 0; 320 if( set->misc_useconstable ) 321 { 322 SCIP_CALL( SCIPhashtableCreate(&(*prob)->consnames, blkmem, 323 (set->misc_usesmalltables ? SCIP_HASHSIZE_NAMES_SMALL : SCIP_HASHSIZE_NAMES), 324 SCIPhashGetKeyCons, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) ); 325 } 326 else 327 (*prob)->consnames = NULL; 328 (*prob)->conss = NULL; 329 (*prob)->origcheckconss = NULL; 330 (*prob)->consssize = 0; 331 (*prob)->nconss = 0; 332 (*prob)->maxnconss = 0; 333 (*prob)->startnvars = 0; 334 (*prob)->startnconss = 0; 335 (*prob)->objsense = SCIP_OBJSENSE_MINIMIZE; 336 (*prob)->objoffset = 0.0; 337 (*prob)->objscale = 1.0; 338 (*prob)->objlim = SCIP_INVALID; 339 (*prob)->dualbound = SCIP_INVALID; 340 (*prob)->objisintegral = FALSE; 341 (*prob)->transformed = transformed; 342 (*prob)->nlpenabled = FALSE; 343 (*prob)->permuted = FALSE; 344 (*prob)->consschecksorted = FALSE; 345 (*prob)->conscompression = FALSE; 346 347 return SCIP_OKAY; 348 } 349 350 /** sets callback to free user data of original problem */ 351 void SCIPprobSetDelorig( 352 SCIP_PROB* prob, /**< problem */ 353 SCIP_DECL_PROBDELORIG ((*probdelorig)) /**< frees user data of original problem */ 354 ) 355 { 356 assert(prob != NULL); 357 358 prob->probdelorig = probdelorig; 359 } 360 361 /** sets callback to create user data of transformed problem by transforming original user data */ 362 void SCIPprobSetTrans( 363 SCIP_PROB* prob, /**< problem */ 364 SCIP_DECL_PROBTRANS ((*probtrans)) /**< creates user data of transformed problem by transforming original user data */ 365 ) 366 { 367 assert(prob != NULL); 368 369 prob->probtrans = probtrans; 370 } 371 372 /** sets callback to free user data of transformed problem */ 373 void SCIPprobSetDeltrans( 374 SCIP_PROB* prob, /**< problem */ 375 SCIP_DECL_PROBDELTRANS((*probdeltrans)) /**< frees user data of transformed problem */ 376 ) 377 { 378 assert(prob != NULL); 379 380 prob->probdeltrans = probdeltrans; 381 } 382 383 /** sets solving process initialization callback of transformed data */ 384 void SCIPprobSetInitsol( 385 SCIP_PROB* prob, /**< problem */ 386 SCIP_DECL_PROBINITSOL ((*probinitsol)) /**< solving process initialization callback of transformed data */ 387 ) 388 { 389 assert(prob != NULL); 390 391 prob->probinitsol= probinitsol; 392 } 393 394 /** sets solving process deinitialization callback of transformed data */ 395 void SCIPprobSetExitsol( 396 SCIP_PROB* prob, /**< problem */ 397 SCIP_DECL_PROBEXITSOL ((*probexitsol)) /**< solving process deinitialization callback of transformed data */ 398 ) 399 { 400 assert(prob != NULL); 401 402 prob->probexitsol= probexitsol; 403 } 404 405 /** sets callback to copy user data to copy it to a subscip, or NULL */ 406 void SCIPprobSetCopy( 407 SCIP_PROB* prob, /**< problem */ 408 SCIP_DECL_PROBCOPY ((*probcopy)) /**< copies user data if you want to copy it to a subscip, or NULL */ 409 ) 410 { 411 assert(prob != NULL); 412 413 prob->probcopy= probcopy; 414 } 415 416 /** frees problem data structure */ 417 SCIP_RETCODE SCIPprobFree( 418 SCIP_PROB** prob, /**< pointer to problem data structure */ 419 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 420 BMS_BLKMEM* blkmem, /**< block memory buffer */ 421 SCIP_SET* set, /**< global SCIP settings */ 422 SCIP_STAT* stat, /**< dynamic problem statistics */ 423 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 424 SCIP_LP* lp /**< current LP data (or NULL, if it's the original problem) */ 425 ) 426 { 427 int v; 428 #ifndef NDEBUG 429 SCIP_Bool unreleasedvar = FALSE; 430 #endif 431 432 assert(prob != NULL); 433 assert(*prob != NULL); 434 assert(set != NULL); 435 436 /* remove all constraints from the problem */ 437 while( (*prob)->nconss > 0 ) 438 { 439 /*@todo for debug mode it even might sense, to sort them downwards after their arraypos */ 440 assert((*prob)->conss != NULL); 441 SCIP_CALL( SCIPprobDelCons(*prob, blkmem, set, stat, (*prob)->conss[(*prob)->nconss - 1]) ); 442 } 443 444 if( (*prob)->transformed ) 445 { 446 int h; 447 448 /* unlock variables for all constraint handlers that don't need constraints */ 449 for( h = 0; h < set->nconshdlrs; ++h ) 450 { 451 if( !SCIPconshdlrNeedsCons(set->conshdlrs[h]) ) 452 { 453 SCIP_CALL( SCIPconshdlrUnlockVars(set->conshdlrs[h], set) ); 454 } 455 } 456 } 457 458 /* free constraint array */ 459 BMSfreeMemoryArrayNull(&(*prob)->origcheckconss); 460 BMSfreeMemoryArrayNull(&(*prob)->conss); 461 462 /* free user problem data */ 463 if( (*prob)->transformed ) 464 { 465 if( (*prob)->probdeltrans != NULL ) 466 { 467 SCIP_CALL( (*prob)->probdeltrans(set->scip, &(*prob)->probdata) ); 468 } 469 } 470 else 471 { 472 if( (*prob)->probdelorig != NULL ) 473 { 474 SCIP_CALL( (*prob)->probdelorig(set->scip, &(*prob)->probdata) ); 475 } 476 } 477 478 /* release problem variables */ 479 for( v = (*prob)->nvars - 1; v >= 0; --v ) 480 { 481 assert(SCIPvarGetProbindex((*prob)->vars[v]) >= 0); 482 483 if( SCIPvarGetNUses((*prob)->vars[v]) > 1 ) 484 { 485 SCIPmessageFPrintWarning(messagehdlr, "%s variable <%s> not released when freeing SCIP problem <%s>.\n", 486 (*prob)->transformed ? "Transformed" : "Original", SCIPvarGetName((*prob)->vars[v]), SCIPprobGetName(*prob)); 487 #ifndef NDEBUG 488 unreleasedvar = TRUE; 489 #endif 490 } 491 492 SCIP_CALL( SCIPvarRemove((*prob)->vars[v], blkmem, NULL, set, TRUE) ); 493 SCIP_CALL( SCIPvarRelease(&(*prob)->vars[v], blkmem, set, eventqueue, lp) ); 494 } 495 BMSfreeMemoryArrayNull(&(*prob)->vars); 496 497 /* release fixed problem variables */ 498 for( v = (*prob)->nfixedvars - 1; v >= 0; --v ) 499 { 500 assert(SCIPvarGetProbindex((*prob)->fixedvars[v]) == -1); 501 502 if( SCIPvarGetNUses((*prob)->fixedvars[v]) > 1 ) 503 { 504 SCIPmessageFPrintWarning(messagehdlr, "%s variable <%s> not released when freeing SCIP problem <%s>.\n", 505 (*prob)->transformed ? "Transformed" : "Original", SCIPvarGetName((*prob)->fixedvars[v]), SCIPprobGetName(*prob)); 506 #ifndef NDEBUG 507 unreleasedvar = TRUE; 508 #endif 509 } 510 511 SCIP_CALL( SCIPvarRelease(&(*prob)->fixedvars[v], blkmem, set, eventqueue, lp) ); 512 } 513 BMSfreeMemoryArrayNull(&(*prob)->fixedvars); 514 515 assert(! unreleasedvar); 516 517 /* free deleted problem variables array */ 518 BMSfreeMemoryArrayNull(&(*prob)->deletedvars); 519 520 /* free hash tables for names */ 521 if( (*prob)->varnames != NULL ) 522 { 523 SCIPhashtableFree(&(*prob)->varnames); 524 } 525 if( (*prob)->consnames != NULL ) 526 { 527 SCIPhashtableFree(&(*prob)->consnames); 528 } 529 BMSfreeMemoryArray(&(*prob)->name); 530 BMSfreeMemory(prob); 531 532 return SCIP_OKAY; 533 } 534 535 /** transform problem data into normalized form */ 536 SCIP_RETCODE SCIPprobTransform( 537 SCIP_PROB* source, /**< problem to transform */ 538 BMS_BLKMEM* blkmem, /**< block memory buffer */ 539 SCIP_SET* set, /**< global SCIP settings */ 540 SCIP_STAT* stat, /**< problem statistics */ 541 SCIP_PRIMAL* primal, /**< primal data */ 542 SCIP_TREE* tree, /**< branch and bound tree */ 543 SCIP_REOPT* reopt, /**< reoptimization data structure */ 544 SCIP_LP* lp, /**< current LP data */ 545 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 546 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 547 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 548 SCIP_CONFLICTSTORE* conflictstore, /**< conflict store */ 549 SCIP_PROB** target /**< pointer to target problem data structure */ 550 ) 551 { 552 SCIP_VAR* targetvar; 553 SCIP_CONS* targetcons; 554 char transname[SCIP_MAXSTRLEN]; 555 int v; 556 int c; 557 int h; 558 559 assert(set != NULL); 560 assert(source != NULL); 561 assert(blkmem != NULL); 562 assert(target != NULL); 563 564 SCIPsetDebugMsg(set, "transform problem: original has %d variables\n", source->nvars); 565 566 /* create target problem data (probdelorig and probtrans are not needed, probdata is set later) */ 567 (void) SCIPsnprintf(transname, SCIP_MAXSTRLEN, "t_%s", source->name); 568 SCIP_CALL( SCIPprobCreate(target, blkmem, set, transname, source->probdelorig, source->probtrans, source->probdeltrans, 569 source->probinitsol, source->probexitsol, source->probcopy, NULL, TRUE) ); 570 SCIPprobSetObjsense(*target, source->objsense); 571 572 /* transform objective limit */ 573 if( source->objlim < SCIP_INVALID ) 574 SCIPprobSetObjlim(*target, source->objlim); 575 576 /* transform dual bound */ 577 if( source->dualbound < SCIP_INVALID ) 578 SCIPprobSetDualbound(*target, source->dualbound); 579 580 /* transform and copy all variables to target problem */ 581 SCIP_CALL( probEnsureVarsMem(*target, set, source->nvars) ); 582 for( v = 0; v < source->nvars; ++v ) 583 { 584 SCIP_CALL( SCIPvarTransform(source->vars[v], blkmem, set, stat, source->objsense, &targetvar) ); 585 SCIP_CALL( SCIPprobAddVar(*target, blkmem, set, lp, branchcand, eventfilter, eventqueue, targetvar) ); 586 SCIP_CALL( SCIPvarRelease(&targetvar, blkmem, set, eventqueue, NULL) ); 587 } 588 assert((*target)->nvars == source->nvars); 589 assert((*target)->nobjvars == SCIPprobGetNObjVars(*target, set)); 590 591 /* call user data transformation */ 592 if( source->probtrans != NULL ) 593 { 594 SCIP_CALL( source->probtrans(set->scip, source->probdata, &(*target)->probdata) ); 595 } 596 else 597 (*target)->probdata = source->probdata; 598 599 /* transform and copy all constraints to target problem */ 600 for( c = 0; c < source->nconss; ++c ) 601 { 602 SCIP_CALL( SCIPconsTransform(source->conss[c], blkmem, set, &targetcons) ); 603 SCIP_CALL( SCIPprobAddCons(*target, set, stat, targetcons) ); 604 SCIP_CALL( SCIPconsRelease(&targetcons, blkmem, set) ); 605 } 606 607 /* lock variables for all constraint handlers that don't need constraints */ 608 for( h = 0; h < set->nconshdlrs; ++h ) 609 { 610 if( !SCIPconshdlrNeedsCons(set->conshdlrs[h]) ) 611 { 612 SCIP_CALL( SCIPconshdlrLockVars(set->conshdlrs[h], set) ); 613 } 614 } 615 616 /* objective value is always integral, iff original objective value is always integral and shift is integral */ 617 (*target)->objisintegral = source->objisintegral && SCIPsetIsIntegral(set, (*target)->objoffset); 618 619 /* check, whether objective value is always integral by inspecting the problem, if it is the case adjust the 620 * cutoff bound if primal solution is already known 621 */ 622 SCIP_CALL( SCIPprobCheckObjIntegral(*target, source, blkmem, set, stat, primal, tree, reopt, lp, eventfilter, eventqueue) ); 623 624 /* copy the nlpenabled flag */ 625 (*target)->nlpenabled = source->nlpenabled; 626 627 /* mark the transformed problem to be permuted iff the source problem is permuted */ 628 (*target)->permuted = source->permuted; 629 630 /* transform the conflict pool */ 631 SCIP_CALL( SCIPconflictstoreTransform(conflictstore, blkmem, set, stat, tree, *target, reopt) ); 632 633 return SCIP_OKAY; 634 } 635 636 /** resets the global and local bounds of original variables in original problem to their original values */ 637 SCIP_RETCODE SCIPprobResetBounds( 638 SCIP_PROB* prob, /**< original problem data */ 639 BMS_BLKMEM* blkmem, /**< block memory */ 640 SCIP_SET* set, /**< global SCIP settings */ 641 SCIP_STAT* stat /**< problem statistics */ 642 ) 643 { 644 int v; 645 646 assert(prob != NULL); 647 assert(prob->nfixedvars == 0); 648 649 for( v = 0; v < prob->nvars; ++v ) 650 { 651 SCIP_CALL( SCIPvarResetBounds(prob->vars[v], blkmem, set, stat) ); 652 } 653 654 return SCIP_OKAY; 655 } 656 657 /** (Re)Sort the variables, which appear in the four categories (binary, integer, implicit, continuous) after presolve 658 * with respect to their original index (within their categories). Adjust the problem index afterwards which is 659 * supposed to reflect the position in the variable array. This additional (re)sorting is supposed to get more robust 660 * against the order presolving fixed variables. (We also reobtain a possible block structure induced by the user 661 * model) 662 */ 663 void SCIPprobResortVars( 664 SCIP_PROB* prob /**< problem data */ 665 ) 666 { 667 SCIP_VAR** vars; 668 int nbinvars; 669 int nintvars; 670 int nimplvars; 671 int ncontvars; 672 int nvars; 673 int v; 674 675 vars = prob->vars; 676 nvars = prob->nvars; 677 nbinvars = prob->nbinvars; 678 nintvars = prob->nintvars; 679 nimplvars = prob->nimplvars; 680 ncontvars = prob->ncontvars; 681 682 if( nvars == 0 ) 683 return; 684 685 assert(vars != NULL); 686 assert(nbinvars + nintvars + nimplvars + ncontvars == nvars); 687 688 SCIPdebugMessage("entering sorting with respect to original block structure! \n"); 689 690 /* sort binaries */ 691 if( nbinvars > 0 ) 692 SCIPsortPtr((void**)vars, SCIPvarComp, nbinvars); 693 694 /* sort integers */ 695 if( nintvars > 0 ) 696 SCIPsortPtr((void**)&vars[nbinvars], SCIPvarComp, nintvars); 697 698 /* sort implicit variables */ 699 if( nimplvars > 0 ) 700 SCIPsortPtr((void**)&vars[nbinvars + nintvars], SCIPvarComp, nimplvars); 701 702 /* sort continuous variables*/ 703 if( ncontvars > 0 ) 704 SCIPsortPtr((void**)&vars[nbinvars + nintvars + nimplvars], SCIPvarComp, ncontvars); 705 706 /* after sorting, the problem index of each variable has to be adjusted */ 707 for( v = 0; v < nvars; ++v ) 708 { 709 vars[v]->probindex = v; 710 SCIPdebugMessage("Variable: Problem index <%d>, original index <%d> \n", vars[v]->probindex, vars[v]->index); 711 } 712 } 713 714 /** possibly create and sort the constraints according to check priorties */ 715 SCIP_RETCODE SCIPprobSortConssCheck( 716 SCIP_PROB* prob /**< problem data */ 717 ) 718 { 719 if( prob->consschecksorted || prob->transformed ) 720 return SCIP_OKAY; 721 722 if( prob->nconss > 0 ) 723 { 724 /* possibly create and copy constraints */ 725 if( prob->origcheckconss == NULL ) 726 { 727 SCIP_ALLOC( BMSduplicateMemoryArray(&prob->origcheckconss, prob->conss, prob->consssize) ); 728 } 729 assert( prob->origcheckconss != NULL ); 730 731 /* sort original constraint according to check priority */ 732 SCIPsortPtr((void**)prob->origcheckconss, SCIPconsCompCheck, prob->nconss); 733 } 734 prob->consschecksorted = TRUE; 735 736 return SCIP_OKAY; 737 } 738 739 740 /* 741 * problem modification 742 */ 743 744 /** sets user problem data */ 745 void SCIPprobSetData( 746 SCIP_PROB* prob, /**< problem */ 747 SCIP_PROBDATA* probdata /**< user problem data to use */ 748 ) 749 { 750 assert(prob != NULL); 751 752 prob->probdata = probdata; 753 } 754 755 /** inserts variable at the correct position in vars array, depending on its type */ 756 static 757 void probInsertVar( 758 SCIP_PROB* prob, /**< problem data */ 759 SCIP_VAR* var /**< variable to insert */ 760 ) 761 { 762 int insertpos; 763 int intstart; 764 int implstart; 765 int contstart; 766 767 assert(prob != NULL); 768 assert(prob->vars != NULL); 769 assert(prob->nvars < prob->varssize); 770 assert(var != NULL); 771 assert(SCIPvarGetProbindex(var) == -1); 772 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL 773 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE 774 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 775 /* original variables cannot go into transformed problem and transformed variables cannot go into original problem */ 776 assert((SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL) == prob->transformed); 777 778 /* insert variable in array */ 779 insertpos = prob->nvars; 780 intstart = prob->nbinvars; 781 implstart = intstart + prob->nintvars; 782 contstart = implstart + prob->nimplvars; 783 784 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS ) 785 prob->ncontvars++; 786 else 787 { 788 if( insertpos > contstart ) 789 { 790 prob->vars[insertpos] = prob->vars[contstart]; 791 SCIPvarSetProbindex(prob->vars[insertpos], insertpos); 792 insertpos = contstart; 793 } 794 assert(insertpos == contstart); 795 796 if( SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT ) 797 prob->nimplvars++; 798 else 799 { 800 if( insertpos > implstart ) 801 { 802 prob->vars[insertpos] = prob->vars[implstart]; 803 SCIPvarSetProbindex(prob->vars[insertpos], insertpos); 804 insertpos = implstart; 805 } 806 assert(insertpos == implstart); 807 808 if( SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER ) 809 prob->nintvars++; 810 else 811 { 812 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY); 813 if( insertpos > intstart ) 814 { 815 prob->vars[insertpos] = prob->vars[intstart]; 816 SCIPvarSetProbindex(prob->vars[insertpos], insertpos); 817 insertpos = intstart; 818 } 819 assert(insertpos == intstart); 820 821 prob->nbinvars++; 822 } 823 } 824 } 825 prob->nvars++; 826 827 assert(prob->nvars == prob->nbinvars + prob->nintvars + prob->nimplvars + prob->ncontvars); 828 assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && insertpos == prob->nbinvars - 1) 829 || (SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER && insertpos == prob->nbinvars + prob->nintvars - 1) 830 || (SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT && insertpos == prob->nbinvars + prob->nintvars + prob->nimplvars - 1) 831 || (SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS 832 && insertpos == prob->nbinvars + prob->nintvars + prob->nimplvars + prob->ncontvars - 1)); 833 834 prob->vars[insertpos] = var; 835 SCIPvarSetProbindex(var, insertpos); 836 837 /* update number of column variables in problem */ 838 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 839 prob->ncolvars++; 840 assert(0 <= prob->ncolvars && prob->ncolvars <= prob->nvars); 841 } 842 843 /** removes variable from vars array */ 844 static 845 SCIP_RETCODE probRemoveVar( 846 SCIP_PROB* prob, /**< problem data */ 847 BMS_BLKMEM* blkmem, /**< block memory */ 848 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 849 SCIP_SET* set, /**< global SCIP settings */ 850 SCIP_VAR* var /**< variable to remove */ 851 ) 852 { 853 int freepos; 854 int intstart; 855 int implstart; 856 int contstart; 857 858 assert(prob != NULL); 859 assert(var != NULL); 860 assert(SCIPvarGetProbindex(var) >= 0); 861 assert(prob->vars != NULL); 862 assert(prob->vars[SCIPvarGetProbindex(var)] == var); 863 864 intstart = prob->nbinvars; 865 implstart = intstart + prob->nintvars; 866 contstart = implstart + prob->nimplvars; 867 868 switch( SCIPvarGetType(var) ) 869 { 870 case SCIP_VARTYPE_BINARY: 871 assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < intstart); 872 prob->nbinvars--; 873 break; 874 case SCIP_VARTYPE_INTEGER: 875 assert(intstart <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < implstart); 876 prob->nintvars--; 877 break; 878 case SCIP_VARTYPE_IMPLINT: 879 assert(implstart <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < contstart); 880 prob->nimplvars--; 881 break; 882 case SCIP_VARTYPE_CONTINUOUS: 883 assert(contstart <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < prob->nvars); 884 prob->ncontvars--; 885 break; 886 default: 887 SCIPerrorMessage("unknown variable type\n"); 888 SCIPABORT(); 889 return SCIP_INVALIDDATA; /*lint !e527*/ 890 } 891 892 /* move last binary, last integer, last implicit, and last continuous variable forward to fill the free slot */ 893 freepos = SCIPvarGetProbindex(var); 894 if( freepos < intstart-1 ) 895 { 896 /* move last binary variable to free slot */ 897 prob->vars[freepos] = prob->vars[intstart-1]; 898 SCIPvarSetProbindex(prob->vars[freepos], freepos); 899 freepos = intstart-1; 900 } 901 if( freepos < implstart-1 ) 902 { 903 /* move last integer variable to free slot */ 904 prob->vars[freepos] = prob->vars[implstart-1]; 905 SCIPvarSetProbindex(prob->vars[freepos], freepos); 906 freepos = implstart-1; 907 } 908 if( freepos < contstart-1 ) 909 { 910 /* move last implicit integer variable to free slot */ 911 prob->vars[freepos] = prob->vars[contstart-1]; 912 SCIPvarSetProbindex(prob->vars[freepos], freepos); 913 freepos = contstart-1; 914 } 915 if( freepos < prob->nvars-1 ) 916 { 917 /* move last implicit integer variable to free slot */ 918 prob->vars[freepos] = prob->vars[prob->nvars-1]; 919 SCIPvarSetProbindex(prob->vars[freepos], freepos); 920 freepos = prob->nvars-1; 921 } 922 assert(freepos == prob->nvars-1); 923 924 prob->nvars--; 925 assert(prob->nvars == prob->nbinvars + prob->nintvars + prob->nimplvars + prob->ncontvars); 926 927 /* update number of column variables in problem */ 928 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 929 prob->ncolvars--; 930 assert(0 <= prob->ncolvars && prob->ncolvars <= prob->nvars); 931 932 /* inform the variable that it is no longer in the problem; if necessary, delete it from the implication graph */ 933 SCIP_CALL( SCIPvarRemove(var, blkmem, cliquetable, set, FALSE) ); 934 935 return SCIP_OKAY; 936 } 937 938 /** adds variable's name to the namespace */ 939 SCIP_RETCODE SCIPprobAddVarName( 940 SCIP_PROB* prob, /**< problem data */ 941 SCIP_VAR* var /**< variable */ 942 ) 943 { 944 assert(SCIPvarGetProbindex(var) != -1); 945 946 if( varHasName(var) && prob->varnames != NULL ) 947 { 948 SCIP_CALL( SCIPhashtableInsert(prob->varnames, (void*)var) ); 949 } 950 951 return SCIP_OKAY; 952 } 953 954 /** removes variable's name from the namespace */ 955 SCIP_RETCODE SCIPprobRemoveVarName( 956 SCIP_PROB* prob, /**< problem data */ 957 SCIP_VAR* var /**< variable */ 958 ) 959 { 960 if( varHasName(var) && prob->varnames != NULL ) 961 { 962 assert(SCIPhashtableExists(prob->varnames, (void*)var)); 963 SCIP_CALL( SCIPhashtableRemove(prob->varnames, (void*)var) ); 964 } 965 966 return SCIP_OKAY; 967 } 968 969 /** adds variable to the problem and captures it */ 970 SCIP_RETCODE SCIPprobAddVar( 971 SCIP_PROB* prob, /**< problem data */ 972 BMS_BLKMEM* blkmem, /**< block memory buffers */ 973 SCIP_SET* set, /**< global SCIP settings */ 974 SCIP_LP* lp, /**< current LP data */ 975 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 976 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 977 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 978 SCIP_VAR* var /**< variable to add */ 979 ) 980 { 981 assert(prob != NULL); 982 assert(set != NULL); 983 assert(var != NULL); 984 assert(SCIPvarGetProbindex(var) == -1); 985 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL 986 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE 987 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 988 /* original variables cannot go into transformed problem and transformed variables cannot go into original problem */ 989 assert((SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL) == prob->transformed); 990 991 #ifndef NDEBUG 992 /* check if we add this variables to the same scip, where we created it */ 993 if( var->scip != set->scip ) 994 { 995 SCIPerrorMessage("variable belongs to a different scip instance\n"); 996 return SCIP_INVALIDDATA; 997 } 998 #endif 999 1000 /* capture variable */ 1001 SCIPvarCapture(var); 1002 1003 /* allocate additional memory */ 1004 SCIP_CALL( probEnsureVarsMem(prob, set, prob->nvars+1) ); 1005 1006 /* insert variable in vars array and mark it to be in problem */ 1007 probInsertVar(prob, var); 1008 1009 /* add variable's name to the namespace */ 1010 SCIP_CALL( SCIPprobAddVarName(prob, var) ); 1011 1012 /* update branching candidates and pseudo and loose objective value in the LP */ 1013 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL ) 1014 { 1015 SCIP_CALL( SCIPbranchcandUpdateVar(branchcand, set, var) ); 1016 SCIP_CALL( SCIPlpUpdateAddVar(lp, set, var) ); 1017 } 1018 1019 SCIPsetDebugMsg(set, "added variable <%s> to problem (%d variables: %d binary, %d integer, %d implicit, %d continuous)\n", 1020 SCIPvarGetName(var), prob->nvars, prob->nbinvars, prob->nintvars, prob->nimplvars, prob->ncontvars); 1021 1022 if( prob->transformed ) 1023 { 1024 SCIP_EVENT* event; 1025 1026 /* issue VARADDED event */ 1027 SCIP_CALL( SCIPeventCreateVarAdded(&event, blkmem, var) ); 1028 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) ); 1029 1030 /* update the number of variables with non-zero objective coefficient */ 1031 SCIPprobUpdateNObjVars(prob, set, 0.0, SCIPvarGetObj(var)); 1032 1033 /* SCIP assumes that the status of objisintegral does not change after transformation. Thus, the objective of all 1034 * new variables beyond that stage has to be compatible. */ 1035 assert( SCIPsetGetStage(set) == SCIP_STAGE_TRANSFORMING || ! prob->objisintegral || SCIPsetIsZero(set, SCIPvarGetObj(var)) || 1036 ( SCIPvarIsIntegral(var) && SCIPsetIsIntegral(set, SCIPvarGetObj(var)) ) ); 1037 } 1038 1039 return SCIP_OKAY; 1040 } 1041 1042 /** marks variable to be removed from the problem; however, the variable is NOT removed from the constraints */ 1043 SCIP_RETCODE SCIPprobDelVar( 1044 SCIP_PROB* prob, /**< problem data */ 1045 BMS_BLKMEM* blkmem, /**< block memory */ 1046 SCIP_SET* set, /**< global SCIP settings */ 1047 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 1048 SCIP_VAR* var, /**< problem variable */ 1049 SCIP_Bool* deleted /**< pointer to store whether marking variable to be deleted was successful */ 1050 ) 1051 { 1052 assert(prob != NULL); 1053 assert(set != NULL); 1054 assert(var != NULL); 1055 assert(deleted != NULL); 1056 assert(SCIPvarGetProbindex(var) != -1); 1057 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL 1058 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE 1059 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 1060 1061 *deleted = FALSE; 1062 1063 /* don't remove variables that are not in the problem */ 1064 /**@todo what about negated variables? should the negation variable be removed instead? */ 1065 if( SCIPvarGetProbindex(var) == -1 ) 1066 return SCIP_OKAY; 1067 1068 /* don't remove the direct counterpart of an original variable from the transformed problem, because otherwise 1069 * operations on the original variables would be applied to a NULL pointer 1070 */ 1071 if( SCIPvarIsTransformedOrigvar(var) ) 1072 return SCIP_OKAY; 1073 1074 assert(SCIPvarGetNegatedVar(var) == NULL); 1075 1076 SCIPsetDebugMsg(set, "deleting variable <%s> from problem (%d variables: %d binary, %d integer, %d implicit, %d continuous)\n", 1077 SCIPvarGetName(var), prob->nvars, prob->nbinvars, prob->nintvars, prob->nimplvars, prob->ncontvars); 1078 1079 /* mark variable to be deleted from the problem */ 1080 SCIPvarMarkDeleted(var); 1081 1082 if( prob->transformed ) 1083 { 1084 SCIP_EVENT* event; 1085 1086 assert(eventqueue != NULL); 1087 1088 /* issue VARDELETED event */ 1089 SCIP_CALL( SCIPeventCreateVarDeleted(&event, blkmem, var) ); 1090 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) ); 1091 } 1092 1093 /* remember that the variable should be deleted from the problem in SCIPprobPerformVarDeletions() */ 1094 SCIP_CALL( probEnsureDeletedvarsMem(prob, set, prob->ndeletedvars+1) ); 1095 prob->deletedvars[prob->ndeletedvars] = var; 1096 prob->ndeletedvars++; 1097 1098 *deleted = TRUE; 1099 1100 return SCIP_OKAY; 1101 } 1102 1103 /** actually removes the deleted variables from the problem and releases them */ 1104 SCIP_RETCODE SCIPprobPerformVarDeletions( 1105 SCIP_PROB* prob, /**< problem data */ 1106 BMS_BLKMEM* blkmem, /**< block memory */ 1107 SCIP_SET* set, /**< global SCIP settings */ 1108 SCIP_STAT* stat, /**< dynamic problem statistics */ 1109 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 1110 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 1111 SCIP_LP* lp, /**< current LP data (may be NULL) */ 1112 SCIP_BRANCHCAND* branchcand /**< branching candidate storage */ 1113 ) 1114 { 1115 int i; 1116 1117 assert(prob != NULL); 1118 assert(set != NULL); 1119 1120 /* delete variables from the constraints; 1121 * do this only in solving stage, in presolving, it is already handled by the constraint handlers 1122 */ 1123 if( SCIPsetGetStage(set) == SCIP_STAGE_SOLVING ) 1124 { 1125 for( i = 0; i < set->nconshdlrs; ++i ) 1126 { 1127 SCIP_CALL( SCIPconshdlrDelVars(set->conshdlrs[i], blkmem, set, stat) ); 1128 } 1129 } 1130 1131 for( i = 0; i < prob->ndeletedvars; ++i ) 1132 { 1133 SCIP_VAR* var; 1134 1135 var = prob->deletedvars[i]; 1136 1137 /* don't delete the variable, if it was fixed or aggregated in the meantime */ 1138 if( SCIPvarGetProbindex(var) >= 0 ) 1139 { 1140 SCIPsetDebugMsg(set, "perform deletion of <%s> [%p]\n", SCIPvarGetName(var), (void*)var); 1141 1142 /* convert column variable back into loose variable, free LP column */ 1143 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 1144 { 1145 SCIP_CALL( SCIPvarLoose(var, blkmem, set, eventqueue, prob, lp) ); 1146 } 1147 1148 /* update branching candidates and pseudo and loose objective value in the LP */ 1149 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL ) 1150 { 1151 SCIP_CALL( SCIPlpUpdateDelVar(lp, set, var) ); 1152 SCIP_CALL( SCIPbranchcandRemoveVar(branchcand, var) ); 1153 } 1154 1155 /* remove variable's name from the namespace */ 1156 SCIP_CALL( SCIPprobRemoveVarName(prob, var) ); 1157 1158 /* remove variable from vars array and mark it to be not in problem */ 1159 SCIP_CALL( probRemoveVar(prob, blkmem, cliquetable, set, var) ); 1160 1161 /* update the number of variables with non-zero objective coefficient */ 1162 if( prob->transformed ) 1163 SCIPprobUpdateNObjVars(prob, set, SCIPvarGetObj(var), 0.0); 1164 1165 /* release variable */ 1166 SCIP_CALL( SCIPvarRelease(&prob->deletedvars[i], blkmem, set, eventqueue, lp) ); 1167 } 1168 } 1169 prob->ndeletedvars = 0; 1170 1171 return SCIP_OKAY; 1172 } 1173 1174 /** changes the type of a variable in the problem */ 1175 SCIP_RETCODE SCIPprobChgVarType( 1176 SCIP_PROB* prob, /**< problem data */ 1177 BMS_BLKMEM* blkmem, /**< block memory */ 1178 SCIP_SET* set, /**< global SCIP settings */ 1179 SCIP_PRIMAL* primal, /**< primal data */ 1180 SCIP_LP* lp, /**< current LP data */ 1181 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 1182 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 1183 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 1184 SCIP_VAR* var, /**< variable to add */ 1185 SCIP_VARTYPE vartype /**< new type of variable */ 1186 ) 1187 { 1188 assert(prob != NULL); 1189 assert(var != NULL); 1190 assert(SCIPvarGetProbindex(var) >= 0); 1191 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL 1192 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE 1193 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); 1194 assert(branchcand != NULL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL); 1195 1196 if( SCIPvarGetType(var) == vartype ) 1197 return SCIP_OKAY; 1198 1199 /* temporarily remove variable from branching candidates */ 1200 if( branchcand != NULL ) 1201 { 1202 SCIP_CALL( SCIPbranchcandRemoveVar(branchcand, var) ); 1203 } 1204 1205 /* temporarily remove variable from problem */ 1206 SCIP_CALL( probRemoveVar(prob, blkmem, cliquetable, set, var) ); 1207 1208 /* change the type of the variable */ 1209 SCIP_CALL( SCIPvarChgType(var, blkmem, set, primal, lp, eventqueue, vartype) ); 1210 1211 /* reinsert variable into problem */ 1212 probInsertVar(prob, var); 1213 1214 /* update branching candidates */ 1215 if( branchcand != NULL ) 1216 { 1217 SCIP_CALL( SCIPbranchcandUpdateVar(branchcand, set, var) ); 1218 } 1219 1220 return SCIP_OKAY; 1221 } 1222 1223 /** informs problem, that the given loose problem variable changed its status */ 1224 SCIP_RETCODE SCIPprobVarChangedStatus( 1225 SCIP_PROB* prob, /**< problem data */ 1226 BMS_BLKMEM* blkmem, /**< block memory */ 1227 SCIP_SET* set, /**< global SCIP settings */ 1228 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 1229 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */ 1230 SCIP_VAR* var /**< problem variable */ 1231 ) 1232 { 1233 assert(prob != NULL); 1234 assert(var != NULL); 1235 assert(SCIPvarGetProbindex(var) != -1); 1236 1237 /* get current status of variable */ 1238 switch( SCIPvarGetStatus(var) ) 1239 { 1240 case SCIP_VARSTATUS_ORIGINAL: 1241 SCIPerrorMessage("variables cannot switch to ORIGINAL status\n"); 1242 return SCIP_INVALIDDATA; 1243 1244 case SCIP_VARSTATUS_LOOSE: 1245 /* variable switched from column to loose */ 1246 prob->ncolvars--; 1247 break; 1248 1249 case SCIP_VARSTATUS_COLUMN: 1250 /* variable switched from non-column to column */ 1251 prob->ncolvars++; 1252 break; 1253 1254 case SCIP_VARSTATUS_FIXED: 1255 case SCIP_VARSTATUS_AGGREGATED: 1256 case SCIP_VARSTATUS_MULTAGGR: 1257 case SCIP_VARSTATUS_NEGATED: 1258 /* variable switched from unfixed to fixed (if it was fixed before, probindex would have been -1) */ 1259 1260 /* remove variable from problem */ 1261 SCIP_CALL( probRemoveVar(prob, blkmem, cliquetable, set, var) ); 1262 1263 /* insert variable in fixedvars array */ 1264 SCIP_CALL( probEnsureFixedvarsMem(prob, set, prob->nfixedvars+1) ); 1265 prob->fixedvars[prob->nfixedvars] = var; 1266 prob->nfixedvars++; 1267 1268 /* update branching candidates */ 1269 SCIP_CALL( SCIPbranchcandUpdateVar(branchcand, set, var) ); 1270 break; 1271 1272 default: 1273 SCIPerrorMessage("invalid variable status <%d>\n", SCIPvarGetStatus(var)); 1274 return SCIP_INVALIDDATA; 1275 } 1276 assert(0 <= prob->ncolvars && prob->ncolvars <= prob->nvars); 1277 1278 return SCIP_OKAY; 1279 } 1280 1281 /** adds constraint's name to the namespace */ 1282 SCIP_RETCODE SCIPprobAddConsName( 1283 SCIP_PROB* prob, /**< problem data */ 1284 SCIP_CONS* cons /**< constraint */ 1285 ) 1286 { 1287 /* add constraint's name to the namespace */ 1288 if( consHasName(cons) && prob->consnames != NULL ) 1289 { 1290 SCIP_CALL( SCIPhashtableInsert(prob->consnames, (void*)cons) ); 1291 } 1292 1293 return SCIP_OKAY; 1294 } 1295 1296 /** remove constraint's name from the namespace */ 1297 SCIP_RETCODE SCIPprobRemoveConsName( 1298 SCIP_PROB* prob, /**< problem data */ 1299 SCIP_CONS* cons /**< constraint */ 1300 ) 1301 { 1302 /* remove constraint's name from the namespace */ 1303 if( consHasName(cons) && prob->consnames != NULL ) 1304 { 1305 SCIP_CONS* currentcons; 1306 currentcons = (SCIP_CONS*)SCIPhashtableRetrieve(prob->consnames, (void*)(cons->name)); 1307 if( currentcons == cons ) 1308 { 1309 SCIP_CALL( SCIPhashtableRemove(prob->consnames, (void*)cons) ); 1310 } 1311 } 1312 1313 return SCIP_OKAY; 1314 } 1315 1316 /** adds constraint to the problem and captures it; 1317 * a local constraint is automatically upgraded into a global constraint 1318 */ 1319 SCIP_RETCODE SCIPprobAddCons( 1320 SCIP_PROB* prob, /**< problem data */ 1321 SCIP_SET* set, /**< global SCIP settings */ 1322 SCIP_STAT* stat, /**< dynamic problem statistics */ 1323 SCIP_CONS* cons /**< constraint to add */ 1324 ) 1325 { 1326 assert(prob != NULL); 1327 assert(cons != NULL); 1328 assert(cons->addconssetchg == NULL); 1329 assert(cons->addarraypos == -1); 1330 1331 #ifndef NDEBUG 1332 /* check if we add this constraint to the same scip, where we create the constraint */ 1333 if( cons->scip != set->scip ) 1334 { 1335 SCIPerrorMessage("constraint belongs to different scip instance\n"); 1336 return SCIP_INVALIDDATA; 1337 } 1338 #endif 1339 SCIPsetDebugMsg(set, "adding constraint <%s> to global problem -> %d constraints\n", 1340 SCIPconsGetName(cons), prob->nconss+1); 1341 1342 /* mark the constraint as problem constraint, and remember the constraint's position */ 1343 cons->addconssetchg = NULL; 1344 cons->addarraypos = prob->nconss; 1345 1346 /* add the constraint to the problem's constraint array */ 1347 SCIP_CALL( probEnsureConssMem(prob, set, prob->nconss+1) ); 1348 prob->conss[prob->nconss] = cons; 1349 if( prob->origcheckconss != NULL ) 1350 prob->origcheckconss[prob->nconss] = cons; 1351 prob->nconss++; 1352 prob->maxnconss = MAX(prob->maxnconss, prob->nconss); 1353 prob->consschecksorted = FALSE; 1354 stat->nactiveconssadded++; 1355 1356 /* undelete constraint, if it was globally deleted in the past */ 1357 cons->deleted = FALSE; 1358 1359 /* mark constraint to be globally valid */ 1360 SCIPconsSetLocal(cons, FALSE); 1361 1362 /* capture constraint */ 1363 SCIPconsCapture(cons); 1364 1365 /* add constraint's name to the namespace */ 1366 SCIP_CALL( SCIPprobAddConsName(prob, cons) ); 1367 1368 /* if the problem is the transformed problem, activate and lock constraint */ 1369 if( prob->transformed ) 1370 { 1371 /* activate constraint */ 1372 if( !SCIPconsIsActive(cons) ) 1373 { 1374 SCIP_CALL( SCIPconsActivate(cons, set, stat, -1, (stat->nnodes <= 1)) ); 1375 } 1376 1377 /* if constraint is a check-constraint, lock roundings of constraint's variables */ 1378 if( SCIPconsIsChecked(cons) ) 1379 { 1380 SCIP_CALL( SCIPconsAddLocks(cons, set, SCIP_LOCKTYPE_MODEL, +1, 0) ); 1381 } 1382 } 1383 1384 return SCIP_OKAY; 1385 } 1386 1387 /** releases and removes constraint from the problem; if the user has not captured the constraint for his own use, the 1388 * constraint may be invalid after the call 1389 */ 1390 SCIP_RETCODE SCIPprobDelCons( 1391 SCIP_PROB* prob, /**< problem data */ 1392 BMS_BLKMEM* blkmem, /**< block memory */ 1393 SCIP_SET* set, /**< global SCIP settings */ 1394 SCIP_STAT* stat, /**< dynamic problem statistics */ 1395 SCIP_CONS* cons /**< constraint to remove */ 1396 ) 1397 { 1398 int arraypos; 1399 1400 assert(prob != NULL); 1401 assert(blkmem != NULL); 1402 assert(cons != NULL); 1403 assert(cons->addconssetchg == NULL); 1404 assert(0 <= cons->addarraypos && cons->addarraypos < prob->nconss); 1405 assert(prob->conss != NULL); 1406 assert(prob->conss[cons->addarraypos] == cons); 1407 1408 /* if the problem is the transformed problem, deactivate and unlock constraint */ 1409 if( prob->transformed ) 1410 { 1411 /* if constraint is a check-constraint, unlock roundings of constraint's variables */ 1412 if( SCIPconsIsChecked(cons) ) 1413 { 1414 SCIP_CALL( SCIPconsAddLocks(cons, set, SCIP_LOCKTYPE_MODEL, -1, 0) ); 1415 } 1416 1417 /* deactivate constraint, if it is currently active */ 1418 if( cons->active && !cons->updatedeactivate ) 1419 { 1420 SCIP_CALL( SCIPconsDeactivate(cons, set, stat) ); 1421 } 1422 } 1423 assert(!cons->active || cons->updatedeactivate); 1424 assert(!cons->enabled || cons->updatedeactivate); 1425 1426 /* remove constraint's name from the namespace */ 1427 SCIP_CALL( SCIPprobRemoveConsName(prob, cons) ); 1428 1429 /* remove the constraint from the problem's constraint array */ 1430 arraypos = cons->addarraypos; 1431 prob->conss[arraypos] = prob->conss[prob->nconss-1]; 1432 assert(prob->conss[arraypos] != NULL); 1433 assert(prob->conss[arraypos]->addconssetchg == NULL); 1434 prob->conss[arraypos]->addarraypos = arraypos; 1435 prob->nconss--; 1436 prob->consschecksorted = FALSE; 1437 1438 /* if we delete constraints then delete array origcheckconss to be sure */ 1439 if( prob->origcheckconss != NULL ) 1440 BMSfreeMemoryArray(&prob->origcheckconss); 1441 1442 /* mark the constraint to be no longer in the problem */ 1443 cons->addarraypos = -1; 1444 1445 /* release constraint */ 1446 SCIP_CALL( SCIPconsRelease(&cons, blkmem, set) ); 1447 1448 return SCIP_OKAY; 1449 } 1450 1451 /** remembers the current number of constraints in the problem's internal data structure 1452 * - resets maximum number of constraints to current number of constraints 1453 * - remembers current number of constraints as starting number of constraints 1454 */ 1455 void SCIPprobMarkNConss( 1456 SCIP_PROB* prob /**< problem data */ 1457 ) 1458 { 1459 assert(prob != NULL); 1460 1461 /* remember number of constraints for statistic */ 1462 prob->maxnconss = prob->nconss; 1463 prob->startnvars = prob->nvars; 1464 prob->startnconss = prob->nconss; 1465 } 1466 1467 /** sets objective sense: minimization or maximization */ 1468 void SCIPprobSetObjsense( 1469 SCIP_PROB* prob, /**< problem data */ 1470 SCIP_OBJSENSE objsense /**< new objective sense */ 1471 ) 1472 { 1473 assert(prob != NULL); 1474 assert(prob->objsense == SCIP_OBJSENSE_MAXIMIZE || prob->objsense == SCIP_OBJSENSE_MINIMIZE); 1475 assert(objsense == SCIP_OBJSENSE_MAXIMIZE || objsense == SCIP_OBJSENSE_MINIMIZE); 1476 1477 prob->objsense = objsense; 1478 } 1479 1480 /** adds value to objective offset */ 1481 void SCIPprobAddObjoffset( 1482 SCIP_PROB* prob, /**< problem data */ 1483 SCIP_Real addval /**< value to add to objective offset */ 1484 ) 1485 { 1486 assert(prob != NULL); 1487 assert(prob->transformed); 1488 1489 SCIPdebugMessage("adding %g to objective offset %g: new offset = %g\n", addval, prob->objoffset, prob->objoffset + addval); 1490 prob->objoffset += addval; 1491 } 1492 1493 /** sets the dual bound on objective function */ 1494 void SCIPprobSetDualbound( 1495 SCIP_PROB* prob, /**< problem data */ 1496 SCIP_Real dualbound /**< external dual bound */ 1497 ) 1498 { 1499 assert(prob != NULL); 1500 1501 prob->dualbound = dualbound; 1502 } 1503 1504 /** sets limit on objective function, such that only solutions better than this limit are accepted */ 1505 void SCIPprobSetObjlim( 1506 SCIP_PROB* prob, /**< problem data */ 1507 SCIP_Real objlim /**< external objective limit */ 1508 ) 1509 { 1510 assert(prob != NULL); 1511 1512 prob->objlim = objlim; 1513 } 1514 1515 /** informs the problem, that its objective value is always integral in every feasible solution */ 1516 void SCIPprobSetObjIntegral( 1517 SCIP_PROB* prob /**< problem data */ 1518 ) 1519 { 1520 assert(prob != NULL); 1521 1522 prob->objisintegral = TRUE; 1523 } 1524 1525 /** sets integral objective value flag, if all variables with non-zero objective values are integral and have 1526 * integral objective value and also updates the cutoff bound if primal solution is already known 1527 */ 1528 SCIP_RETCODE SCIPprobCheckObjIntegral( 1529 SCIP_PROB* transprob, /**< tranformed problem data */ 1530 SCIP_PROB* origprob, /**< original problem data */ 1531 BMS_BLKMEM* blkmem, /**< block memory */ 1532 SCIP_SET* set, /**< global SCIP settings */ 1533 SCIP_STAT* stat, /**< problem statistics data */ 1534 SCIP_PRIMAL* primal, /**< primal data */ 1535 SCIP_TREE* tree, /**< branch and bound tree */ 1536 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1537 SCIP_LP* lp, /**< current LP data */ 1538 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 1539 SCIP_EVENTQUEUE* eventqueue /**< event queue */ 1540 ) 1541 { 1542 SCIP_Real obj; 1543 int v; 1544 1545 assert(transprob != NULL); 1546 assert(origprob != NULL); 1547 1548 /* if we know already, that the objective value is integral, nothing has to be done */ 1549 if( transprob->objisintegral ) 1550 return SCIP_OKAY; 1551 1552 /* if there exist unknown variables, we cannot conclude that the objective value is always integral */ 1553 if( set->nactivepricers != 0 || set->nactivebenders != 0 ) 1554 return SCIP_OKAY; 1555 1556 /* if the objective value offset is fractional, the value itself is possibly fractional */ 1557 if( !SCIPsetIsIntegral(set, transprob->objoffset) ) 1558 return SCIP_OKAY; 1559 1560 /* scan through the variables */ 1561 for( v = 0; v < transprob->nvars; ++v ) 1562 { 1563 /* get objective value of variable */ 1564 obj = SCIPvarGetObj(transprob->vars[v]); 1565 1566 /* check, if objective value is non-zero */ 1567 if( !SCIPsetIsZero(set, obj) ) 1568 { 1569 /* if variable's objective value is fractional, the problem's objective value may also be fractional */ 1570 if( !SCIPsetIsIntegral(set, obj) ) 1571 break; 1572 1573 /* if variable with non-zero objective value is continuous, the problem's objective value may be fractional */ 1574 if( SCIPvarGetType(transprob->vars[v]) == SCIP_VARTYPE_CONTINUOUS ) 1575 break; 1576 } 1577 } 1578 1579 /* objective value is integral, if the variable loop scanned all variables */ 1580 if( v == transprob->nvars ) 1581 { 1582 transprob->objisintegral = TRUE; 1583 1584 /* update upper bound and cutoff bound in primal data structure due to new internality information */ 1585 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) ); 1586 } 1587 1588 return SCIP_OKAY; 1589 } 1590 1591 /** update the number of variables with non-zero objective coefficient */ 1592 void SCIPprobUpdateNObjVars( 1593 SCIP_PROB* prob, /**< problem data */ 1594 SCIP_SET* set, /**< global SCIP settings */ 1595 SCIP_Real oldobj, /**< old objective value for variable */ 1596 SCIP_Real newobj /**< new objective value for variable */ 1597 ) 1598 { 1599 assert(prob->transformed); 1600 1601 if( !SCIPsetIsZero(set, oldobj) ) 1602 prob->nobjvars--; 1603 1604 if( !SCIPsetIsZero(set, newobj) ) 1605 prob->nobjvars++; 1606 } 1607 1608 /** update the dual bound if its better as the current one */ 1609 void SCIPprobUpdateDualbound( 1610 SCIP_PROB* prob, /**< problem data */ 1611 SCIP_Real newbound /**< new dual bound for the node (if it's tighter than the old one) */ 1612 ) 1613 { 1614 if( prob->dualbound == SCIP_INVALID ) /*lint !e777*/ 1615 SCIPprobSetDualbound(prob, newbound); 1616 else 1617 { 1618 switch( prob->objsense ) 1619 { 1620 case SCIP_OBJSENSE_MINIMIZE: 1621 prob->dualbound = MAX(newbound, prob->dualbound); 1622 break; 1623 1624 case SCIP_OBJSENSE_MAXIMIZE: 1625 prob->dualbound = MIN(newbound, prob->dualbound); 1626 break; 1627 1628 default: 1629 SCIPerrorMessage("invalid objective sense <%d>\n", prob->objsense); 1630 SCIPABORT(); 1631 } 1632 } 1633 } 1634 1635 /** invalidates the dual bound */ 1636 void SCIPprobInvalidateDualbound( 1637 SCIP_PROB* prob /**< problem data */ 1638 ) 1639 { 1640 assert(prob != NULL); 1641 1642 prob->dualbound = SCIP_INVALID; 1643 } 1644 1645 /** if possible, scales objective function such that it is integral with gcd = 1 */ 1646 SCIP_RETCODE SCIPprobScaleObj( 1647 SCIP_PROB* transprob, /**< tranformed problem data */ 1648 SCIP_PROB* origprob, /**< original problem data */ 1649 BMS_BLKMEM* blkmem, /**< block memory */ 1650 SCIP_SET* set, /**< global SCIP settings */ 1651 SCIP_STAT* stat, /**< problem statistics data */ 1652 SCIP_PRIMAL* primal, /**< primal data */ 1653 SCIP_TREE* tree, /**< branch and bound tree */ 1654 SCIP_REOPT* reopt, /**< reoptimization data structure */ 1655 SCIP_LP* lp, /**< current LP data */ 1656 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */ 1657 SCIP_EVENTQUEUE* eventqueue /**< event queue */ 1658 ) 1659 { 1660 int v; 1661 int nints; 1662 1663 assert(transprob != NULL); 1664 assert(set != NULL); 1665 1666 /* do not change objective if there are pricers involved */ 1667 if( set->nactivepricers != 0 || set->nactivebenders != 0 || !set->misc_scaleobj ) 1668 return SCIP_OKAY; 1669 1670 nints = transprob->nvars - transprob->ncontvars; 1671 1672 /* scan through the continuous variables */ 1673 for( v = nints; v < transprob->nvars; ++v ) 1674 { 1675 SCIP_Real obj; 1676 1677 /* get objective value of variable; it it is non-zero, no scaling can be applied */ 1678 obj = SCIPvarGetObj(transprob->vars[v]); 1679 if( !SCIPsetIsZero(set, obj) ) 1680 break; 1681 } 1682 1683 /* only continue if all continuous variables have obj = 0 */ 1684 if( v == transprob->nvars ) 1685 { 1686 SCIP_Real* objvals; 1687 SCIP_Real intscalar; 1688 SCIP_Bool success; 1689 1690 /* get temporary memory */ 1691 SCIP_CALL( SCIPsetAllocBufferArray(set, &objvals, nints) ); 1692 1693 /* get objective values of integer variables */ 1694 for( v = 0; v < nints; ++v ) 1695 objvals[v] = SCIPvarGetObj(transprob->vars[v]); 1696 1697 /* calculate integral scalar */ 1698 SCIP_CALL( SCIPcalcIntegralScalar(objvals, nints, -SCIPsetEpsilon(set), +SCIPsetEpsilon(set), OBJSCALE_MAXDNOM, OBJSCALE_MAXSCALE, 1699 &intscalar, &success) ); 1700 1701 SCIPsetDebugMsg(set, "integral objective scalar: success=%u, intscalar=%g\n", success, intscalar); 1702 1703 if( success ) 1704 { 1705 SCIP_Longint gcd; 1706 1707 assert(intscalar > 0.0); 1708 1709 /* calculate gcd of resulting integral coefficients */ 1710 gcd = 0; 1711 for( v = 0; v < nints && gcd != 1; ++v ) 1712 { 1713 SCIP_Longint absobj; 1714 1715 /* if absobj exceeds maximum SCIP_Longint value, return */ 1716 if( REALABS(objvals[v]) * intscalar + 0.5 > (SCIP_Real)SCIP_LONGINT_MAX ) 1717 { 1718 SCIPsetFreeBufferArray(set, &objvals); 1719 return SCIP_OKAY; 1720 } 1721 1722 absobj = (SCIP_Longint)(REALABS(objvals[v]) * intscalar + 0.5); 1723 if( gcd == 0 ) 1724 gcd = absobj; 1725 else if( absobj > 0 ) 1726 gcd = SCIPcalcGreComDiv(gcd, absobj); 1727 } 1728 if( gcd != 0 ) 1729 intscalar /= gcd; 1730 SCIPsetDebugMsg(set, "integral objective scalar: gcd=%" SCIP_LONGINT_FORMAT ", intscalar=%g\n", gcd, intscalar); 1731 1732 /* only apply scaling if the final scalar is small enough */ 1733 if( intscalar <= OBJSCALE_MAXFINALSCALE ) 1734 { 1735 /* apply scaling */ 1736 if( !SCIPsetIsEQ(set, intscalar, 1.0) ) 1737 { 1738 /* calculate scaled objective values */ 1739 for( v = 0; v < nints; ++v ) 1740 { 1741 SCIP_Real newobj; 1742 1743 /* check if new obj is really integral */ 1744 newobj = intscalar * SCIPvarGetObj(transprob->vars[v]); 1745 if( !SCIPsetIsFeasIntegral(set, newobj) ) 1746 break; 1747 objvals[v] = SCIPsetFeasFloor(set, newobj); 1748 } 1749 1750 /* change the variables' objective values and adjust objscale and objoffset */ 1751 if( v == nints ) 1752 { 1753 for( v = 0; v < nints; ++v ) 1754 { 1755 SCIPsetDebugMsg(set, " -> var <%s>: newobj = %.6f\n", SCIPvarGetName(transprob->vars[v]), objvals[v]); 1756 SCIP_CALL( SCIPvarChgObj(transprob->vars[v], blkmem, set, transprob, primal, lp, eventqueue, objvals[v]) ); 1757 } 1758 transprob->objoffset *= intscalar; 1759 transprob->objscale /= intscalar; 1760 transprob->objisintegral = TRUE; 1761 SCIPsetDebugMsg(set, "integral objective scalar: objscale=%g\n", transprob->objscale); 1762 1763 /* update upperbound and cutoffbound in primal data structure */ 1764 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) ); 1765 } 1766 } 1767 } 1768 } 1769 1770 /* free temporary memory */ 1771 SCIPsetFreeBufferArray(set, &objvals); 1772 } 1773 1774 return SCIP_OKAY; 1775 } 1776 1777 /** remembers the current solution as root solution in the problem variables */ 1778 void SCIPprobStoreRootSol( 1779 SCIP_PROB* prob, /**< problem data */ 1780 SCIP_SET* set, /**< global SCIP settings */ 1781 SCIP_STAT* stat, /**< SCIP statistics */ 1782 SCIP_LP* lp, /**< current LP data */ 1783 SCIP_Bool roothaslp /**< is the root solution from LP? */ 1784 ) 1785 { 1786 int v; 1787 1788 assert(prob != NULL); 1789 assert(prob->transformed); 1790 1791 if( roothaslp ) 1792 { 1793 for( v = 0; v < prob->nvars; ++v ) 1794 SCIPvarStoreRootSol(prob->vars[v], roothaslp); 1795 1796 SCIPlpSetRootLPIsRelax(lp, SCIPlpIsRelax(lp)); 1797 SCIPlpStoreRootObjval(lp, set, prob); 1798 1799 /* compute root LP best-estimate */ 1800 SCIPstatComputeRootLPBestEstimate(stat, set, SCIPlpGetColumnObjval(lp), prob->vars, prob->nbinvars + prob->nintvars + prob->nimplvars); 1801 } 1802 } 1803 1804 /** remembers the best solution w.r.t. root reduced cost propagation as root solution in the problem variables */ 1805 void SCIPprobUpdateBestRootSol( 1806 SCIP_PROB* prob, /**< problem data */ 1807 SCIP_SET* set, /**< global SCIP settings */ 1808 SCIP_STAT* stat, /**< problem statistics */ 1809 SCIP_LP* lp /**< current LP data */ 1810 ) 1811 { 1812 SCIP_Real rootlpobjval; 1813 int v; 1814 1815 assert(prob != NULL); 1816 assert(lp != NULL); 1817 assert(prob->transformed); 1818 assert(lp->lpsolstat == SCIP_LPSOLSTAT_OPTIMAL); 1819 1820 /* in case we have a zero objective fucntion, we skip the root reduced cost update */ 1821 if( SCIPprobGetNObjVars(prob, set) == 0 ) 1822 return; 1823 1824 if( !SCIPlpIsDualReliable(lp) ) 1825 return; 1826 1827 SCIPsetDebugMsg(set, "update root reduced costs\n"); 1828 1829 /* compute current root LP objective value */ 1830 rootlpobjval = SCIPlpGetObjval(lp, set, prob); 1831 assert(rootlpobjval != SCIP_INVALID); /*lint !e777*/ 1832 1833 for( v = 0; v < prob->nvars; ++v ) 1834 { 1835 SCIP_VAR* var; 1836 SCIP_COL* col; 1837 SCIP_Real rootsol = 0.0; 1838 SCIP_Real rootredcost = 0.0; 1839 1840 var = prob->vars[v]; 1841 assert(var != NULL); 1842 1843 /* check if the variable is part of the LP */ 1844 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN ) 1845 continue; 1846 1847 col = SCIPvarGetCol(var); 1848 assert(col != NULL); 1849 1850 assert(SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL); 1851 1852 if( !SCIPvarIsBinary(var) ) 1853 { 1854 rootsol = SCIPvarGetSol(var, TRUE); 1855 rootredcost = SCIPcolGetRedcost(col, stat, lp); 1856 } 1857 else 1858 { 1859 SCIP_Real primsol; 1860 SCIP_BASESTAT basestat; 1861 SCIP_Bool lpissolbasic; 1862 1863 basestat = SCIPcolGetBasisStatus(col); 1864 lpissolbasic = SCIPlpIsSolBasic(lp); 1865 primsol = SCIPcolGetPrimsol(col); 1866 1867 if( (lpissolbasic && (basestat == SCIP_BASESTAT_LOWER || basestat == SCIP_BASESTAT_UPPER)) || 1868 (!lpissolbasic && (SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol) || 1869 SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol))) ) 1870 { 1871 SCIP_Real lbrootredcost; 1872 SCIP_Real ubrootredcost; 1873 1874 /* get reduced cost if the variable gets fixed to zero */ 1875 lbrootredcost = SCIPvarGetImplRedcost(var, set, FALSE, stat, prob, lp); 1876 assert( !SCIPsetIsDualfeasPositive(set, lbrootredcost) 1877 || SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var))); 1878 1879 /* get reduced cost if the variable gets fixed to one */ 1880 ubrootredcost = SCIPvarGetImplRedcost(var, set, TRUE, stat, prob, lp); 1881 assert( !SCIPsetIsDualfeasNegative(set, ubrootredcost) 1882 || SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var))); 1883 1884 if( -lbrootredcost > ubrootredcost ) 1885 { 1886 rootredcost = lbrootredcost; 1887 rootsol = 1.0; 1888 } 1889 else 1890 { 1891 rootredcost = ubrootredcost; 1892 rootsol = 0.0; 1893 } 1894 } 1895 } 1896 1897 /* update the current solution as best root solution in the problem variables if it is better */ 1898 SCIPvarUpdateBestRootSol(var, set, rootsol, rootredcost, rootlpobjval); 1899 } 1900 } 1901 1902 /** informs problem, that the presolving process was finished, and updates all internal data structures */ /*lint -e715*/ 1903 SCIP_RETCODE SCIPprobExitPresolve( 1904 SCIP_PROB* prob, /**< problem data */ 1905 SCIP_SET* set /**< global SCIP settings */ 1906 ) 1907 { /*lint --e{715}*/ 1908 return SCIP_OKAY; 1909 } 1910 1911 /** initializes problem for branch and bound process and resets all constraint's ages and histories of current run */ 1912 SCIP_RETCODE SCIPprobInitSolve( 1913 SCIP_PROB* prob, /**< problem data */ 1914 SCIP_SET* set /**< global SCIP settings */ 1915 ) 1916 { 1917 int c; 1918 int v; 1919 1920 assert(prob != NULL); 1921 assert(prob->transformed); 1922 assert(set != NULL); 1923 1924 /* reset constraint's ages */ 1925 for( c = 0; c < prob->nconss; ++c ) 1926 { 1927 SCIP_CALL( SCIPconsResetAge(prob->conss[c], set) ); 1928 } 1929 1930 /* initialize variables for solving */ 1931 for( v = 0; v < prob->nvars; ++v ) 1932 SCIPvarInitSolve(prob->vars[v]); 1933 1934 /* call user data function */ 1935 if( prob->probinitsol != NULL ) 1936 { 1937 SCIP_CALL( prob->probinitsol(set->scip, prob->probdata) ); 1938 } 1939 1940 /* assert that the counter for variables with nonzero objective is correct */ 1941 assert(prob->nobjvars == SCIPprobGetNObjVars(prob, set)); 1942 1943 return SCIP_OKAY; 1944 } 1945 1946 /** deinitializes problem after branch and bound process, and converts all COLUMN variables back into LOOSE variables */ 1947 SCIP_RETCODE SCIPprobExitSolve( 1948 SCIP_PROB* prob, /**< problem data */ 1949 BMS_BLKMEM* blkmem, /**< block memory */ 1950 SCIP_SET* set, /**< global SCIP settings */ 1951 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 1952 SCIP_LP* lp, /**< current LP data */ 1953 SCIP_Bool restart /**< was this exit solve call triggered by a restart? */ 1954 ) 1955 { 1956 SCIP_VAR* var; 1957 int v; 1958 1959 assert(prob != NULL); 1960 assert(prob->transformed); 1961 assert(set != NULL); 1962 1963 /* call user data function */ 1964 if( prob->probexitsol != NULL ) 1965 { 1966 SCIP_CALL( prob->probexitsol(set->scip, prob->probdata, restart) ); 1967 } 1968 1969 /* - convert all COLUMN variables back into LOOSE variables 1970 * - mark relaxation-only variables for deletion, if possible and restarting 1971 * - initPresolve will then call SCIPprobPerformVarDeletions 1972 * - if no restart, then the whole transformed problem will be deleted anyway 1973 */ 1974 if( prob->ncolvars > 0 || restart ) 1975 { 1976 for( v = 0; v < prob->nvars; ++v ) 1977 { 1978 var = prob->vars[v]; 1979 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) 1980 { 1981 SCIP_CALL( SCIPvarLoose(var, blkmem, set, eventqueue, prob, lp) ); 1982 } 1983 1984 /* invalidate root reduced cost, root reduced solution, and root LP objective value for each variable */ 1985 SCIPvarSetBestRootSol(var, 0.0, 0.0, SCIP_INVALID); 1986 1987 if( SCIPvarIsRelaxationOnly(var) && restart ) 1988 { 1989 /* relaxation variables should be unlocked and only captured by prob at this moment */ 1990 assert(SCIPvarGetNLocksDown(var) == 0); 1991 assert(SCIPvarGetNLocksUp(var) == 0); 1992 assert(SCIPvarGetNUses(var) == 1); 1993 1994 if( SCIPvarIsDeletable(var) ) 1995 { 1996 SCIP_Bool deleted; 1997 1998 SCIPsetDebugMsg(set, "queue relaxation-only variable <%s> for deletion\n", SCIPvarGetName(var)); 1999 SCIP_CALL( SCIPprobDelVar(prob, blkmem, set, eventqueue, var, &deleted) ); 2000 assert(deleted); 2001 } 2002 else 2003 { 2004 SCIPsetDebugMsg(set, "cannot queue relaxation-only variable <%s> for deletion because it is marked non-deletable\n", SCIPvarGetName(var)); 2005 } 2006 } 2007 } 2008 } 2009 assert(prob->ncolvars == 0); 2010 2011 return SCIP_OKAY; 2012 } 2013 2014 2015 2016 2017 /* 2018 * problem information 2019 */ 2020 2021 /** sets problem name */ 2022 SCIP_RETCODE SCIPprobSetName( 2023 SCIP_PROB* prob, /**< problem data */ 2024 const char* name /**< name to be set */ 2025 ) 2026 { 2027 assert(prob != NULL); 2028 2029 BMSfreeMemoryArray(&(prob->name)); 2030 SCIP_ALLOC( BMSduplicateMemoryArray(&(prob->name), name, strlen(name)+1) ); 2031 2032 return SCIP_OKAY; 2033 } 2034 2035 /** returns the number of implicit binary variables, meaning variable of vartype != SCIP_VARTYPE_BINARY and != 2036 * SCIP_VARTYPE_CONTINUOUS but with global bounds [0,1] 2037 * 2038 * @note this number needs to be computed, because it cannot be updated like the other counters for binary and integer 2039 * variables, each time the variable type changes(, we would need to update this counter each time a global bound 2040 * changes), even at the end of presolving this cannot be computed, because some variable can change to an 2041 * implicit binary status 2042 */ 2043 int SCIPprobGetNImplBinVars( 2044 SCIP_PROB* prob /**< problem data */ 2045 ) 2046 { 2047 int v; 2048 int nimplbinvars = 0; 2049 2050 for( v = prob->nbinvars + prob->nintvars + prob->nimplvars - 1; v >= prob->nbinvars; --v ) 2051 { 2052 if( SCIPvarIsBinary(prob->vars[v]) ) 2053 ++nimplbinvars; 2054 } 2055 2056 return nimplbinvars; 2057 } 2058 2059 /** returns the number of variables with non-zero objective coefficient */ 2060 int SCIPprobGetNObjVars( 2061 SCIP_PROB* prob, /**< problem data */ 2062 SCIP_SET* set /**< global SCIP settings */ 2063 ) 2064 { 2065 if( prob->transformed ) 2066 { 2067 /* this is much too expensive, to check it in each debug run */ 2068 #ifdef SCIP_MORE_DEBUG 2069 int nobjvars; 2070 int v; 2071 2072 nobjvars = 0; 2073 2074 for( v = prob->nvars - 1; v >= 0; --v ) 2075 { 2076 if( !SCIPsetIsZero(set, SCIPvarGetObj(prob->vars[v])) ) 2077 nobjvars++; 2078 } 2079 2080 /* check that the internal count is correct */ 2081 assert(prob->nobjvars == nobjvars); 2082 #endif 2083 return prob->nobjvars; 2084 } 2085 else 2086 { 2087 int nobjvars; 2088 int v; 2089 2090 nobjvars = 0; 2091 2092 for( v = prob->nvars - 1; v >= 0; --v ) 2093 { 2094 if( !SCIPsetIsZero(set, SCIPvarGetObj(prob->vars[v])) ) 2095 nobjvars++; 2096 } 2097 return nobjvars; 2098 } 2099 } 2100 2101 /** returns the minimal absolute non-zero objective coefficient 2102 * 2103 * @note currently, this is only used for statistics and printed after the solving process. if this information is 2104 * needed during the (pre)solving process this should be implemented more efficiently, e.g., updating the minimal 2105 * absolute non-zero coefficient every time an objective coefficient has changed. 2106 */ 2107 SCIP_Real SCIPprobGetAbsMinObjCoef( 2108 SCIP_PROB* prob, /**< problem data */ 2109 SCIP_SET* set /**< global SCIP settings */ 2110 ) 2111 { 2112 SCIP_Real absmin; 2113 int v; 2114 2115 absmin = SCIPsetInfinity(set); 2116 2117 for( v = 0; v < prob->nvars; v++ ) 2118 { 2119 SCIP_Real objcoef = SCIPvarGetObj(prob->vars[v]); 2120 2121 if( !SCIPsetIsZero(set, objcoef) && SCIPsetIsLT(set, REALABS(objcoef), absmin) ) 2122 absmin = REALABS(objcoef); 2123 } 2124 2125 return absmin; 2126 } 2127 2128 /** returns the maximal absolute non-zero objective coefficient 2129 * 2130 * @note currently, this is only used for statistics and printed after the solving process. if this information is 2131 * needed during the (pre)solving process this should be implemented more efficiently, e.g., updating the maximal 2132 * absolute non-zero coefficient every time an objective coefficient has changed. 2133 */ 2134 SCIP_Real SCIPprobGetAbsMaxObjCoef( 2135 SCIP_PROB* prob, /**< problem data */ 2136 SCIP_SET* set /**< global SCIP settings */ 2137 ) 2138 { 2139 SCIP_Real absmax; 2140 int v; 2141 2142 absmax = -SCIPsetInfinity(set); 2143 2144 for( v = 0; v < prob->nvars; v++ ) 2145 { 2146 SCIP_Real objcoef = SCIPvarGetObj(prob->vars[v]); 2147 2148 if( !SCIPsetIsZero(set, objcoef) && SCIPsetIsGT(set, REALABS(objcoef), absmax) ) 2149 absmax = REALABS(objcoef); 2150 } 2151 2152 return absmax; 2153 } 2154 2155 2156 /** returns the external value of the given internal objective value */ 2157 SCIP_Real SCIPprobExternObjval( 2158 SCIP_PROB* transprob, /**< tranformed problem data */ 2159 SCIP_PROB* origprob, /**< original problem data */ 2160 SCIP_SET* set, /**< global SCIP settings */ 2161 SCIP_Real objval /**< internal objective value */ 2162 ) 2163 { 2164 assert(set != NULL); 2165 assert(origprob != NULL); 2166 assert(transprob != NULL); 2167 assert(transprob->transformed); 2168 assert(transprob->objscale > 0.0); 2169 2170 if( SCIPsetIsInfinity(set, objval) ) 2171 return (SCIP_Real)transprob->objsense * SCIPsetInfinity(set); 2172 else if( SCIPsetIsInfinity(set, -objval) ) 2173 return -(SCIP_Real)transprob->objsense * SCIPsetInfinity(set); 2174 else 2175 return (SCIP_Real)transprob->objsense * transprob->objscale * (objval + transprob->objoffset) + origprob->objoffset; 2176 } 2177 2178 /** returns the internal value of the given external objective value */ 2179 SCIP_Real SCIPprobInternObjval( 2180 SCIP_PROB* transprob, /**< tranformed problem data */ 2181 SCIP_PROB* origprob, /**< original problem data */ 2182 SCIP_SET* set, /**< global SCIP settings */ 2183 SCIP_Real objval /**< external objective value */ 2184 ) 2185 { 2186 assert(set != NULL); 2187 assert(origprob != NULL); 2188 assert(transprob != NULL); 2189 assert(transprob->transformed); 2190 assert(transprob->objscale > 0.0); 2191 2192 if( SCIPsetIsInfinity(set, objval) ) 2193 return (SCIP_Real)transprob->objsense * SCIPsetInfinity(set); 2194 else if( SCIPsetIsInfinity(set, -objval) ) 2195 return -(SCIP_Real)transprob->objsense * SCIPsetInfinity(set); 2196 else 2197 return (SCIP_Real)transprob->objsense * (objval - origprob->objoffset)/transprob->objscale - transprob->objoffset; 2198 } 2199 2200 /** returns variable of the problem with given name */ 2201 SCIP_VAR* SCIPprobFindVar( 2202 SCIP_PROB* prob, /**< problem data */ 2203 const char* name /**< name of variable to find */ 2204 ) 2205 { 2206 assert(prob != NULL); 2207 assert(name != NULL); 2208 2209 if( prob->varnames == NULL ) 2210 { 2211 SCIPerrorMessage("Cannot find variable if variable-names hashtable was disabled (due to parameter <misc/usevartable>)\n"); 2212 SCIPABORT();/*lint --e{527}*/ /* only in debug mode */ 2213 return NULL; 2214 } 2215 2216 return (SCIP_VAR*)(SCIPhashtableRetrieve(prob->varnames, (char*)name)); 2217 } 2218 2219 /** returns constraint of the problem with given name */ 2220 SCIP_CONS* SCIPprobFindCons( 2221 SCIP_PROB* prob, /**< problem data */ 2222 const char* name /**< name of variable to find */ 2223 ) 2224 { 2225 assert(prob != NULL); 2226 assert(name != NULL); 2227 2228 if( prob->consnames == NULL ) 2229 { 2230 SCIPerrorMessage("Cannot find constraint if constraint-names hashtable was disabled (due to parameter <misc/useconstable>)\n"); 2231 SCIPABORT();/*lint --e{527}*/ /* only in debug mode */ 2232 return NULL; 2233 } 2234 2235 return (SCIP_CONS*)(SCIPhashtableRetrieve(prob->consnames, (char*)name)); 2236 } 2237 2238 /** displays current pseudo solution */ 2239 void SCIPprobPrintPseudoSol( 2240 SCIP_PROB* prob, /**< problem data */ 2241 SCIP_SET* set, /**< global SCIP settings */ 2242 SCIP_MESSAGEHDLR* messagehdlr /**< message handler */ 2243 ) 2244 { 2245 SCIP_VAR* var; 2246 SCIP_Real solval; 2247 int v; 2248 2249 for( v = 0; v < prob->nvars; ++v ) 2250 { 2251 var = prob->vars[v]; 2252 assert(var != NULL); 2253 solval = SCIPvarGetPseudoSol(var); 2254 if( !SCIPsetIsZero(set, solval) ) 2255 SCIPmessagePrintInfo(messagehdlr, " <%s>=%.15g", SCIPvarGetName(var), solval); 2256 } 2257 SCIPmessagePrintInfo(messagehdlr, "\n"); 2258 } 2259 2260 /** outputs problem statistics */ 2261 void SCIPprobPrintStatistics( 2262 SCIP_PROB* prob, /**< problem data */ 2263 SCIP_SET* set, /**< global SCIP settings */ 2264 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 2265 FILE* file /**< output file (or NULL for standard output) */ 2266 ) 2267 { 2268 assert(prob != NULL); 2269 2270 SCIPmessageFPrintInfo(messagehdlr, file, " Problem name : %s\n", prob->name); 2271 SCIPmessageFPrintInfo(messagehdlr, file, " Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n", 2272 prob->nvars, prob->nbinvars, prob->nintvars, prob->nimplvars, prob->ncontvars); 2273 SCIPmessageFPrintInfo(messagehdlr, file, " Constraints : %d initial, %d maximal\n", prob->startnconss, prob->maxnconss); 2274 SCIPmessageFPrintInfo(messagehdlr, file, " Objective : %s, %d non-zeros (abs.min = %g, abs.max = %g)\n", 2275 !prob->transformed ? (prob->objsense == SCIP_OBJSENSE_MINIMIZE ? "minimize" : "maximize") : "minimize", 2276 SCIPprobGetNObjVars(prob, set), SCIPprobGetAbsMinObjCoef(prob, set), SCIPprobGetAbsMaxObjCoef(prob, set)); 2277 } 2278 2279 2280 #ifndef NDEBUG 2281 2282 /* In debug mode, the following methods are implemented as function calls to ensure 2283 * type validity. 2284 * In optimized mode, the methods are implemented as defines to improve performance. 2285 * However, we want to have them in the library anyways, so we have to undef the defines. 2286 */ 2287 2288 #undef SCIPprobIsPermuted 2289 #undef SCIPprobMarkPermuted 2290 #undef SCIPprobIsTransformed 2291 #undef SCIPprobIsObjIntegral 2292 #undef SCIPprobAllColsInLP 2293 #undef SCIPprobGetObjlim 2294 #undef SCIPprobGetData 2295 #undef SCIPprobGetName 2296 #undef SCIPprobGetNVars 2297 #undef SCIPprobGetNBinVars 2298 #undef SCIPprobGetNIntVars 2299 #undef SCIPprobGetNImplVars 2300 #undef SCIPprobGetNContVars 2301 #undef SCIPprobGetNConss 2302 #undef SCIPprobGetVars 2303 #undef SCIPprobGetObjoffset 2304 #undef SCIPisConsCompressedEnabled 2305 #undef SCIPprobEnableConsCompression 2306 2307 /** is the problem permuted */ 2308 SCIP_Bool SCIPprobIsPermuted( 2309 SCIP_PROB* prob 2310 ) 2311 { 2312 assert(prob != NULL); 2313 2314 return prob->permuted; 2315 } 2316 2317 /** mark the problem as permuted */ 2318 void SCIPprobMarkPermuted( 2319 SCIP_PROB* prob 2320 ) 2321 { 2322 assert(prob != NULL); 2323 2324 prob->permuted = TRUE; 2325 } 2326 2327 /** is the problem data transformed */ 2328 SCIP_Bool SCIPprobIsTransformed( 2329 SCIP_PROB* prob /**< problem data */ 2330 ) 2331 { 2332 assert(prob != NULL); 2333 2334 return prob->transformed; 2335 } 2336 2337 /** returns whether the objective value is known to be integral in every feasible solution */ 2338 SCIP_Bool SCIPprobIsObjIntegral( 2339 SCIP_PROB* prob /**< problem data */ 2340 ) 2341 { 2342 assert(prob != NULL); 2343 2344 return prob->objisintegral; 2345 } 2346 2347 /** returns TRUE iff all columns, i.e. every variable with non-empty column w.r.t. all ever created rows, are present 2348 * in the LP, and FALSE, if there are additional already existing columns, that may be added to the LP in pricing 2349 */ 2350 SCIP_Bool SCIPprobAllColsInLP( 2351 SCIP_PROB* prob, /**< problem data */ 2352 SCIP_SET* set, /**< global SCIP settings */ 2353 SCIP_LP* lp /**< current LP data */ 2354 ) 2355 { 2356 assert(SCIPlpGetNCols(lp) <= prob->ncolvars && prob->ncolvars <= prob->nvars); 2357 2358 return (SCIPlpGetNCols(lp) == prob->ncolvars && set->nactivepricers == 0); 2359 } 2360 2361 /** gets limit on objective function in external space */ 2362 SCIP_Real SCIPprobGetObjlim( 2363 SCIP_PROB* prob, /**< problem data */ 2364 SCIP_SET* set /**< global SCIP settings */ 2365 ) 2366 { 2367 assert(prob != NULL); 2368 assert(set != NULL); 2369 2370 return prob->objlim >= SCIP_INVALID ? (SCIP_Real)(prob->objsense) * SCIPsetInfinity(set) : prob->objlim; 2371 } 2372 2373 /** gets user problem data */ 2374 SCIP_PROBDATA* SCIPprobGetData( 2375 SCIP_PROB* prob /**< problem */ 2376 ) 2377 { 2378 assert(prob != NULL); 2379 2380 return prob->probdata; 2381 } 2382 2383 /** gets problem name */ 2384 const char* SCIPprobGetName( 2385 SCIP_PROB* prob /**< problem data */ 2386 ) 2387 { 2388 assert(prob != NULL); 2389 return prob->name; 2390 } 2391 2392 /** gets number of problem variables */ 2393 int SCIPprobGetNVars( 2394 SCIP_PROB* prob /**< problem data */ 2395 ) 2396 { 2397 assert(prob != NULL); 2398 return prob->nvars; 2399 } 2400 2401 /** gets number of binary problem variables */ 2402 int SCIPprobGetNBinVars( 2403 SCIP_PROB* prob /**< problem data */ 2404 ) 2405 { 2406 assert(prob != NULL); 2407 return prob->nbinvars; 2408 } 2409 2410 /** gets number of integer problem variables */ 2411 int SCIPprobGetNIntVars( 2412 SCIP_PROB* prob /**< problem data */ 2413 ) 2414 { 2415 assert(prob != NULL); 2416 return prob->nintvars; 2417 } 2418 2419 /** gets number of implicit integer problem variables */ 2420 int SCIPprobGetNImplVars( 2421 SCIP_PROB* prob /**< problem data */ 2422 ) 2423 { 2424 assert(prob != NULL); 2425 return prob->nimplvars; 2426 } 2427 2428 /** gets number of continuous problem variables */ 2429 int SCIPprobGetNContVars( 2430 SCIP_PROB* prob /**< problem data */ 2431 ) 2432 { 2433 assert(prob != NULL); 2434 return prob->ncontvars; 2435 } 2436 2437 /** gets problem variables */ 2438 SCIP_VAR** SCIPprobGetVars( 2439 SCIP_PROB* prob /**< problem data */ 2440 ) 2441 { 2442 assert(prob != NULL); 2443 return prob->vars; 2444 } 2445 2446 /** gets number of problem constraints */ 2447 int SCIPprobGetNConss( 2448 SCIP_PROB* prob /**< problem data */ 2449 ) 2450 { 2451 assert(prob != NULL); 2452 return prob->nconss; 2453 } 2454 2455 /** gets the objective offset */ 2456 SCIP_Real SCIPprobGetObjoffset( 2457 SCIP_PROB* prob /**< problem data */ 2458 ) 2459 { 2460 assert(prob != NULL); 2461 return prob->objoffset; 2462 } 2463 2464 /** gets the objective scalar */ 2465 SCIP_Real SCIPprobGetObjscale( 2466 SCIP_PROB* prob /**< problem data */ 2467 ) 2468 { 2469 assert(prob != NULL); 2470 return prob->objscale; 2471 } 2472 2473 /** is constraint compression enabled for this problem? */ 2474 SCIP_Bool SCIPprobIsConsCompressionEnabled( 2475 SCIP_PROB* prob /**< problem data */ 2476 ) 2477 { 2478 assert(prob != NULL); 2479 2480 return prob->conscompression; 2481 } 2482 2483 /** enable problem compression, i.e., constraints can reduce memory size by removing fixed variables during creation */ 2484 void SCIPprobEnableConsCompression( 2485 SCIP_PROB* prob /**< problem data */ 2486 ) 2487 { 2488 assert(prob != NULL); 2489 2490 prob->conscompression = TRUE; 2491 } 2492 2493 #endif 2494