private void printRoute(BBNode node) { List<City> cities = new List<City>(Cities); Console.WriteLine("Route: "); foreach (Object obj in node.Route) { City city = (City)obj; Console.Write(cities.IndexOf(city) + "->"); } Console.WriteLine(cities.IndexOf((City)node.Route[0])); }
/// <summary> /// performs a Branch and Bound search of the state space of partial tours /// stops when time limit expires and uses BSSF as solution /// </summary> /// <returns>results array for GUI that contains three ints: cost of solution, time spent to find solution, number of solutions found during search (not counting initial BSSF estimate)</returns> public string[] bBSolveProblem() { string[] results = new string[3]; Stopwatch timer = new Stopwatch(); int intermediateSolutions = 0; int numStatesCreated = 0; int maxInQueue = 0; int numStatesPruned = 0; defaultSolveProblem(); timer.Start(); // initialize the root node List<int> children = new List<int>(); int[,] matrix = initializeCostMatrix(Cities, ref children, 0); //printMatrix(matrix, "Absolute Cost:"); BBNode rootNode = new BBNode(children, matrix, 0); // 0 is it's row index in the cost matrix rootNode.reduceMatrix(); //printMatrix(rootNode.costMatrix, "Root Reduced Matrix:"); //Console.WriteLine("\nRoot.LocalBound = " + rootNode.localBound); rootNode.Route.Add(Cities[0]); // the route starts at itself // initialize the priority queue (add the root) priorityQueue.Enqueue(rootNode, 0); double costOfBSSF = bssf.costOfRoute(); //Console.WriteLine("BSSF cost:" + costOfBSSF); bool timesUp = false; while (!timesUp && priorityQueue.Count > 0) { BBNode node = priorityQueue.Dequeue(); if (node.localBound < costOfBSSF) { foreach (int child in node.children) { // Check if time has expired if (timer.Elapsed.TotalMilliseconds > time_limit) { timesUp = true; } // Find the cost to the child node from the current node int costToNode = node.costMatrix[node.rowIndex, child]; if ((costToNode < int.MaxValue) && (costToNode + node.localBound) < costOfBSSF) // we want to create a new state { List<int> childrenToPass = new List<int>(node.children); childrenToPass.Remove(child); int[,] childMatrix = infinityOutMatrix(node.costMatrix, node.rowIndex, child); BBNode childNode = new BBNode(childrenToPass, childMatrix, child); // Create a state childNode.localBound = node.localBound + node.costMatrix[node.rowIndex, child]; childNode.reduceMatrix(); childNode.Route.AddRange(node.Route); childNode.Route.Add(Cities[child]); numStatesCreated++; // if it's a leaf, update the BSSF if (childNode.children.Count == 0) { if (childNode.localBound < costOfBSSF) { bssf = new TSPSolution(childNode.Route); costOfBSSF = bssf.costOfRoute(); intermediateSolutions++; } } else // otherwise, add it to the queue. { priorityQueue.Enqueue(childNode, (float)(childNode.localBound / (childNode.Route.Count * 1000))); if (priorityQueue.Count > maxInQueue) { maxInQueue = priorityQueue.Count; } } } else { numStatesPruned++; } // otherwise ignore it. Definitely not part of the solution. } } else numStatesPruned++; } timer.Stop(); results[COST] = bssf.costOfRoute().ToString(); // load results into array here, replacing these dummy values results[TIME] = timer.Elapsed.ToString(); results[COUNT] = intermediateSolutions.ToString(); // Used to fill out the table in the report String storedStates = "Max Stored States: " + maxInQueue + "\n"; String statesCreated = "Total States Created: " + numStatesCreated + "\n"; String statesPruned = "Total State Pruned: " + numStatesPruned + "\n"; MessageBox.Show(storedStates + statesCreated + statesPruned); Console.WriteLine(storedStates); Console.WriteLine(statesCreated); Console.WriteLine(statesPruned); return results; }
// Processes a node in the branch and bound tree // If it is a leaf node and is better than the current best solution, // set the bssf to this node. If it is not a leaf, add nodes for each // unvisited city which is lower than the current upper bound. private void ProcessBBNode( IPriorityQueue <BBNode, BBPriority> queue, Tuple <BBNode, BBPriority> el, ref int count, ref double upper, ref int totalStates, ref int pruned, ref int maxQueueSize ) { BBNode top = el.Item1; // Check if the route has passed through every city if (top.Cities.Count == Cities.Length) { // Add the trip back to the starting node. double cost = top.Cost + top.Matrix.Costs[top.Cities[top.Cities.Count - 1], 0]; if (cost < upper) { upper = cost; count++; // CLear any nodes with higher cost than the new upper. DEPTH_NONE indicates // that only cost should be considered, and not depth. Add the pruned nodes // to the pruned count. pruned += queue.DeleteElementsHigherThan(new BBPriority(BBPriority.DEPTH_NONE, upper)); ArrayList cities = new ArrayList(); foreach (int city in top.Cities) { cities.Add(Cities[city]); } bssf = new TSPSolution(cities); } } else { // Add nodes to the queue for each potential route out of the current city int lastCity = top.Cities[top.Cities.Count - 1]; for (int i = 0; i < top.Matrix.Costs.GetLength(0); i++) { if (!Double.IsInfinity(top.Matrix.Costs[lastCity, i])) { Matrix newMatrix = top.Matrix.FollowRoute(lastCity, i); double newCost = el.Item2.Cost + top.Matrix.Costs[lastCity, i] + (newMatrix.LowerBound - top.Matrix.LowerBound); totalStates++; // If the prospective state is lower cost than the bssf, add it to the queue if (newCost < upper) { List <int> newCities = top.Cities.Concat(new List <int> { i }).ToList(); queue.Insert( new BBNode(newCities, newMatrix, newCost), new BBPriority(newCities.Count, newCost) ); } else { pruned++; } } } if (queue.Size > maxQueueSize) { maxQueueSize = queue.Size; } } }