ECS 110: Data Structures and Programming Discussion Section Notes -- Week 9 Ted Krovetz (tdkrovetz@ucdavis.edu) BRANCH & BOUND ============== This week we will examine branch and bound techniques to reduce the state space tree of an exhaustive search. 1. BRANCH AND BOUND ------------------- 1.1 Motivation There exist many real-life, practical problems for which no efficient algorithm is known, but whose intrinsic difficulty no one has yet managed to prove. Many of these problems reduce to "try every possible configuration and select the result which best fits the problem." The travelling salesperson problem is an example of this type. Essentially, to solve the TSP, one must try all possible orderings of the cities to visit and keep track of the one which costs the least. Unfortunately, a small sample of cities (15) can quickly yield a number of possible solutions which is very large (15! = 1.3e12). 1.3 Search Tree Using either breadth-first or depth-first search, all the possible paths of a graph can be represented as a tree. Each leaf of the tree represents a completed path, while each node represents a partial tour, which has associated with it a fixed cost to get from the start node, and a sub-tree of possible completions to the path. (demonstration given in class). 1.4 Pruning the Sample Space One solution to the size of the search tree is not to search the entire sample space. For example, you could follow a greedy strategy, picking the possible edges with least cost until a TSP tour has been selected. This is a very fast approach which generally yields a good solution. Good, but not optimal. To get an optimal solution you must consider all possible permutations. With the proper heuristics, you can usually prune the search space to a much more manageable size. For instance, using the quick greedy strategy, we can establish a bound on our solution. While considering other possible tours, any tour which would produce a cost greater that that of the quick greedy method can be thrown out. As an example consider the following distance matrix 0 3 8 10 1 3 0 3 1 2 8 3 0 2 4 10 1 2 0 3 1 2 4 3 0 Using the greedy strategy on the graph gives a quick bound of 14 (demonstrated in section). With this information, we can nip many paths before wasting time exploring them (demonstrated in section). For instance, any path beginning with (1,4,5) will be greater than 13 and therefore no better than our previously found bound. No need to continue on that search path. If we are smart about the way we generate a search tree for the possible solutions, and we keep information about the best solution found so far, and we make clever guesses about how much further we need to go to complete our tour, then at each node there will be a lot of information to help judge whether the current path is likely to be optimal. In fact, all branch-and-bound really is applying some heuristic to possible paths to determine whether continuing on that path is prudent. The heuristic is entirely up to the programmer. Some heuristics could be quite accurate but rather expensive, while others could be quick and dirty. Which solves a problem faster can only be discovered through experimentation. 1.5 An algorithm Given a function, c, which maps a partial solution to an estimate of the best total cost to complete the solution; and given that c is less than or equal to the actual total cost, at each level of our search we can rank the promise of following a particular edge. Also, if we keep track of the best solution found, we never need to consider partial solutions whose estimated cost is greater than the best found. So, some pseudo-code. int U = INFINITY; // (Upperbound) Haven't found any solutions yet priority_queue pq; E = initial state; while (1) { for each child X of E { if c(X) < U then pq.enqueue(X, c(X)); if (X = leaf) U = min(U,cost(X)) } do { if (pq.empty()) { cout << "Answer = U" exit(); } E = pq.delete(); // Kill all nodes >= U } while (E >= U) } A branch-and-bound solution can be applied to any problem that can be represented using a search tree and a cost function which can estimate the cost of a partial solution. Other examples include n-queens, knapsack, 15-puzzle. Time permitting, we will discuss some other problems. 1.6 TSP Branch and Bound Example [The following is extracted from "Algorithmics: Theory and Practice, G. Brassard and P. Bratley, Prentice-Hall, 1988"] Like backtracking, branch-and-bound is a technique for exploring an implicit directed graph. Again, this graph is usually acyclic or even a tree. This time, we are looking for the optimal solution to some problem. At each node we calculate a bound on the possible values of any solutions that might happen to be farther on in the graph. If the bound shows that any such solutions must necessarily be worst than the best solution found so far, then we do not need to go on exploring this part of the graph. In the simplest version, calculation of these bounds is combined with a breadth-first of depth-first search, and serves only, as we have just explained, to prune certain branches of a tree or to close certain paths in a graph. More often, however, the calculated bound is used not only to close off certain paths, but also to choose which of the open paths looks the most promising, so that it can be explored first. In general terms we may say that a depth-first search finishes exploring nodes in the inverse order of their creation, using a stack to hold those nodes that have been generated but not yet explored fully; a breadth-first search finishes exploring nodes in the order of their creation, using this time a queue to hold those that have been generated but not yet explored. Branch-and-bound uses auxiliary computations to decide at each instant which node should be explored next, and a priority list to hold those nodes that have been generated but not yet explored. We return to the travelling salesperson problem. Let G be the complete graph on five points with the following distance matrix: 0 14 4 10 20 14 0 7 8 7 4 5 0 7 16 11 7 9 0 2 18 7 17 4 0 We are looking for the shortest tour starting from node 1 that passes exactly once through each other node before returning to node 1. The nodes in the implicit graph correspond to partially specified paths. For instance, node (1,4,3) corresponds to two complete tours: (1,4,3,2,5,1) and (1,4,3,5,2,1). The successors of a given node correspond to paths in which one additional node has been specified. At each node we calculate a lower bound on the length of the corresponding complete tours. To calculate this bound, suppose that half the distance between two points i and j is counted at the moment we leave i, and the the other half when we arrive at j. For instance, leaving node 1 costs us at least 2, namely the lowest of the values 14/2, 4/2, 10/2, and 20/2. Similarly, visiting node 2 costs us at least 5 (at least 4/2 when we arrive and at least 7/2 when we leave). Returning to node 1 costs at least 2, the minimum of 14/2, 4/2, 11/2 and 18/2. To obtain a bound on the length of a path, it suffices to add elements of this kind. For instance, a complete tour must include a departure from node 1, a visit to each of the nodes 2,3,4, and 5 (not necessarily in this order) and a return to 1. Its length is therefore at least 2 + 6 + 4 + 3 + 3 + 2 = 20 Notice that this calculation does not imply the existence of a solution that costs only 20. In Figure 6.6.5 (a tree to be drawn in section) the root of the tree specifies that the starting point for our tour is node 1. Obviously, this arbitrary choice of a starting point does not alter the length of the shortest tour. We have just calculated the lower bound shown for this node. (This bound on the root of the implicit tree serves no purpose in the algorithm; it was computed here for the sake of illustration.) Our search begins by generating (as though for a breadth-first search) the four possible successors of the root, namely, nodes (1,2), (1,3), (1,4) and (1,5). The bound for node (1,2), for example, is calculated as follows. A tour that begins with (1,2) must include - The trip 1-2: 14 (formally , leaving 1 for 2 and arriving at 2 from 1: 7 + 7) - A departure from 2 toward 3,4, or 5: minimum 7/2 - A visit to 3 that neither comes from 1 nor leaves for 2: minimum 11/2 - A similar visit to 4: minimum 3 - A similar visit to 5: minimum 3 - A return to 1 from 3,4, or 5: minimum 2. The length of such a tour is therefore at least 31. The other bounds are calculated similarly. Next, the most promising node seems to be (1,3), whose bound is 24. The three children (1,3,2), (1,3,4), and (1,3,5) of this node are therefore generated. To give just one example, we calculate the bound for node (1,3,2) as follows: - The trip 1-3-2: 9 - A departure from 2 toward 4 or 5: minimum 7/2 - A visit to 4 that comes from neither 1 nor 3 and that leaves for neither 2 nor 3: minimum 3 - A similar visit to 5: minimum 3 - A return to 1 from 4 or 5: minimum 11/2, which gives a total length of at least 24. The most promising node is now (1,3,2). Its two children (1,3,2,4) and (1,3,2,5) are generated. This time, as node (1,3,2,4), for instance, corresponds to exactly one complete tour (1,3,2,4,5,1), we do not need to calculate a lower bound since we can calculate immediately its length 37. We find that the length of the tour (1,3,2,5,4,1) is 31. If we are only concerned to find one optimal solution, we do not need to continue exploration of the nodes (1,2), (1,5), and (1,3,5), which cannot possibly lead to a better solution. Even the node (1,3,4) is pointless. (Why?) There remains only node (1,4) to explore. The only child to offer interesting possibilities is (1,4,5). After looing at the two complete tours (1,4,5,2,3,1) and (1,4,5,3,2,1), we find that the tour (1,4,5,2,3,1) of length 30 is optimal. This example demonstrates that although at one point (1,3) was the most promising node, the optimal solution does not come from there. To obtain our answer, we have looked at merely 15 of the 41 nodes that are present in a complete (state space) tree. The need to keep a list of nodes that have been generated but not yet completely explored, situated at all levels of the tree and preferably sorted in order of the corresponding bounds, makes branch-and-bound quite hard to program. The heap is an ideal data structure for holding this list. Unlike depth-first search and its related techniques, no elegant recursive formulation of branch-an-bound is available to the programmer. Nevertheless, the technique is sufficiently powerful that it is often used in practical applications. It is next to impossible to give any idea how well the technique will perform on a given problem using a given bound. There is always a compromise to be made concerning the quality of the bound to be calculated: with a better bound we look at less nodes, but on the other hand, we shall most likely spend more time at each one calculating the corresponding bound. In the worst case it may turn out that even an excellent bound does not allow us to cut any branches off the tree, and all the extra work we have done is wasted.