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