Scippy

SCIP

Solving Constraint Integer Programs

branch_fullstrong.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 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_fullstrong.c
26 * @ingroup DEFPLUGINS_BRANCH
27 * @brief full strong LP branching rule
28 * @author Tobias Achterberg
29 * @author Gerald Gamrath
30 */
31
32/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33
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_exact.h"
42#include "scip/scip_general.h"
43#include "scip/scip_lp.h"
44#include "scip/scip_mem.h"
45#include "scip/scip_message.h"
46#include "scip/scip_numerics.h"
47#include "scip/scip_param.h"
48#include "scip/scip_prob.h"
50#include "scip/scip_tree.h"
51#include "scip/scip_var.h"
52#include <string.h>
53
54
55#define BRANCHRULE_NAME "fullstrong"
56#define BRANCHRULE_DESC "full strong branching"
57#define BRANCHRULE_PRIORITY 0
58#define BRANCHRULE_MAXDEPTH -1
59#define BRANCHRULE_MAXBOUNDDIST 1.0
60
61#define DEFAULT_REEVALAGE 10LL /**< number of intermediate LPs solved to trigger reevaluation of strong branching
62 * value for a variable that was already evaluated at the current node */
63#define DEFAULT_MAXPROPROUNDS -2 /**< maximum number of propagation rounds to be performed during strong branching
64 * before solving the LP (-1: no limit, -2: parameter settings) */
65#define DEFAULT_PROBINGBOUNDS TRUE /**< should valid bounds be identified in a probing-like fashion during strong
66 * branching (only with propagation)? */
67#define DEFAULT_FORCESTRONGBRANCH FALSE /**< should strong branching be applied even if there is just a single candidate? */
68
69
70/** branching rule data */
71struct SCIP_BranchruleData
72{
73 SCIP_Longint reevalage; /**< number of intermediate LPs solved to trigger reevaluation of strong branching
74 * value for a variable that was already evaluated at the current node */
75 int maxproprounds; /**< maximum number of propagation rounds to be performed during strong branching
76 * before solving the LP (-1: no limit, -2: parameter settings) */
77 SCIP_Bool probingbounds; /**< should valid bounds be identified in a probing-like fashion during strong
78 * branching (only with propagation)? */
79 SCIP_Bool forcestrongbranch; /**< should strong branching be applied even if there is just a single candidate? */
80 int lastcand; /**< last evaluated candidate of last branching rule execution */
81 int skipsize; /**< size of skipdown and skipup array */
82 SCIP_Bool* skipdown; /**< should be branching on down child be skipped? */
83 SCIP_Bool* skipup; /**< should be branching on up child be skipped? */
84};
85
86
87/*
88 * Callback methods
89 */
90
91/** copy method for branchrule plugins (called when SCIP copies plugins) */
92static
93SCIP_DECL_BRANCHCOPY(branchCopyFullstrong)
94{ /*lint --e{715}*/
95 assert(scip != NULL);
96 assert(branchrule != NULL);
97 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
98
99 /* call inclusion method of branchrule */
101
102 return SCIP_OKAY;
103}
104
105/** destructor of branching rule to free user data (called when SCIP is exiting) */
106static
107SCIP_DECL_BRANCHFREE(branchFreeFullstrong)
108{ /*lint --e{715}*/
109 SCIP_BRANCHRULEDATA* branchruledata;
110
111 /* free branching rule data */
112 branchruledata = SCIPbranchruleGetData(branchrule);
113 assert(branchruledata != NULL);
114
115 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipdown, branchruledata->skipsize);
116 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipup, branchruledata->skipsize);
117
118 SCIPfreeBlockMemory(scip, &branchruledata);
119 SCIPbranchruleSetData(branchrule, NULL);
120
121 return SCIP_OKAY;
122}
123
124
125/** initialization method of branching rule (called after problem was transformed) */
126static
127SCIP_DECL_BRANCHINIT(branchInitFullstrong)
128{ /*lint --e{715}*/
129 SCIP_BRANCHRULEDATA* branchruledata;
130
131 /* initialize branching rule data */
132 branchruledata = SCIPbranchruleGetData(branchrule);
133 assert(branchruledata != NULL);
134
135 branchruledata->lastcand = 0;
136
137 return SCIP_OKAY;
138}
139
140/** deinitialization method of branching rule (called before transformed problem is freed) */
141static
142SCIP_DECL_BRANCHEXIT(branchExitFullstrong)
143{ /*lint --e{715}*/
144 SCIP_BRANCHRULEDATA* branchruledata;
145
146 /* initialize branching rule data */
147 branchruledata = SCIPbranchruleGetData(branchrule);
148 assert(branchruledata != NULL);
149 assert((branchruledata->skipdown != NULL) == (branchruledata->skipup != NULL));
150
151 if( branchruledata->skipdown != NULL )
152 {
153 SCIPfreeBlockMemoryArray(scip, &branchruledata->skipup, branchruledata->skipsize);
154 SCIPfreeBlockMemoryArray(scip, &branchruledata->skipdown, branchruledata->skipsize);
155 branchruledata->skipdown = NULL;
156 branchruledata->skipup = NULL;
157 branchruledata->skipsize = 0;
158 }
159
160 return SCIP_OKAY;
161}
162
163/**
164 * Selects a variable from a set of candidates by strong branching
165 *
166 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
167 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
168 *
169 * @note The variables in the lpcands array must have a fractional value in the current LP solution
170 */
172 SCIP* scip, /**< original SCIP data structure */
173 SCIP_VAR** lpcands, /**< branching candidates */
174 SCIP_Real* lpcandssol, /**< solution values of the branching candidates */
175 SCIP_Real* lpcandsfrac, /**< fractional values of the branching candidates */
176 SCIP_Bool* skipdown, /**< should down branchings be skipped? */
177 SCIP_Bool* skipup, /**< should up branchings be skipped? */
178 int nlpcands, /**< number of branching candidates */
179 int npriolpcands, /**< number of priority branching candidates */
180 int ncomplete, /**< number of branching candidates without skip */
181 int* start, /**< starting index in lpcands */
182 int maxproprounds, /**< maximum number of propagation rounds to be performed during strong
183 * branching before solving the LP (-1: no limit, -2: parameter settings) */
184 SCIP_Bool probingbounds, /**< should valid bounds be identified in a probing-like fashion during
185 * strong branching (only with propagation)? */
186 SCIP_Bool forcestrongbranch, /**< should strong branching be applied even if there is just a single candidate? */
187 int* bestcand, /**< best candidate for branching */
188 SCIP_Real* bestdown, /**< objective value of the down branch for bestcand */
189 SCIP_Real* bestup, /**< objective value of the up branch for bestcand */
190 SCIP_Real* bestscore, /**< score for bestcand */
191 SCIP_Bool* bestdownvalid, /**< is bestdown a valid dual bound for the down branch? */
192 SCIP_Bool* bestupvalid, /**< is bestup a valid dual bound for the up branch? */
193 SCIP_Real* provedbound, /**< proved dual bound for current subtree */
194 SCIP_RESULT* result /**< result pointer */
195 )
196{ /*lint --e{715}*/
197 SCIP_VAR** vars = NULL;
198 SCIP_Real* newlbs = NULL;
199 SCIP_Real* newubs = NULL;
200 SCIP_BRANCHRULE* branchrule;
201 SCIP_BRANCHRULEDATA* branchruledata;
202 SCIP_Longint reevalage;
203 SCIP_Longint nodenum;
204 SCIP_Real down;
205 SCIP_Real up;
206 SCIP_Real downgain;
207 SCIP_Real upgain;
208 SCIP_Real score;
209 SCIP_Real lpobjval;
210 SCIP_Bool exactsolve;
211 SCIP_Bool lperror;
212 SCIP_Bool allcolsinlp;
213 SCIP_Bool downvalid;
214 SCIP_Bool upvalid;
215 SCIP_Bool downinf;
216 SCIP_Bool upinf;
217 SCIP_Bool downconflict;
218 SCIP_Bool upconflict;
219 SCIP_Bool bothgains;
220 SCIP_Bool propagate;
221 int nvars = 0;
222 int nsbcalls;
223 int i;
224 int c;
225
226 assert(scip != NULL);
227 assert(lpcands != NULL);
228 assert(lpcandssol != NULL);
229 assert(lpcandsfrac != NULL);
230 assert(bestcand != NULL);
231 assert(skipdown != NULL);
232 assert(skipup != NULL);
233 assert(bestdown != NULL);
234 assert(bestup != NULL);
235 assert(bestscore != NULL);
236 assert(bestdownvalid != NULL);
237 assert(bestupvalid != NULL);
238 assert(provedbound != NULL);
239 assert(result != NULL);
240 assert(nlpcands > 0);
241
242 /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful
243 * for cutting off sub problems and improving lower bounds of children
244 */
245 exactsolve = SCIPisExact(scip);
246
247 /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */
248 allcolsinlp = SCIPallColsInLP(scip);
249
250 /* get current node number */
251 nodenum = SCIPgetNNodes(scip);
252
253 /* get current LP objective bound of the local sub problem and global cutoff bound */
254 lpobjval = SCIPgetLPObjval(scip);
255 *provedbound = lpobjval;
256
257 *bestcand = 0;
258 *bestdown = lpobjval;
259 *bestup = lpobjval;
260 *bestdownvalid = FALSE;
261 *bestupvalid = FALSE;
262 *bestscore = -SCIPinfinity(scip);
263
264 /* if only one candidate exists, choose this one without applying strong branching; also, when SCIP is about to be
265 * stopped, all strongbranching evaluations will be aborted anyway, thus we can return immediately
266 */
267 if( (!forcestrongbranch && nlpcands == 1) || SCIPisStopped(scip) )
268 return SCIP_OKAY;
269
270 /* this assert may not hold if SCIP is stopped, thus we only check it here */
272
273 /* get branching rule */
275 assert(branchrule != NULL);
276
277 /* get branching rule data */
278 branchruledata = SCIPbranchruleGetData(branchrule);
279 assert(branchruledata != NULL);
280
281 /* auto-setting for reevalage */
282 reevalage = branchruledata->reevalage;
283
284 /* check whether propagation should be performed */
285 propagate = (maxproprounds != 0);
286
287 /* if we don't do propagation, we cannot identify valid bounds in a probing-like fashion */
288 if( !propagate && maxproprounds > -3 )
289 probingbounds = FALSE;
290
291 /* create arrays for probing-like bound tightening */
292 if( probingbounds )
293 {
294 vars = SCIPgetVars(scip);
295 nvars = SCIPgetNVars(scip);
296
297 SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
298 SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
299 }
300
301 /* initialize strong branching */
302 SCIP_CALL( SCIPstartStrongbranch(scip, propagate) );
303
304 /* search the full strong candidate
305 * cycle through the candidates, starting with the position evaluated in the last run
306 */
307 nsbcalls = 0;
308 bothgains = FALSE;
309 for( i = 0, c = *start; i < nlpcands && (!bothgains || i < ncomplete); ++i, ++c )
310 {
311 c = c % nlpcands;
312 assert(lpcands[c] != NULL);
313
314 /* don't use strong branching on variables that have already been initialized at the current node,
315 * and that were evaluated not too long ago
316 */
317 if( SCIPgetVarStrongbranchNode(scip, lpcands[c]) == nodenum
318 && SCIPgetVarStrongbranchLPAge(scip, lpcands[c]) < reevalage )
319 {
320 SCIP_Real lastlpobjval;
321
322 /* use the score of the strong branching call at the current node */
323 SCIP_CALL( SCIPgetVarStrongbranchLast(scip, lpcands[c], &down, &up, NULL, NULL, NULL, &lastlpobjval) );
324 downgain = MAX(down - lastlpobjval, 0.0);
325 upgain = MAX(up - lastlpobjval, 0.0);
326 downvalid = FALSE;
327 upvalid = FALSE;
328 downinf = FALSE;
329 upinf = FALSE;
330 downconflict = FALSE;
331 upconflict = FALSE;
332 lperror = FALSE;
333 SCIPdebugMsg(scip, "strong branching on variable <%s> already performed (lpage=%" SCIP_LONGINT_FORMAT ", down=%g (%+g), up=%g (%+g))\n",
334 SCIPvarGetName(lpcands[c]), SCIPgetVarStrongbranchLPAge(scip, lpcands[c]), down, downgain, up, upgain);
335 }
336 else
337 {
338 SCIPdebugMsg(scip, "applying strong branching%s on variable <%s> with solution %g\n",
339 propagate ? "with propagation" : "", SCIPvarGetName(lpcands[c]), lpcandssol[c]);
340 assert(i >= ncomplete || (!skipdown[i] && !skipup[i]));
341
342 /* apply strong branching */
343 up = -SCIPinfinity(scip);
344 down = -SCIPinfinity(scip);
345
346 if( propagate )
347 {
348 SCIP_CALL( SCIPgetVarStrongbranchWithPropagation(scip, lpcands[c], lpcandssol[c], lpobjval, INT_MAX,
349 maxproprounds, skipdown[i] ? NULL : &down, skipup[i] ? NULL : &up, &downvalid,
350 &upvalid, NULL, NULL, &downinf, &upinf, &downconflict, &upconflict, &lperror, newlbs, newubs) );
351
352 SCIPdebugMsg(scip, "-> down=%.9g (gain=%.9g, valid=%u, inf=%u, conflict=%u), up=%.9g (gain=%.9g, valid=%u, inf=%u, conflict=%u)\n",
353 down, down - lpobjval, downvalid, downinf, downconflict, up, up - lpobjval, upvalid, upinf, upconflict);
354 }
355 else
356 {
357 SCIP_CALL( SCIPgetVarStrongbranchFrac(scip, lpcands[c], INT_MAX, FALSE,
358 skipdown[i] ? NULL : &down, skipup[i] ? NULL : &up, &downvalid, &upvalid, &downinf, &upinf,
359 &downconflict, &upconflict, &lperror) );
360 }
361 nsbcalls++;
362
363 /* display node information line */
364 if( SCIPgetDepth(scip) == 0 && nsbcalls % 100 == 0 )
365 {
367 }
368
369 /* check for an error in strong branching */
370 if( lperror )
371 {
373 "(node %" SCIP_LONGINT_FORMAT ") error in strong branching call%s for variable <%s> with solution %g\n",
374 SCIPgetNNodes(scip), propagate ? " with propagation" : "", SCIPvarGetName(lpcands[c]), lpcandssol[c]);
375 break;
376 }
377
378 /* evaluate strong branching */
379 down = MAX(down, lpobjval);
380 up = MAX(up, lpobjval);
381 downgain = down - lpobjval;
382 upgain = up - lpobjval;
383 if( !SCIPisFeasZero(scip,downgain) && !SCIPisFeasZero(scip,upgain) )
384 bothgains = TRUE;
385
386 assert(!allcolsinlp || exactsolve || !downvalid || downinf == SCIPisGE(scip, down, SCIPgetCutoffbound(scip)));
387 assert(!allcolsinlp || exactsolve || !upvalid || upinf == SCIPisGE(scip, up, SCIPgetCutoffbound(scip)));
388 assert(downinf || !downconflict);
389 assert(upinf || !upconflict);
390
391 /* update pseudo cost values */
392 if( !downinf && downvalid )
393 {
394 SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[c], 0.0-lpcandsfrac[c], downgain, 1.0) );
395 }
396 if( !upinf && upvalid )
397 {
398 SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[c], 1.0-lpcandsfrac[c], upgain, 1.0) );
399 }
400
401 /* check if there are infeasible roundings */
402 if( downinf || upinf )
403 {
404 /* if we didn't do propagation, we can only detect infeasibility if the LP is a valid relaxation */
405 assert(allcolsinlp || propagate);
406 assert(!exactsolve);
407
408 if( downinf && upinf )
409 {
410 /* both roundings are infeasible -> node is infeasible */
411 *result = SCIP_CUTOFF;
412 SCIPdebugMsg(scip, " -> variable <%s> is infeasible in both directions\n", SCIPvarGetName(lpcands[c]));
413 break; /* terminate initialization loop, because node is infeasible */
414 }
415 else if( downinf )
416 {
417 SCIP_Bool infeasible;
418 SCIP_Bool tightened;
419
420 /* downwards rounding is infeasible -> change lower bound of variable to upward rounding */
421 SCIP_CALL( SCIPtightenVarLb(scip, lpcands[c], SCIPfeasCeil(scip, lpcandssol[c]), TRUE, &infeasible, &tightened) );
422 assert(!infeasible);
423
424 /* if we did propagation, the bound change might already have been added */
425 assert(tightened || propagate);
426
427 *result = SCIP_REDUCEDDOM;
428 SCIPdebugMsg(scip, " -> variable <%s> is infeasible in downward branch\n", SCIPvarGetName(lpcands[c]));
429 break; /* terminate initialization loop, because LP was changed */
430 }
431 else
432 {
433 SCIP_Bool infeasible;
434 SCIP_Bool tightened;
435
436 /* upwards rounding is infeasible -> change upper bound of variable to downward rounding */
437 assert(upinf);
438 SCIP_CALL( SCIPtightenVarUb(scip, lpcands[c], SCIPfeasFloor(scip, lpcandssol[c]), TRUE, &infeasible, &tightened) );
439 assert(!infeasible);
440
441 /* if we did propagation, the bound change might already have been added */
442 assert(tightened || propagate);
443
444 *result = SCIP_REDUCEDDOM;
445 SCIPdebugMsg(scip, " -> variable <%s> is infeasible in upward branch\n", SCIPvarGetName(lpcands[c]));
446 break; /* terminate initialization loop, because LP was changed */
447 }
448 }
449 else if( allcolsinlp && !exactsolve && downvalid && upvalid )
450 {
451 SCIP_Real minbound;
452
453 /* the minimal lower bound of both children is a proved lower bound of the current subtree */
454 minbound = MIN(down, up);
455 *provedbound = MAX(*provedbound, minbound);
456
457 /* apply probing-like bounds detected during strong branching */
458 if( probingbounds )
459 {
460 int nboundchgs;
461 int v;
462
463 assert(vars != NULL);
464 assert(nvars > 0);
465 assert(newlbs != NULL);
466 assert(newubs != NULL);
467
468 nboundchgs = 0;
469
470 for( v = 0; v < nvars; ++v )
471 {
472 if( SCIPisGT(scip, newlbs[v], SCIPvarGetLbLocal(vars[v])) )
473 {
474 SCIPdebugMsg(scip, "better lower bound for variable <%s>: %.9g -> %.9g (strongbranching on var <%s>\n",
475 SCIPvarGetName(vars[v]), SCIPvarGetLbLocal(vars[v]), newlbs[v], SCIPvarGetName(lpcands[c]));
476
477 SCIP_CALL( SCIPchgVarLb(scip, vars[v], newlbs[v]) );
478 ++nboundchgs;
479 }
480 if( SCIPisLT(scip, newubs[v], SCIPvarGetUbLocal(vars[v])) )
481 {
482 SCIPdebugMsg(scip, "better upper bound for variable <%s>: %.9g -> %.9g (strongbranching on var <%s>\n",
483 SCIPvarGetName(vars[v]), SCIPvarGetUbLocal(vars[v]), newubs[v], SCIPvarGetName(lpcands[c]));
484
485 SCIP_CALL( SCIPchgVarUb(scip, vars[v], newubs[v]) );
486 ++nboundchgs;
487 }
488 }
489
490 if( nboundchgs > 0 )
491 {
492 *result = SCIP_REDUCEDDOM;
493 SCIPdebugMsg(scip, " -> strong branching with propagation on variable <%s> led to %d bound changes\n",
494 SCIPvarGetName(lpcands[c]), nboundchgs);
495 break; /* terminate initialization loop, because LP was changed */
496 }
497 }
498 }
499 }
500
501 /* check for a better score, if we are within the maximum priority candidates */
502 if( c < npriolpcands )
503 {
504 score = SCIPgetBranchScore(scip, lpcands[c], downgain, upgain);
505 if( score > *bestscore )
506 {
507 *bestcand = c;
508 *bestdown = down;
509 *bestup = up;
510 *bestdownvalid = downvalid;
511 *bestupvalid = upvalid;
512 *bestscore = score;
513 }
514 }
515 else
516 {
517 SCIPdebug(score = 0.0;)
518 }
519
520 SCIPdebugMsg(scip, " -> cand %d/%d (prio:%d) var <%s> (solval=%g, downgain=%g, upgain=%g, score=%g) -- best: <%s> (%g)\n",
521 c, nlpcands, npriolpcands, SCIPvarGetName(lpcands[c]), lpcandssol[c], downgain, upgain, score,
522 SCIPvarGetName(lpcands[*bestcand]), *bestscore);
523 }
524
525 /* end strong branching */
527
528 *start = c;
529
530 if( probingbounds )
531 {
532 assert(newlbs != NULL);
533 assert(newubs != NULL);
534
535 SCIPfreeBufferArray(scip, &newlbs);
536 SCIPfreeBufferArray(scip, &newubs);
537 }
538
539 return SCIP_OKAY;
540}
541
542/** branching execution method for fractional LP solutions */
543static
544SCIP_DECL_BRANCHEXECLP(branchExeclpFullstrong)
545{ /*lint --e{715}*/
546 SCIP_BRANCHRULEDATA* branchruledata;
547 SCIP_VAR** tmplpcands;
548 SCIP_VAR** lpcands;
549 SCIP_Real* tmplpcandssol;
550 SCIP_Real* lpcandssol;
551 SCIP_Real* tmplpcandsfrac;
552 SCIP_Real* lpcandsfrac;
553 SCIP_Real bestdown;
554 SCIP_Real bestup;
555 SCIP_Real bestscore;
556 SCIP_Real provedbound;
557 SCIP_Bool bestdownvalid;
558 SCIP_Bool bestupvalid;
559 int nlpcands;
560 int npriolpcands;
561 int bestcand;
562
563 assert(branchrule != NULL);
564 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
565 assert(scip != NULL);
566 assert(result != NULL);
567
568 SCIPdebugMsg(scip, "Execlp method of fullstrong branching\n");
569
570 *result = SCIP_DIDNOTRUN;
571
572 /* get branching rule data */
573 branchruledata = SCIPbranchruleGetData(branchrule);
574 assert(branchruledata != NULL);
575
576 /* get branching candidates */
577 SCIP_CALL( SCIPgetLPBranchCands(scip, &tmplpcands, &tmplpcandssol, &tmplpcandsfrac, &nlpcands, &npriolpcands, NULL) );
578 assert(nlpcands > 0);
579 assert(npriolpcands > 0);
580
581 /* copy LP banching candidates and solution values, because they will be updated w.r.t. the strong branching LP
582 * solution
583 */
584 SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcands, tmplpcands, nlpcands) );
585 SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcandssol, tmplpcandssol, nlpcands) );
586 SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcandsfrac, tmplpcandsfrac, nlpcands) );
587
588 if( branchruledata->skipdown == NULL )
589 {
590 assert(branchruledata->skipup == NULL);
591
592 branchruledata->skipsize = SCIPgetNVars(scip);
593 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipdown, branchruledata->skipsize) );
594 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipup, branchruledata->skipsize) );
595 BMSclearMemoryArray(branchruledata->skipdown, branchruledata->skipsize);
596 BMSclearMemoryArray(branchruledata->skipup, branchruledata->skipsize);
597 }
598
599 SCIP_CALL( SCIPselectVarStrongBranching(scip, lpcands, lpcandssol, lpcandsfrac, branchruledata->skipdown,
600 branchruledata->skipup, nlpcands, npriolpcands, nlpcands, &branchruledata->lastcand,
601 branchruledata->maxproprounds, branchruledata->probingbounds, branchruledata->forcestrongbranch, &bestcand,
602 &bestdown, &bestup, &bestscore, &bestdownvalid, &bestupvalid, &provedbound, result) );
603
604 if( *result != SCIP_CUTOFF )
605 {
606 SCIP_Bool allcolsinlp;
607 SCIP_Bool exactsolve;
608
609 /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful
610 * for cutting off sub problems and improving lower bounds of children
611 */
612 exactsolve = SCIPisExact(scip);
613
614 /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */
615 allcolsinlp = SCIPallColsInLP(scip);
616
617 /* update lower bound of current node */
618 if( allcolsinlp && !exactsolve )
619 {
621 }
622
623 if( *result != SCIP_REDUCEDDOM && *result != SCIP_CONSADDED )
624 {
625 SCIP_NODE* downchild;
626 SCIP_NODE* upchild;
627 SCIP_VAR* var;
628 SCIP_Real val;
629
630 assert(*result == SCIP_DIDNOTRUN);
631 assert(0 <= bestcand && bestcand < nlpcands);
632 assert(SCIPisLT(scip, provedbound, SCIPgetCutoffbound(scip)));
633
634 var = lpcands[bestcand];
635 val = lpcandssol[bestcand];
636
637 /* perform the branching */
638 SCIPdebugMsg(scip, " -> %d candidates, selected candidate %d: variable <%s> (solval=%g, down=%g, up=%g, score=%g)\n",
639 nlpcands, bestcand, SCIPvarGetName(var), lpcandssol[bestcand], bestdown, bestup, bestscore);
640 SCIP_CALL( SCIPbranchVarVal(scip, var, val, &downchild, NULL, &upchild) );
641
642 /* update the lower bounds in the children */
643 if( allcolsinlp && !exactsolve )
644 {
645 if( downchild != NULL && bestdownvalid )
646 {
647 SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, bestdown) );
648 SCIPdebugMsg(scip, " -> down child's lowerbound: %g\n", SCIPnodeGetLowerbound(downchild));
649 }
650 if( upchild != NULL && bestupvalid )
651 {
652 SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, bestup) );
653 SCIPdebugMsg(scip, " -> up child's lowerbound: %g\n", SCIPnodeGetLowerbound(upchild));
654 }
655 }
656
657 *result = SCIP_BRANCHED;
658 }
659 }
660
661 SCIPfreeBufferArray(scip, &lpcandsfrac);
662 SCIPfreeBufferArray(scip, &lpcandssol);
663 SCIPfreeBufferArray(scip, &lpcands);
664
665 return SCIP_OKAY;
666}
667
668
669/*
670 * branching specific interface methods
671 */
672
673/** creates the full strong LP branching rule and includes it in SCIP */
675 SCIP* scip /**< SCIP data structure */
676 )
677{
678 SCIP_BRANCHRULEDATA* branchruledata;
679 SCIP_BRANCHRULE* branchrule;
680
681 /* create fullstrong branching rule data */
682 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) );
683 branchruledata->lastcand = 0;
684 branchruledata->skipsize = 0;
685 branchruledata->skipup = NULL;
686 branchruledata->skipdown = NULL;
687
688 /* include branching rule */
691
692 assert(branchrule != NULL);
693
694 /* set non-fundamental callbacks via specific setter functions*/
695 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyFullstrong) );
696 SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeFullstrong) );
697 SCIP_CALL( SCIPsetBranchruleInit(scip, branchrule, branchInitFullstrong) );
698 SCIP_CALL( SCIPsetBranchruleExit(scip, branchrule, branchExitFullstrong) );
699 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpFullstrong) );
700
701 /* fullstrong branching rule parameters */
703 "branching/fullstrong/reevalage",
704 "number of intermediate LPs solved to trigger reevaluation of strong branching value for a variable that was already evaluated at the current node",
705 &branchruledata->reevalage, TRUE, DEFAULT_REEVALAGE, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
707 "branching/fullstrong/maxproprounds",
708 "maximum number of propagation rounds to be performed during strong branching before solving the LP (-1: no limit, -2: parameter settings)",
709 &branchruledata->maxproprounds, TRUE, DEFAULT_MAXPROPROUNDS, -3, INT_MAX, NULL, NULL) );
711 "branching/fullstrong/probingbounds",
712 "should valid bounds be identified in a probing-like fashion during strong branching (only with propagation)?",
713 &branchruledata->probingbounds, TRUE, DEFAULT_PROBINGBOUNDS, NULL, NULL) );
715 "branching/fullstrong/forcestrongbranch",
716 "should strong branching be applied even if there is just a single candidate?",
717 &branchruledata->forcestrongbranch, TRUE, DEFAULT_FORCESTRONGBRANCH, NULL, NULL) );
718
719 return SCIP_OKAY;
720}
#define BRANCHRULE_DESC
#define BRANCHRULE_PRIORITY
#define DEFAULT_PROBINGBOUNDS
static SCIP_DECL_BRANCHEXIT(branchExitFullstrong)
#define DEFAULT_REEVALAGE
static SCIP_DECL_BRANCHINIT(branchInitFullstrong)
#define BRANCHRULE_NAME
static SCIP_DECL_BRANCHFREE(branchFreeFullstrong)
#define DEFAULT_FORCESTRONGBRANCH
#define DEFAULT_MAXPROPROUNDS
#define BRANCHRULE_MAXDEPTH
static SCIP_DECL_BRANCHCOPY(branchCopyFullstrong)
#define BRANCHRULE_MAXBOUNDDIST
static SCIP_DECL_BRANCHEXECLP(branchExeclpFullstrong)
full strong LP branching rule
#define NULL
Definition: def.h:248
#define SCIP_Longint
Definition: def.h:141
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIP_LONGINT_MAX
Definition: def.h:142
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_RETCODE SCIPselectVarStrongBranching(SCIP *scip, SCIP_VAR **lpcands, SCIP_Real *lpcandssol, SCIP_Real *lpcandsfrac, SCIP_Bool *skipdown, SCIP_Bool *skipup, int nlpcands, int npriolpcands, int ncomplete, int *start, int maxproprounds, SCIP_Bool probingbounds, SCIP_Bool forcestrongbranch, int *bestcand, SCIP_Real *bestdown, SCIP_Real *bestup, SCIP_Real *bestscore, SCIP_Bool *bestdownvalid, SCIP_Bool *bestupvalid, SCIP_Real *provedbound, SCIP_RESULT *result)
SCIP_RETCODE SCIPincludeBranchruleFullstrong(SCIP *scip)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:2201
SCIP_RETCODE SCIPupdateNodeLowerbound(SCIP *scip, SCIP_NODE *node, SCIP_Real newbound)
Definition: scip_prob.c:4354
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:4289
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:111
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
SCIP_RETCODE SCIPsetBranchruleExit(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXIT((*branchexit)))
Definition: scip_branch.c:208
SCIP_RETCODE SCIPsetBranchruleExecLp(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECLP((*branchexeclp)))
Definition: scip_branch.c:256
SCIP_BRANCHRULE * SCIPfindBranchrule(SCIP *scip, const char *name)
Definition: scip_branch.c:304
SCIP_RETCODE SCIPsetBranchruleCopy(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHCOPY((*branchcopy)))
Definition: scip_branch.c:160
SCIP_RETCODE SCIPincludeBranchruleBasic(SCIP *scip, SCIP_BRANCHRULE **branchruleptr, const char *name, const char *desc, int priority, int maxdepth, SCIP_Real maxbounddist, SCIP_BRANCHRULEDATA *branchruledata)
Definition: scip_branch.c:123
const char * SCIPbranchruleGetName(SCIP_BRANCHRULE *branchrule)
Definition: branch.c:2018
SCIP_BRANCHRULEDATA * SCIPbranchruleGetData(SCIP_BRANCHRULE *branchrule)
Definition: branch.c:1886
SCIP_RETCODE SCIPsetBranchruleFree(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHFREE((*branchfree)))
Definition: scip_branch.c:176
SCIP_RETCODE SCIPsetBranchruleInit(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHINIT((*branchinit)))
Definition: scip_branch.c:192
void SCIPbranchruleSetData(SCIP_BRANCHRULE *branchrule, SCIP_BRANCHRULEDATA *branchruledata)
Definition: branch.c:1896
SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1134
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:402
SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
Definition: scip_branch.c:857
SCIP_Bool SCIPisExact(SCIP *scip)
Definition: scip_exact.c:193
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
SCIP_Bool SCIPallColsInLP(SCIP *scip)
Definition: scip_lp.c:655
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:253
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_Real SCIPnodeGetLowerbound(SCIP_NODE *node)
Definition: tree.c:8503
SCIP_Longint SCIPgetNNodes(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_RETCODE SCIPprintDisplayLine(SCIP *scip, FILE *file, SCIP_VERBLEVEL verblevel, SCIP_Bool endline)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_RETCODE SCIPgetVarStrongbranchFrac(SCIP *scip, SCIP_VAR *var, int itlim, SCIP_Bool idempotent, SCIP_Real *down, SCIP_Real *up, SCIP_Bool *downvalid, SCIP_Bool *upvalid, SCIP_Bool *downinf, SCIP_Bool *upinf, SCIP_Bool *downconflict, SCIP_Bool *upconflict, SCIP_Bool *lperror)
Definition: scip_var.c:3664
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6401
SCIP_RETCODE SCIPendStrongbranch(SCIP *scip)
Definition: scip_var.c:3488
SCIP_RETCODE SCIPchgVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:5697
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:5875
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6651
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Longint SCIPgetVarStrongbranchNode(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:5019
SCIP_Longint SCIPgetVarStrongbranchLPAge(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:5053
SCIP_RETCODE SCIPgetVarStrongbranchWithPropagation(SCIP *scip, SCIP_VAR *var, SCIP_Real solval, SCIP_Real lpobjval, int itlim, int maxproprounds, SCIP_Real *down, SCIP_Real *up, SCIP_Bool *downvalid, SCIP_Bool *upvalid, SCIP_Longint *ndomredsdown, SCIP_Longint *ndomredsup, SCIP_Bool *downinf, SCIP_Bool *upinf, SCIP_Bool *downconflict, SCIP_Bool *upconflict, SCIP_Bool *lperror, SCIP_Real *newlbs, SCIP_Real *newubs)
Definition: scip_var.c:4138
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_RETCODE SCIPupdateVarPseudocost(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta, SCIP_Real objdelta, SCIP_Real weight)
Definition: scip_var.c:11122
SCIP_RETCODE SCIPgetVarStrongbranchLast(SCIP *scip, SCIP_VAR *var, SCIP_Real *down, SCIP_Real *up, SCIP_Bool *downvalid, SCIP_Bool *upvalid, SCIP_Real *solval, SCIP_Real *lpobjval)
Definition: scip_var.c:4869
SCIP_RETCODE SCIPstartStrongbranch(SCIP *scip, SCIP_Bool enablepropagation)
Definition: scip_var.c:3430
memory allocation routines
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
public methods for branching rules
public methods for message output
#define SCIPdebug(x)
Definition: pub_message.h:93
public methods for branch and bound tree
public methods for problem variables
public methods for branching rule plugins and branching
public methods for exact solving
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
struct SCIP_BranchruleData SCIP_BRANCHRULEDATA
Definition: type_branch.h:57
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:44
@ SCIP_VERBLEVEL_HIGH
Definition: type_message.h:61
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_REDUCEDDOM
Definition: type_result.h:51
@ SCIP_CONSADDED
Definition: type_result.h:52
@ SCIP_BRANCHED
Definition: type_result.h:54
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63