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