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 branch_vanillafullstrong.c 26 * @ingroup DEFPLUGINS_BRANCH 27 * @brief vanilla full strong LP branching rule 28 * @author Tobias Achterberg 29 * @author Maxime Gasse 30 */ 31 32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 33 34 #include "blockmemshell/memory.h" 35 #include "scip/branch_vanillafullstrong.h" 36 #include "scip/pub_branch.h" 37 #include "scip/pub_message.h" 38 #include "scip/pub_tree.h" 39 #include "scip/pub_var.h" 40 #include "scip/scip_branch.h" 41 #include "scip/scip_general.h" 42 #include "scip/scip_lp.h" 43 #include "scip/scip_mem.h" 44 #include "scip/scip_message.h" 45 #include "scip/scip_numerics.h" 46 #include "scip/scip_param.h" 47 #include "scip/scip_prob.h" 48 #include "scip/scip_solvingstats.h" 49 #include "scip/scip_tree.h" 50 #include "scip/scip_var.h" 51 #include <string.h> 52 53 54 #define BRANCHRULE_NAME "vanillafullstrong" 55 #define BRANCHRULE_DESC "vanilla full strong branching" 56 #define BRANCHRULE_PRIORITY -2000 57 #define BRANCHRULE_MAXDEPTH -1 58 #define BRANCHRULE_MAXBOUNDDIST 1.0 59 60 #define DEFAULT_INTEGRALCANDS FALSE /**< should integral variables in the current LP solution be considered as 61 * branching candidates ? */ 62 #define DEFAULT_SCOREALL FALSE /**< should strong branching scores be computed for all candidates, or can 63 * we early stop when a variable has infinite score ? */ 64 #define DEFAULT_IDEMPOTENT FALSE /**< should strong branching side-effects be prevented (e.g., domain 65 * changes, stat updates etc.) ? */ 66 #define DEFAULT_COLLECTSCORES FALSE /**< should strong branching scores be collected ? */ 67 #define DEFAULT_DONOTBRANCH FALSE /**< should branching be done ? */ 68 69 70 /** branching rule data */ 71 struct SCIP_BranchruleData 72 { 73 SCIP_Bool integralcands; /**< should integral variables in the current LP solution be considered 74 * as branching candidates ? */ 75 SCIP_Bool scoreall; /**< should strong branching scores be computed for all candidates, or 76 * can we early stop when a node is detected infeasible ? */ 77 SCIP_Bool idempotent; /**< should strong branching side-effects be prevented (e.g., domain 78 * changes, stat updates etc.) ? */ 79 SCIP_Bool collectscores; /**< should strong branching scores be collected ? */ 80 SCIP_Bool donotbranch; /**< should branching be done ? */ 81 SCIP_VAR** cands; /**< candidate variables */ 82 SCIP_Real* candscores; /**< candidate scores */ 83 int ncands; /**< number of candidates */ 84 int npriocands; /**< number of priority candidates */ 85 int bestcand; /**< best branching candidate */ 86 int candcapacity; /**< capacity of candidate arrays */ 87 }; 88 89 90 /* 91 * local methods 92 */ 93 94 95 /** selects a variable from a set of candidates by strong branching */ 96 static 97 SCIP_RETCODE runVanillaStrongBranching( 98 SCIP* scip, /**< SCIP data structure */ 99 SCIP_VAR** cands, /**< branching candidates */ 100 int ncands, /**< number of branching candidates */ 101 int npriocands, /**< number of branching candidates with highest priority */ 102 SCIP_Bool scoreall, /**< should strong branching scores be computed for all candidates, or can 103 * we early stop when a node is detected infeasible ? */ 104 SCIP_Bool idempotent, /**< should strong branching side-effects be prevented (e.g., domain 105 * changes, stat updates etc.) ? */ 106 SCIP_Real* scores, /**< candidate scores */ 107 int* bestcand, /**< best candidate for branching */ 108 SCIP_Real* bestdown, /**< objective value of the down branch for bestcand */ 109 SCIP_Real* bestup, /**< objective value of the up branch for bestcand */ 110 SCIP_Real* bestscore, /**< score for bestcand */ 111 SCIP_Bool* bestdownvalid, /**< is bestdown a valid dual bound for the down branch? */ 112 SCIP_Bool* bestupvalid, /**< is bestup a valid dual bound for the up branch? */ 113 SCIP_Real* provedbound /**< proved dual bound for current subtree */ 114 ) 115 { /*lint --e{715}*/ 116 SCIP_Real lpobjval; 117 int nsbcalls; 118 int c; 119 120 assert(scip != NULL); 121 assert(cands != NULL); 122 assert(bestcand != NULL); 123 assert(bestdown != NULL); 124 assert(bestup != NULL); 125 assert(bestscore != NULL); 126 assert(bestdownvalid != NULL); 127 assert(bestupvalid != NULL); 128 assert(provedbound != NULL); 129 assert(ncands > 0); 130 131 /* get current LP objective bound of the local sub problem and global cutoff bound */ 132 lpobjval = SCIPgetLPObjval(scip); 133 *provedbound = lpobjval; 134 135 *bestcand = 0; 136 *bestdown = lpobjval; 137 *bestup = lpobjval; 138 *bestdownvalid = TRUE; 139 *bestupvalid = TRUE; 140 *bestscore = -SCIPinfinity(scip); 141 142 if( scores != NULL ) 143 for( c = 0; c < ncands; ++c ) 144 scores[c] = -SCIPinfinity(scip); 145 146 /* if only one candidate exists, choose this one without applying strong branching; also, when SCIP is about to be 147 * stopped, all strongbranching evaluations will be aborted anyway, thus we can return immediately 148 */ 149 if( (!scoreall && ncands == 1) || SCIPisStopped(scip) ) 150 return SCIP_OKAY; 151 152 /* this assert may not hold if SCIP is stopped, thus we only check it here */ 153 assert(SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL); 154 155 /* initialize strong branching without propagation */ 156 SCIP_CALL( SCIPstartStrongbranch(scip, FALSE) ); 157 158 /* compute strong branching scores */ 159 nsbcalls = 0; 160 for( c = 0; c < ncands ; ++c ) 161 { 162 SCIP_VAR* var; 163 SCIP_Real val; 164 SCIP_Bool integral; 165 SCIP_Real down, up; 166 SCIP_Real downgain, upgain; 167 SCIP_Bool downvalid, upvalid; 168 SCIP_Bool downinf, upinf; 169 SCIP_Bool downconflict, upconflict; 170 SCIP_Bool lperror; 171 SCIP_Real gains[3]; 172 SCIP_Real score; 173 174 var = cands[c]; 175 assert(var != NULL); 176 177 val = SCIPvarGetLPSol(var); 178 integral = SCIPisFeasIntegral(scip, val); 179 180 up = -SCIPinfinity(scip); 181 down = -SCIPinfinity(scip); 182 183 SCIPdebugMsg(scip, "applying vanilla strong branching on variable <%s> with solution %g\n", 184 SCIPvarGetName(var), val); 185 186 /* apply strong branching */ 187 if( integral ) 188 { 189 SCIP_CALL( SCIPgetVarStrongbranchInt(scip, cands[c], INT_MAX, idempotent, 190 &down, &up, &downvalid, &upvalid, &downinf, &upinf, &downconflict, &upconflict, &lperror) ); 191 } 192 else 193 { 194 SCIP_CALL( SCIPgetVarStrongbranchFrac(scip, cands[c], INT_MAX, idempotent, 195 &down, &up, &downvalid, &upvalid, &downinf, &upinf, &downconflict, &upconflict, &lperror) ); 196 } 197 nsbcalls++; 198 199 /* check for an error in strong branching */ 200 if( lperror ) 201 { 202 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, 203 "(node %" SCIP_LONGINT_FORMAT ") error in strong branching call for variable <%s> with solution %g\n", 204 SCIPgetNNodes(scip), SCIPvarGetName(var), val); 205 break; 206 } 207 208 /* evaluate strong branching */ 209 down = MAX(down, lpobjval); 210 up = MAX(up, lpobjval); 211 downgain = down - lpobjval; 212 upgain = up - lpobjval; 213 214 assert(!SCIPallColsInLP(scip) || SCIPisExactSolve(scip) || !downvalid || downinf == SCIPisGE(scip, down, SCIPgetCutoffbound(scip))); 215 assert(!SCIPallColsInLP(scip) || SCIPisExactSolve(scip) || !upvalid || upinf == SCIPisGE(scip, up, SCIPgetCutoffbound(scip))); 216 assert(downinf || !downconflict); 217 assert(upinf || !upconflict); 218 219 if( !idempotent ) 220 { 221 /* display node information line */ 222 if( SCIPgetDepth(scip) == 0 && nsbcalls % 100 == 0 ) 223 { 224 SCIP_CALL( SCIPprintDisplayLine(scip, NULL, SCIP_VERBLEVEL_HIGH, TRUE) ); 225 } 226 /* update variable pseudo cost values */ 227 if( !downinf && downvalid ) 228 { 229 SCIP_CALL( SCIPupdateVarPseudocost(scip, var, integral ? -1.0 : 0.0 - SCIPfrac(scip, val), downgain, 1.0) ); 230 } 231 if( !upinf && upvalid ) 232 { 233 SCIP_CALL( SCIPupdateVarPseudocost(scip, var, integral ? +1.0 : 1.0 - SCIPfrac(scip, val), upgain, 1.0) ); 234 } 235 } 236 237 /* compute strong branching score */ 238 gains[0] = downgain; 239 gains[1] = upgain; 240 gains[2] = 0.0; 241 score = SCIPgetBranchScoreMultiple(scip, var, integral ? 3 : 2, gains); 242 243 /* collect scores if requested */ 244 if( scores != NULL ) 245 scores[c] = score; 246 247 /* check for a better score */ 248 if( score > *bestscore ) 249 { 250 *bestcand = c; 251 *bestdown = down; 252 *bestup = up; 253 *bestdownvalid = downvalid; 254 *bestupvalid = upvalid; 255 *bestscore = score; 256 } 257 258 SCIPdebugMsg(scip, " -> cand %d/%d (prio:%d) var <%s> (solval=%g, downgain=%g, upgain=%g, score=%g) -- best: <%s> (%g)\n", 259 c, ncands, npriocands, SCIPvarGetName(var), val, downgain, upgain, score, 260 SCIPvarGetName(cands[*bestcand]), *bestscore); 261 262 /* node is infeasible -> early stopping (highest score) */ 263 if( !integral && !scoreall && downinf && upinf ) 264 { 265 /* we should only detect infeasibility if the LP is a valid relaxation */ 266 assert(SCIPallColsInLP(scip)); 267 assert(!SCIPisExactSolve(scip)); 268 269 SCIPdebugMsg(scip, " -> variable <%s> is infeasible in both directions\n", SCIPvarGetName(var)); 270 break; 271 } 272 } 273 274 /* end strong branching */ 275 SCIP_CALL( SCIPendStrongbranch(scip) ); 276 277 return SCIP_OKAY; 278 } 279 280 /* 281 * Callback methods 282 */ 283 284 /** copy method for branchrule plugins (called when SCIP copies plugins) */ 285 static 286 SCIP_DECL_BRANCHCOPY(branchCopyVanillafullstrong) 287 { /*lint --e{715}*/ 288 assert(scip != NULL); 289 assert(branchrule != NULL); 290 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0); 291 292 /* call inclusion method of branchrule */ 293 SCIP_CALL( SCIPincludeBranchruleVanillafullstrong(scip) ); 294 295 return SCIP_OKAY; 296 } 297 298 /** destructor of branching rule to free user data (called when SCIP is exiting) */ 299 static 300 SCIP_DECL_BRANCHFREE(branchFreeVanillafullstrong) 301 { /*lint --e{715}*/ 302 SCIP_BRANCHRULEDATA* branchruledata; 303 304 /* free branching rule data */ 305 branchruledata = SCIPbranchruleGetData(branchrule); 306 assert(branchruledata != NULL); 307 308 SCIPfreeBlockMemoryNull(scip, &branchruledata); 309 310 return SCIP_OKAY; 311 } 312 313 /** initialization method of branching rule (called after problem was transformed) */ 314 static 315 SCIP_DECL_BRANCHINIT(branchInitVanillafullstrong) 316 { /*lint --e{715}*/ 317 #ifndef NDEBUG 318 SCIP_BRANCHRULEDATA* branchruledata; 319 320 /* initialize branching rule data */ 321 branchruledata = SCIPbranchruleGetData(branchrule); 322 #endif 323 assert(branchruledata != NULL); 324 assert(branchruledata->candscores == NULL); 325 assert(branchruledata->cands == NULL); 326 327 return SCIP_OKAY; 328 } 329 330 /** deinitialization method of branching rule (called before transformed problem is freed) */ 331 static 332 SCIP_DECL_BRANCHEXIT(branchExitVanillafullstrong) 333 { /*lint --e{715}*/ 334 SCIP_BRANCHRULEDATA* branchruledata; 335 336 /* initialize branching rule data */ 337 branchruledata = SCIPbranchruleGetData(branchrule); 338 assert(branchruledata != NULL); 339 340 /* free candidate arrays if any */ 341 if( branchruledata->candscores != NULL ) 342 { 343 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->candscores, branchruledata->candcapacity); 344 } 345 if( branchruledata->cands != NULL ) 346 { 347 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->cands, branchruledata->candcapacity); 348 } 349 350 branchruledata->candcapacity = -1; 351 branchruledata->ncands = -1; 352 branchruledata->npriocands = -1; 353 branchruledata->bestcand = -1; 354 355 return SCIP_OKAY; 356 } 357 358 /** branching execution method */ 359 static 360 SCIP_DECL_BRANCHEXECLP(branchExeclpVanillafullstrong) 361 { /*lint --e{715}*/ 362 SCIP_BRANCHRULEDATA* branchruledata; 363 SCIP_Real bestdown; 364 SCIP_Real bestup; 365 SCIP_Real bestscore; 366 SCIP_Real provedbound; 367 SCIP_Bool bestdownvalid; 368 SCIP_Bool bestupvalid; 369 SCIP_VAR** cands; 370 int ncands; 371 int npriocands; 372 int i; 373 374 assert(branchrule != NULL); 375 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0); 376 assert(scip != NULL); 377 assert(result != NULL); 378 379 SCIPdebugMsg(scip, "Execlp method of vanilla fullstrong branching\n"); 380 381 *result = SCIP_DIDNOTRUN; 382 383 /* get branching rule data */ 384 branchruledata = SCIPbranchruleGetData(branchrule); 385 assert(branchruledata != NULL); 386 387 /* get branching candidates, either all non-fixed variables or only the 388 * fractional ones */ 389 if( branchruledata->integralcands ) 390 { 391 SCIP_CALL( SCIPgetPseudoBranchCands(scip, &cands, &ncands, &npriocands) ); 392 } 393 else 394 { 395 SCIP_CALL( SCIPgetLPBranchCands(scip, &cands, NULL, NULL, &ncands, &npriocands, NULL) ); 396 } 397 398 assert(ncands > 0); 399 assert(npriocands > 0); 400 401 /* increase candidate arrays capacity if needed */ 402 if( ncands > branchruledata->candcapacity ) 403 { 404 /* free previously allocated arrays if any */ 405 if( branchruledata->candscores != NULL) 406 { 407 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->candscores, branchruledata->candcapacity); 408 branchruledata->candscores = NULL; 409 } 410 if( branchruledata->cands != NULL) 411 { 412 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->cands, branchruledata->candcapacity); 413 branchruledata->cands = NULL; 414 } 415 416 /* update capacity */ 417 branchruledata->candcapacity = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) + SCIPgetNImplVars(scip); 418 } 419 assert(branchruledata->candcapacity >= ncands); 420 421 /* allocate new candidate arrays if needed */ 422 if( branchruledata->cands == NULL ) 423 { 424 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->cands, branchruledata->candcapacity) ); 425 } 426 if( branchruledata->candscores == NULL && branchruledata->collectscores ) 427 { 428 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->candscores, branchruledata->candcapacity) ); 429 } 430 431 /* copy candidates */ 432 branchruledata->ncands = ncands; 433 branchruledata->npriocands = npriocands; 434 435 for( i = 0; i < ncands; i++ ) 436 branchruledata->cands[i] = cands[i]; 437 438 SCIP_CALL( runVanillaStrongBranching(scip, branchruledata->cands, branchruledata->ncands, branchruledata->npriocands, 439 branchruledata->scoreall, branchruledata->idempotent, branchruledata->candscores, 440 &branchruledata->bestcand, &bestdown, &bestup, &bestscore, &bestdownvalid, 441 &bestupvalid, &provedbound) ); 442 443 if( !branchruledata->donotbranch ) 444 { 445 SCIP_VAR* var; 446 SCIP_Real val; 447 SCIP_NODE* downchild; 448 SCIP_NODE* eqchild; 449 SCIP_NODE* upchild; 450 SCIP_Bool allcolsinlp; 451 SCIP_Bool exactsolve; 452 453 assert(0 <= branchruledata->bestcand && branchruledata->bestcand < branchruledata->ncands); 454 assert(SCIPisLT(scip, provedbound, SCIPgetCutoffbound(scip))); 455 456 var = branchruledata->cands[branchruledata->bestcand]; 457 val = SCIPvarGetLPSol(var); 458 459 /* perform the branching */ 460 SCIPdebugMsg(scip, " -> %d candidates, selected candidate %d: variable <%s>[%g,%g] (solval=%g, down=%g, up=%g, score=%g)\n", 461 branchruledata->ncands, branchruledata->bestcand, SCIPvarGetName(var), SCIPvarGetLbLocal(var), 462 SCIPvarGetUbLocal(var), val, bestdown, bestup, bestscore); 463 SCIP_CALL( SCIPbranchVarVal(scip, var, val, &downchild, &eqchild, &upchild) ); 464 465 /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful 466 * for cutting off sub problems and improving lower bounds of children 467 */ 468 exactsolve = SCIPisExactSolve(scip); 469 470 /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */ 471 allcolsinlp = SCIPallColsInLP(scip); 472 473 /* update the lower bounds in the children */ 474 if( !branchruledata->idempotent && allcolsinlp && !exactsolve ) 475 { 476 if( downchild != NULL ) 477 { 478 SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, bestdownvalid ? MAX(bestdown, provedbound) : provedbound) ); 479 SCIPdebugMsg(scip, " -> down child's lowerbound: %g\n", SCIPnodeGetLowerbound(downchild)); 480 } 481 if( eqchild != NULL ) 482 { 483 SCIP_CALL( SCIPupdateNodeLowerbound(scip, eqchild, provedbound) ); 484 SCIPdebugMsg(scip, " -> eq child's lowerbound: %g\n", SCIPnodeGetLowerbound(eqchild)); 485 } 486 if( upchild != NULL ) 487 { 488 SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, bestupvalid ? MAX(bestup, provedbound) : provedbound) ); 489 SCIPdebugMsg(scip, " -> up child's lowerbound: %g\n", SCIPnodeGetLowerbound(upchild)); 490 } 491 } 492 493 *result = SCIP_BRANCHED; 494 } 495 496 return SCIP_OKAY; 497 } 498 499 500 /* 501 * branching specific interface methods 502 */ 503 504 /** creates the vanilla full strong LP branching rule and includes it in SCIP */ 505 SCIP_RETCODE SCIPincludeBranchruleVanillafullstrong( 506 SCIP* scip /**< SCIP data structure */ 507 ) 508 { 509 SCIP_BRANCHRULEDATA* branchruledata; 510 SCIP_BRANCHRULE* branchrule; 511 512 /* create fullstrong branching rule data */ 513 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) ); 514 branchruledata->cands = NULL; 515 branchruledata->candscores = NULL; 516 branchruledata->candcapacity = -1; 517 branchruledata->ncands = -1; 518 branchruledata->npriocands = -1; 519 branchruledata->bestcand = -1; 520 521 /* include branching rule */ 522 SCIP_CALL( SCIPincludeBranchruleBasic(scip, &branchrule, BRANCHRULE_NAME, BRANCHRULE_DESC, BRANCHRULE_PRIORITY, 523 BRANCHRULE_MAXDEPTH, BRANCHRULE_MAXBOUNDDIST, branchruledata) ); 524 525 assert(branchrule != NULL); 526 527 /* set non-fundamental callbacks via specific setter functions*/ 528 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyVanillafullstrong) ); 529 SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeVanillafullstrong) ); 530 SCIP_CALL( SCIPsetBranchruleInit(scip, branchrule, branchInitVanillafullstrong) ); 531 SCIP_CALL( SCIPsetBranchruleExit(scip, branchrule, branchExitVanillafullstrong) ); 532 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpVanillafullstrong) ); 533 534 /* fullstrong branching rule parameters */ 535 SCIP_CALL( SCIPaddBoolParam(scip, 536 "branching/vanillafullstrong/integralcands", 537 "should integral variables in the current LP solution be considered as branching candidates?", 538 &branchruledata->integralcands, FALSE, DEFAULT_INTEGRALCANDS, NULL, NULL) ); 539 SCIP_CALL( SCIPaddBoolParam(scip, 540 "branching/vanillafullstrong/idempotent", 541 "should strong branching side-effects be prevented (e.g., domain changes, stat updates etc.)?", 542 &branchruledata->idempotent, FALSE, DEFAULT_IDEMPOTENT, NULL, NULL) ); 543 SCIP_CALL( SCIPaddBoolParam(scip, 544 "branching/vanillafullstrong/scoreall", 545 "should strong branching scores be computed for all candidates, or can we early stop when a variable has infinite score?", 546 &branchruledata->scoreall, TRUE, DEFAULT_SCOREALL, NULL, NULL) ); 547 SCIP_CALL( SCIPaddBoolParam(scip, 548 "branching/vanillafullstrong/collectscores", 549 "should strong branching scores be collected?", 550 &branchruledata->collectscores, TRUE, DEFAULT_COLLECTSCORES, NULL, NULL) ); 551 SCIP_CALL( SCIPaddBoolParam(scip, 552 "branching/vanillafullstrong/donotbranch", 553 "should candidates only be scored, but no branching be performed?", 554 &branchruledata->donotbranch, TRUE, DEFAULT_DONOTBRANCH, NULL, NULL) ); 555 556 return SCIP_OKAY; 557 } 558 559 560 /** recovers candidate variables and their scores from last vanilla full strong branching call */ 561 SCIP_RETCODE SCIPgetVanillafullstrongData( 562 SCIP* scip, /**< SCIP data structure */ 563 SCIP_VAR*** cands, /**< pointer to store candidate variables; or NULL */ 564 SCIP_Real** candscores, /**< pointer to store candidate scores; or NULL */ 565 int* ncands, /**< pointer to store number of candidates; or NULL */ 566 int* npriocands, /**< pointer to store number of priority candidates; or NULL */ 567 int* bestcand /**< pointer to store best branching candidate; or NULL */ 568 ) 569 { 570 SCIP_BRANCHRULEDATA* branchruledata; 571 SCIP_BRANCHRULE* branchrule; 572 573 assert(scip != NULL); 574 575 branchrule = SCIPfindBranchrule(scip, BRANCHRULE_NAME); 576 assert( branchrule != NULL ); 577 branchruledata = SCIPbranchruleGetData(branchrule); 578 assert( branchruledata != NULL ); 579 580 if( cands ) 581 { 582 *cands = branchruledata->cands; 583 } 584 if( candscores && branchruledata->collectscores ) 585 { 586 *candscores = branchruledata->candscores; 587 } 588 if( ncands ) 589 { 590 *ncands = branchruledata->ncands; 591 } 592 if( npriocands ) 593 { 594 *npriocands = branchruledata->npriocands; 595 } 596 if( bestcand ) 597 { 598 *bestcand = branchruledata->bestcand; 599 } 600 601 return SCIP_OKAY; 602 } 603