// Initial state, reduces matrix public State(City[] cities) { queue = new HeapPriorityQueue<State>(10000); root = this; Watch = new Stopwatch(); Watch.Start(); State.cities = cities; cityCount = cities.Length; matrix = new double[cities.Length, cities.Length]; for (int i = 0; i < cities.Length; i++) { for (int j = 0; j < cities.Length; j++) { matrix[i, j] = cities[i].costToGetTo(cities[j]); // Set diagonals to infinity (negative) if (i == j) { matrix[i, j] = double.PositiveInfinity; } } } bound = 0; route = new ArrayList(); visited = new ArrayList(); pathsLeft = cityCount; setInitialBSSF(); reduceMatrix(); // Start expanding until agenda is empty, time is up, or BSSF cost is equal to original LB. Expand(); }
public State(State state) { Matrix = new Matrix(state.Matrix); LowerBound = state.LowerBound; _cityFrom = (int[])state._cityFrom.Clone(); _cityTo = (int[])state._cityTo.Clone(); _citiesInSolution = state._citiesInSolution; }
public LbDifferenceResult(State includeState, State excludeState, double lowerBoundDifference, int fromCity, int toCity) { IncludeState = includeState; ExcludeState = excludeState; LowerBoundDifference = lowerBoundDifference; FromCity = fromCity; ToCity = toCity; }
public void Add(State newState) { int position = newState.routeSF.Count; System.Console.WriteLine(position); if (_states[position] == null) _states[position] = new ArrayList(); _states[position].Add(newState); count++; if (count > _maxCount) _maxCount = count; }
//O(n^2) public State makeExclude(int x, int y, State state) { State excludeState = new State(copyMatrix(state.getMap()), state.getLB(), state.getEdges()); //O(n^2) excludeState.setPoint(x, y, double.PositiveInfinity); //make chosen point infinity reduceMatrix(excludeState); //O(n^2) excludeState.setEdges(state.getEdges()); //initialize excludeStates edges return excludeState; }
//O(n) public bool isDictionaryFilled(State state) { //returns whether or not the all of the edges have been added for (int i = 0; i < state.getEdges().Count; i++) { if (state.getEdge(i) == -1) return false; //if one hasn't been added, then it isn't full } return true; }
//O(n^3) public void findGreatestDiff(State state) { int chosenX = 0; //city x to city y int chosenY = 0; double greatestDiff = double.NegativeInfinity; //initialize to -oo to find what the greatest //difference is List<PointF> points = new List<PointF>(); for (int i = 0; i < state.getMap().GetLength(0); i++) //rows, O(n) { for (int j = 0; j < state.getMap().GetLength(1); j++) //columns { if (state.getPoint(i, j) == 0) //if point is 0 { points.Add(new PointF(i, j)); //store all 0's in a point array } } } for (int i = 0; i < points.Count; i++) //loop through 0's to find the greatest difference {//O(n^3) there will be atmost n points, because the entire //matrix will be 0 int possibleMax = findExcludeMinusInclude(Convert.ToInt32(points[i].X), Convert.ToInt32(points[i].Y), state); //O(n^2) if (possibleMax >= greatestDiff) //set the point to point values, if it is 0 is covered by = { chosenX = Convert.ToInt32(points[i].X); chosenY = Convert.ToInt32(points[i].Y); greatestDiff = possibleMax; } } State include = makeInclude(chosenX, chosenY, state); //O(n^2) if (BSSF > include.getLB()) //if include's lowerbound is better than the BSSF { include.setEdge(chosenX, chosenY); //set the edge in the dictionary checkCycles(include, chosenX, chosenY); //O(n), make sure there are no potential cycles queue.Add(include); //add to the queue to be popped off later } if (isDictionaryFilled(include))//O(n), have all of the edges been filled? then the include.LB is better { //than the current BSSF, set the BSSF BSSF = include.getLB(); bestState = include; //save the "bestState" } State exclude = makeExclude(chosenX, chosenY, state);//O(n^2) if (BSSF > exclude.getLB()) //if exclude's lowerbound is than the BSSF, add it to the queue queue.Add(exclude); if (isDictionaryFilled(exclude))//O(n), have all of the edges been filled? { // then exclude's lowerbound is better, set the BSSF to exclude.LB BSSF = exclude.getLB(); bestState = exclude; } }
//O(n^2) public int findExcludeMinusInclude(int x, int y, State state) { //finds the exlude minus the include of a point in a matrix State excludeState = makeExclude(x, y, state); //O(n^2) reduceMatrix(excludeState);//O(n^2) State includeState = makeInclude(x, y, state); //O(n^2) reduceMatrix(includeState); //O(n^2) int cost = Convert.ToInt32(excludeState.getLB() - includeState.getLB()); return cost; }
//O(n) public void checkCycles(State state, int i, int j) { Dictionary<int, int> edges = new Dictionary<int, int>(state.getEdges()); if (getDictionarySize(edges) == edges.Count) //if the dictionary is full, stop return; int[] entered = new int[edges.Count]; int[] exited = new int[edges.Count]; for (int x = 0; x < entered.Length; x++) //O(n) entered[x] = -1; for (int x = 0; x < edges.Count; x++) //O(n) { exited[x] = edges[x]; if (exited[x] != -1) entered[exited[x]] = x; } //the two loops above "flip" the arrays with value and index, e.g. if //entered contained [0]=2, [1]=0, [2]=1 //exited will now contain [0]=1, [1]=2, [2]=0 entered[j] = i; exited[i] = j; int start = i; int end = j; while (exited[end] != -1) //O(n) end = exited[end]; while (entered[start] != -1)//O(n) start = entered[start]; if (getDictionarySize(edges) != edges.Count - 1) //if there is only one point left to fill, { //this will think there is a cycle, so make while (start != j) //O(n) make sure there isn't one element left { state.setPoint(end, start, double.PositiveInfinity); state.setPoint(j, start, double.PositiveInfinity); start = exited[start]; } } }
public void branchAndBoundSolve() { initialState = new State(new Double[Cities.Length, Cities.Length]); timer = new Stopwatch(); timer.Start(); for (int i = 0; i < Cities.Length; i++) //O(n^2), initialize initialStates map { for (int x = 0; x < Cities.Length; x++) { initialState.setPoint(i, x, Cities[i].costToGetTo(Cities[x])); if (initialState.getPoint(i, x) == 0) initialState.setPoint(i, x, double.PositiveInfinity); } } initialState.initializeEdges(); //initializeEdges initializes the state's dictionary //with key 0 to n (# of cities), value -> -1 reduceMatrix(initialState); //reduce the matrix to find lower bound queue = new IntervalHeap<State>(); //this is a global queue BSSF = greedy(); //find initial best solution so far, O(n^4) Console.WriteLine("BSSF: " + BSSF); findGreatestDiff(initialState); //exclude minus include, O(n^3) TimeSpan ts = timer.Elapsed; bool terminatedEarly = false; //boolean to keep track if we stopped after 30 seconds int maxStates = 0; //keeps track of the maximum amount of states in the queue at one point int totalSeconds = 0; while (queue.Count != 0) //O(2^n * n^3), because each time you expand a node, it expands it 2 times, exponentially { //where n is the number of cities if (queue.Count > maxStates) //if maxStates needs to be updated, update it maxStates = queue.Count; ts = timer.Elapsed; State min = queue.DeleteMin(); if (totalSeconds < ts.Seconds) { totalSeconds = ts.Seconds; Console.WriteLine("seconds: " + totalSeconds); } if (min.getLB() < BSSF) //if the min popped off the queue has a lowerbound less than findGreatestDiff(min);//the BSSF, expand it, otherwise, prune it. -> O(n^3) else {//all of the lowerbounds are worse than the BSSF, break! break; } } if (!terminatedEarly)//if it solved the problem in less than 30 seconds { int city = 0; for (int i = 0; i < bestState.getEdges().Count; i++) //O(n) { if (i == 0) //outputting a map into the Route list { Route.Add(Cities[i]); city = bestState.getEdge(i); } else { Route.Add(Cities[city]); city = bestState.getEdge(city); } } bssf = new TSPSolution(Route); // update the cost of the tour. Program.MainForm.tbCostOfTour.Text = " " + bssf.costOfRoute(); Program.MainForm.tbElapsedTime.Text = ts.TotalSeconds.ToString(); // do a refresh. Program.MainForm.Invalidate(); } }
public IncludeExcludeStates(State includeState, State excludeState) { this.includeState = includeState; this.excludeState = excludeState; }
/** * This method updates the nodes in the queue after inserting a new node * Time Complexity: O(log(|V|)) as reording the heap works by bubbling up the min value to the top * which takes as long as the depth of the tree which is log|V|. * Space Complexity: O(1) as it does not create any extra variables that vary with the size of the input. */ public void insert(State newState) { // update the count count++; states[count] = newState; if (count > maxNum) maxNum = count; // as long as its parent has a larger value and have not hit the root int indexIterator = count; while (indexIterator > 1 && states[indexIterator / 2].getPriority() > states[indexIterator].getPriority()) { // swap the two nodes State temp = states[indexIterator / 2]; states[indexIterator / 2] = states[indexIterator]; states[indexIterator] = temp; indexIterator /= 2; } }
/// <summary> /// solve the problem. This is the entry point for the solver when the run button is clicked /// right now it just picks a simple solution. /// </summary> public void solveProblem() { int x; Route = new ArrayList(); ArrayList CitiesLeft = new ArrayList(); for (x = 0; x < Cities.Length; x++) { CitiesLeft.Add( Cities[Cities.Length - x - 1]); } City curCity = (City)CitiesLeft[0]; Route.Add(curCity); CitiesLeft.RemoveAt(0); while (CitiesLeft.Count > 0) { double minDist = 999999; int minInd = 0; for (int i = 0; i < CitiesLeft.Count; i++) { City temp = (City)CitiesLeft[i]; if (curCity.costToGetTo(temp) < minDist) { minDist = curCity.costToGetTo(temp); minInd = i; } } Program.MainForm.tbCostOfTour.Text += "Ind " + minInd; curCity = (City)CitiesLeft[minInd]; Route.Add(curCity); CitiesLeft.RemoveAt(minInd); } // call this the best solution so far. bssf is the route that will be drawn by the Draw method. bssf = new TSPSolution(Route); // update the cost of the tour. Program.MainForm.tbCostOfTour.Text = " " + bssf.costOfRoute(); Program.MainForm.tbElapsedTime.Text = "initial bssf"; // do a refresh. Program.MainForm.Invalidate(); //My solving begins here //generate first adjacency matrix double[,] firstAdj = new double[Cities.Length,Cities.Length]; for (int i = 0; i < Cities.Length; i++) { for (int j = 0; j < Cities.Length; j++) { if (i == j) firstAdj[i, j] = 999999; else firstAdj[i, j] = Cities[i].costToGetTo(Cities[j]); } } State firstState = new State(firstAdj); Agenda myAgenda = new Agenda(Cities.Length); myAgenda.Add(firstState); //Start timer and go DateTime start = DateTime.Now; DateTime timeUp = DateTime.Now.AddSeconds(60); while ((myAgenda.hasNextState()) && (DateTime.Now <= timeUp)) { State s = myAgenda.nextState; if ((s.routeSF.Count == Cities.Length) && s.costSF < bssf.costOfRoute()) { TSPSolution posS = new TSPSolution(s.routeSF); if (posS.costOfRoute() < bssf.costOfRoute()) { bssf = posS; //Prune the agenda myAgenda.Prune(bssf.costOfRoute()); // update the cost of the tour. Program.MainForm.tbCostOfTour.Text = " " + bssf.costOfRoute(); Program.MainForm.tbElapsedTime.Text = " " + (DateTime.Now - start); // do a refresh. Program.MainForm.Invalidate(); } } else { ArrayList newStates = s.Expand(Cities); foreach (State state in newStates) { if (state.lowerBound < bssf.costOfRoute()) myAgenda.Add(state); } } } if (DateTime.Now < timeUp) Program.MainForm.tbElapsedTime.Text += " true"; Program.MainForm.tbCostOfTour.Text += " MC " + myAgenda.MaxCount + " NP " + myAgenda.NumPruned; }
//O(n^2) public State makeInclude(int x, int y, State state) { State includeState = new State(copyMatrix(state.getMap()), state.getLB(), state.getEdges()); //O(n^2) includeState.setPoint(y, x, double.PositiveInfinity); //set the "opposite point to infinity" for (int j = 0; j < includeState.getMap().GetLength(1); j++) //set the row to infinity, O(n) { includeState.setPoint(x, j, double.PositiveInfinity); } for (int i = 0; i < includeState.getMap().GetLength(0); i++) //set the column to infinity, O(n) { includeState.setPoint(i, y, double.PositiveInfinity); } reduceMatrix(includeState); //O(n^2) includeState.setEdges(state.getEdges()); //initialize includeState's dictionary of edges return includeState; }
// Copy constructor for making children (Josh) // Reduces matrix based on whether edge is included // Adds state to queue public State(State parent, Boolean include, int from, int to) { matrix = (double[,])parent.matrix.Clone(); route = new ArrayList(parent.route); visited = new ArrayList(parent.visited); bound = parent.bound; this.parent = parent; depth = parent.depth + 1; if (include) { bound += matrix[from, to]; pathsLeft = parent.pathsLeft - 1; visited.Add(from); visited.Add(to); for (int i = 0; i < cityCount; i++) { matrix[from, i] = double.PositiveInfinity; matrix[i, to] = double.PositiveInfinity; } // If there's more than one path left, delete paths to used vertices (Josh) if (pathsLeft > 2) { for (int i = 0; i < visited.Count; i++) { matrix[to, (int)visited[i]] = double.PositiveInfinity; // Shouldn't be necessary, but who knows? matrix[(int)visited[i], from] = double.PositiveInfinity; } } else if (pathsLeft == 2) { //this should keep the path from the final city back to the first one for (int i = 1; i < visited.Count; i++) { matrix[to, (int)visited[i]] = double.PositiveInfinity; // Shouldn't be necessary, but who knows? matrix[(int)visited[i], from] = double.PositiveInfinity; } } matrix[to, from] = double.PositiveInfinity; } else { matrix[from, to] = double.PositiveInfinity; pathsLeft = parent.pathsLeft; } reduceMatrix(); // set BSSF if necessary (Josh) // If not, set BSSF if necessary (Josh) if (pathsLeft == 1) { for (int i = 0; i < cityCount; i++) { for (int j = 0; j < cityCount; j++) { if (matrix[i, j] != double.PositiveInfinity) { includeChild = new State(this, true, i, j); Console.WriteLine("Found solution"); for (int k = 0; k < includeChild.visited.Count; k++) { Console.WriteLine(includeChild.visited[k]); } if (includeChild.bound < BSSF.bound) { // Calculate route from visited nodes includeChild.calculateRoute(); BSSF = includeChild; // Prune states starting with root root.prune(); } else { return; } } } } } // Add to queue if (pathsLeft > 0 && bound < BSSF.bound) { queue.Enqueue(this, Priority); } }
private ArrayList generateChildren(State u) { ArrayList children = new ArrayList(); int row = (int)u.path[(u.path.Count-1)]; for (int i = 0; i < Cities.Length; i++) { if (u.matrix[row, i] != double.MaxValue && !u.path.Contains(i)) { State child = new State(u); child.path.Add(i); child.boundValue += child.matrix[row, i]; for (int j = 0; j < Cities.Length; j++) { child.matrix[row, j] = double.MaxValue; child.matrix[j, i] = double.MaxValue; } child.calculateBound(); children.Add(child); } } return children; }
// Finds initial BSSF (Brian) // Call after setting cost matrix // Use vertices to the right (or left) of the diagonal // Cost matrix of initial BSSF, doesn't matter // Only the route and bound matter // So don't worry about the rest of the fields public void setInitialBSSF() { ArrayList bssfCities = new ArrayList(); double cost = 0; // TODO: fill this in for (int i = 0; i < cityCount; i++) { bssfCities.Add(cities[(i + 1) % cityCount]); cost += matrix[(i + 1) % cityCount, i]; } BSSF = new State(bssfCities, cost); }
public State(State m) { this.path = (ArrayList) m.path.Clone(); this.matrix = (double[,]) m.matrix.Clone(); this.boundValue = m.boundValue; }
private State initState() { State s = new State(); s.matrix = new double[Cities.Length, Cities.Length]; for (int i = 0; i < Cities.Length; i++) { for (int j = 0; j < Cities.Length; j++) { double entry = Cities[i].costToGetTo(Cities[j]); if (entry == 0) entry = double.MaxValue; s.matrix[i, j] = entry; } } s.calculateBound(); return s; }
//O(n^2) public void reduceMatrix(State currentState) { double lowerBound = currentState.getLB(); for (int i = 0; i < currentState.getMap().GetLength(0); i++) // reduce rows {//O(n^2) double minimum = double.PositiveInfinity; //find the lowest value in that row to reduce for (int j = 0; j < currentState.getMap().GetLength(1); j++) { if (currentState.getPoint(i, j) < minimum) minimum = currentState.getPoint(i, j); } if (minimum == 0) //if there is already a 0 in that row, don't waste time looping through it continue; if (minimum != double.PositiveInfinity) { for (int j = 0; j < currentState.getMap().GetLength(1); j++) { //reduce the other entire row by that value double reducedPoint = currentState.getPoint(i, j) - minimum; currentState.setPoint(i, j, reducedPoint); } lowerBound += minimum; //add that lowest value to the lowerBound } } for (int j = 0; j < currentState.getMap().GetLength(1); j++) //reduce columns {//O(n^2) double minimum = double.PositiveInfinity; for (int i = 0; i < currentState.getMap().GetLength(0); i++) { if (currentState.getPoint(i, j) < minimum) minimum = currentState.getPoint(i, j); //find the lowest value in the column } if (minimum == 0) //if there is already a 0 in that column, don't waste time looping through it continue; if (minimum != double.PositiveInfinity) { for (int i = 0; i < currentState.getMap().GetLength(0); i++) {//reduce the entire column by that value double lowerPoint = currentState.getPoint(i, j) - minimum; currentState.setPoint(i, j, lowerPoint); } lowerBound += minimum; //add that minimum value to the lowerBound } } currentState.setLB(lowerBound); //set the lowerbound }
/// <summary> /// solve the problem. This is the entry point for the solver when the run button is clicked /// right now it just picks a simple solution. /// </summary> public void solveProblem() { State state = new State(Cities); bssf = new TSPSolution(State.BSSF.Route); Console.WriteLine(bssf.costOfRoute()); Console.WriteLine(State.BSSF.Bound); Debug.Assert(bssf.costOfRoute() == State.BSSF.Bound); Program.MainForm.tbCostOfTour.Text = " " + bssf.costOfRoute(); Program.MainForm.tbElapsedTime.Text = State.Watch.Elapsed.ToString(); Program.MainForm.Invalidate(); // Trivial solution, what appeared here originally // Uncomment to see how it works /*int x; Route = new ArrayList(); // this is the trivial solution. for (x = 0; x < Cities.Length; x++) { Route.Add( Cities[Cities.Length - x -1]); } // call this the best solution so far. bssf is the route that will be drawn by the Draw method. bssf = new TSPSolution(Route); // update the cost of the tour. Program.MainForm.tbCostOfTour.Text = " " + bssf.costOfRoute(); // do a refresh. Program.MainForm.Invalidate();*/ }
public ArrayList RunTSP(City[] Cities) { Route = new ArrayList(); Stopwatch timer = new Stopwatch(); bAndBTime = new TimeSpan(); timer.Start(); Greedy greedyAlgorithm = new Greedy(Cities); ArrayList greedyRoute = greedyAlgorithm.RunGreedyTSP(); double[,] matrix = new double[Cities.Length, Cities.Length]; //Populate each array item with each respective edge cost for (int i = 0; i < Cities.Length; i++) {//O(n^2) for (int j = 0; j < Cities.Length; j++) { if (i == j) { matrix[i, j] = double.PositiveInfinity; } else { matrix[i, j] = Cities[i].costToGetTo(Cities[j]); } } } IntervalHeap<State> queue = new IntervalHeap<State>(); double bestSolutionSoFar = greedyAlgorithm.BestSolutionSoFar(); bssfUpdatesAmt = 0; prunedAmt = 0; State bssfState = null; totalStatesCreated = 0; //Start with some problem State curState = new State(matrix, 0, new Edge(-1, -1)); totalStatesCreated++; //Reduce Matrix //O(4n^2) curState.Reduce(); //Let the queue be the set of active subproblems //O(log(n)) queue.Add(curState); maxQueueCount = 0; bool timesUp = false; while (queue.Count > 0) {//O(2^n) or O(2^(8n^2 + 9n + 2log(n))) if (timer.Elapsed.Seconds >= 30) { timesUp = true; break; } //Choose a subproblem and remove it from the queue if (queue.Count > maxQueueCount) { maxQueueCount = queue.Count; } //O(log(n)) curState = queue.DeleteMin(); if (curState.Cost() < bestSolutionSoFar) {//O(8n^2 + 9n + 2log(n)) //For each lowest cost (each 0) double highestScore = double.NegativeInfinity; State[] includeExcludeStates = new State[2]; foreach (Edge edge in curState.LowestNums()) {//O(8n^2 + 9n) //Include Matrix State includeState = new State(curState, edge); //O(n) totalStatesCreated++; includeState.IncludeMatrix(edge.Row(), edge.Col()); //O(4n^2 + 7n) //Exclude Matrix State excludeState = new State(curState, edge); //O(n) totalStatesCreated++; excludeState.ExcludeMatrix(edge.Row(), edge.Col());//O(4n^2) //Find the score for that edge (Exclude cost - Include cost) double score = excludeState.Cost() - includeState.Cost(); if (score > highestScore) { includeExcludeStates[0] = includeState; includeExcludeStates[1] = excludeState; highestScore = score; } } foreach (State subproblemState in includeExcludeStates) {//O(2log(n)) //if each P (subproblem) chosen is a complete solution, update the bssf if (subproblemState.CompleteSolution() && subproblemState.Cost() < bestSolutionSoFar) { bestSolutionSoFar = subproblemState.Cost(); bssfState = subproblemState; bssfUpdatesAmt++; } //else if lowerBound < bestSolutionSoFar else if (!subproblemState.CompleteSolution() && subproblemState.Cost() < bestSolutionSoFar) { //O(log(n)) queue.Add(subproblemState); } else { prunedAmt++; } } } } if (!timesUp) prunedAmt += queue.Count; //Call this the best solution so far. bssf is the route that will be drawn by the Draw method. if (bssfState != null) { int index = bssfState.Exited(0); Route.Add(Cities[index]); index = bssfState.Exited(bssfState.Exited(0)); while (index != bssfState.Exited(0)) {//O(n) Route.Add(Cities[index]); index = bssfState.Exited(index); } } else { Route = greedyRoute; } timer.Stop(); bAndBTime = timer.Elapsed; this.count = bssfState.Cost(); // update the cost of the tour. timer.Reset(); return Route; }
///////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////// BB Algorithm //////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// #region MainBBAlgorithm /// <summary> /// performs a Branch and Bound search of the state space of partial tours /// stops when time limit expires and uses BSSF as solution /// Time Complexity: O((n^2)*(2^n) as that is the most dominant factor in the code, and it is a result /// of the loop, for more details scroll to the comment above the loop in the function. /// Space Complexity: O((n^2)*(2^n) as that is the most dominant factor in the code, and it is a result /// of the loop, for more details scroll to the comment above the loop in the function. /// </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]; // Helper variables /* This part of the code takes O(1) space and time as we are just initializing some data */ int numOfCitiesLeft = Cities.Length; int numOfSolutions = 0; int numOfStatesCreated = 0; int numOfStatesNotExpanded = 0; // Initialize the time variable to stop after the time limit, which is defaulted to 60 seconds /* This part of the code takes O(1) space and time as we are just initializing some data */ DateTime start = DateTime.Now; DateTime end = start.AddSeconds(time_limit/1000); // Create the initial root State and set its priority to its lower bound as we don't have any extra info at this point /* This part of the code takes O(n^2) space and time as explained above */ State initialState = createInitialState(); numOfStatesCreated++; initialState.setPriority(calculateKey(numOfCitiesLeft - 1, initialState.getLowerBound())); // Create the initial BSSF Greedily /* This part of the code takes O(n^2) time and O(n) space as explained above */ double BSSFBOUND = createGreedyInitialBSSF(); // Create the queue and add the initial state to it, then subtract the number of cities left /* This part of the code takes O(1) time since we are just creating a data structure and O(1,000,000) space which is just a constant so O(1) space as well*/ PriorityQueueHeap queue = new PriorityQueueHeap(); queue.makeQueue(Cities.Length); queue.insert(initialState); // Branch and Bound until the queue is empty, we have exceeded the time limit, or we found the optimal solution /* This loop will have a iterate 2^n times approximately with expanding and pruning for each state, then for each state it does O(n^2) work by reducing the matrix, so over all O((n^2)*(2^n)) time and space as well as it creates a nxn matrix for each state*/ while (!queue.isEmpty() && DateTime.Now < end && queue.getMinLB() != BSSFBOUND) { // Grab the next state in the queue State currState = queue.deleteMin(); // check if lower bound is less than the BSSF, else prune it if (currState.getLowerBound() < BSSFBOUND) { // Branch and create the child states for (int i = 0; i < Cities.Length; i++) { // First check that we haven't exceeded the time limit if (DateTime.Now >= end) break; // Make sure we are only checking cities that we haven't checked already if (currState.getPath().Contains(Cities[i])) continue; // Create the State double[,] oldCostMatrix = currState.getCostMatrix(); double[,] newCostMatrix = new double[Cities.Length, Cities.Length]; // Copy the old array in the new one to modify the new without affecting the old for (int k = 0; k < Cities.Length; k++) { for (int l = 0; l < Cities.Length; l++) { newCostMatrix[k, l] = oldCostMatrix[k, l]; } } City lastCityinCurrState = (City)currState.getPath()[currState.getPath().Count-1]; double oldLB = currState.getLowerBound(); setUpMatrix(ref newCostMatrix, Array.IndexOf(Cities, lastCityinCurrState), i, ref oldLB); double newLB = oldLB + reduceMatrix(ref newCostMatrix); ArrayList oldPath = currState.getPath(); ArrayList newPath = new ArrayList(); foreach (City c in oldPath) { newPath.Add(c); } newPath.Add(Cities[i]); State childState = new State(ref newPath, ref newLB, ref newCostMatrix, Cities.Length); numOfStatesCreated++; // Prune States larger than the BSSF if (childState.getLowerBound() < BSSFBOUND) { City firstCity = (City)childState.getPath()[0]; City lastCity = (City)childState.getPath()[childState.getPath().Count-1]; double costToLoopBack = lastCity.costToGetTo(firstCity); // If we found a solution and it goes back from last city to first city if (childState.getPath().Count == Cities.Length && costToLoopBack != double.MaxValue) { childState.setLowerBound(childState.getLowerBound() + costToLoopBack); bssf = new TSPSolution(childState.getPath()); BSSFBOUND = bssf.costOfRoute(); numOfSolutions++; numOfStatesNotExpanded++; // this state is not expanded because it is not put on the queue } else { // Set the priority for the state and add the new state to the queue numOfCitiesLeft = Cities.Length - childState.getPath().Count; childState.setPriority(calculateKey(numOfCitiesLeft, childState.getLowerBound())); queue.insert(childState); } } else { numOfStatesNotExpanded++; // States that are pruned are not expanded } } } currState = null; } numOfStatesNotExpanded += queue.getSize(); // if the code terminated before queue is empty, then those states never got expanded Console.WriteLine("Number of states generated: " + numOfStatesCreated); Console.WriteLine("Number of states not Expanded: " + numOfStatesNotExpanded); Console.WriteLine("Max Number of states put in queue: " + queue.getMaxNumOfItems()); end = DateTime.Now; TimeSpan diff = end - start; double seconds = diff.TotalSeconds; results[COST] = System.Convert.ToString(bssf.costOfRoute()); // load results into array here, replacing these dummy values results[TIME] = System.Convert.ToString(seconds); results[COUNT] = System.Convert.ToString(numOfSolutions); return results; }