Data structures for branch and bound: Efficiently finding the branch node vs. efficiently fathoming

I am implementing a branch and bound algorithm for the knapsack program that is essentially identical to the one described here. I am trying to decide on the optimal data structure to store the set of candidate nodes.

It seems there are two natural choices: Either a kind of tree that represents the relationships between parent and child nodes, or a heap sorted by the LP relaxation values.

Suppose there are $$n$$ nodes in the candidate set (i.e. nodes that are not leaves and have not had their children explored). At each iteration, we

1. Select the candidate node having the highest LP upper bound and generate child nodes by fixing $$x_s = 0$$ and $$x_s = 1$$ (where $$s$$ is the index of the "critical" item that takes a fractional value in the LP relaxation).
2. If one of the child nodes yields a feasible, integral solution with a higher objective value than our best solution on hand, we inspect the remaining candidate nodes and "fathom" any for which the LP relaxation value is less than the new lower bound.

The heap has the advantage of reducing the time used in step 1 to $$O(1)$$ rather than $$O(n)$$. But since the heap doesn't encode any information about the parent-child relationships among nodes, identifying the nodes that we can fathom in step 2 is $$O(n)$$, because a fathomable node could conceivably be anywhere on the heap (right?), and then actually removing these keys from the heap costs $$O(\log n)$$ each.

From this analysis, it would appear that the better choice is to choose the tree data structure. Then the search step (step 1) costs $$O(n)$$, but then the fathoming step (step 2) is also $$O(n)$$ because each node is removed in unit time.

However, this is not what I see in other implementations: When I run branch-and-bound solvers like SCIP, the terminal message at each iteration says "1234 nodes on heap." This makes me think that they have somehow figured out a way to get the best of both worlds from a heap, i.e. selecting the branch node in unit time and completing the fathoms in $$O(n)$$ time. Is this possible? How?

• Note that this is a toy example, in real life 1) one does not solve a knapsack problem with a branch-and-bound algorithm 2) in a branch-and-bound, the cost of computing the bound is usually significantly greater than the time to manage the nodes, so its not very critical Mar 7 at 15:33
• @fontanf I guess "toy example" is a relative term. The problem I am actually working on is a nonlinear integer program whose objective function is bounded from above by the value of a certain knapsack problem. I have better algorithms for my problem, but I am using a branch-and-bound routine as a benchmark, and I figured I would write my question here in terms of the basic knapsack problem, which is of more general interest. In the knapsack problem (unlike general IPs) the LP relaxation at each node can be solved in linear time, so IMO tree management is an important issue.
– Max
Mar 8 at 0:15
• Ok, that makes sense Mar 8 at 5:56
• Fathoms or pruning only saves space rather than time, as far as I know. So I think you could just prune when the heap is full.
– xd y
Mar 9 at 11:46

One approach is to not "fathom" them at the time we replace our best candidate. Rather, as things get naturally pulled from the heap (because they are the min/max heap root), we then toss and repull if said best is unusable. This avoids the $$O(n)$$ search.
• Thank you. The "toss and repull" method sounds quite practical. However, if I have understood correctly, I believe it is still $O(n)$ in the worst-case, because there could be $n-1$ fathomed nodes above the true branch node in the heap. Similarly, I think "reheapify" is going to be equivalent to my "tree" idea in the end, because emptying and reheapifying will cost $O(n)$ just like searching through the tree. I guess there is no way to get the time for a whole iteration below $O(n)$, huh?