//**********************************************BBAlgorithm*********************************************************************************
        /// <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];

            // TODO: Add your implementation for a branch and bound solver here.
            //Initalize variables. Takes O(1) space and time
            int numOfCitiesLeft        = Cities.Length;
            int numOfSolutions         = 0;
            int numOfStatesCreated     = 0;
            int numOfStatesNotExpanded = 0;

            //Initalize time variable for stopping the algorithm after the default of 60 seconds. Takes O(1) space and time
            DateTime start = DateTime.Now;
            DateTime end   = start.AddSeconds(time_limit / 1000);

            //Create initial root state and set its priority to its lower bound. Takes O(n^2) space and time as discussed above
            TSPState initialState = createInitialState();

            numOfStatesCreated++;
            initialState.setPriority(calculateKey(numOfCitiesLeft - 1, initialState.getLowerBound()));

            //Create initial BSSF greedily
            double bssfBound = createGreedyBssf();

            PriorityQueue queue = new PriorityQueue(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
                TSPState 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]);
                        TSPState childState = new TSPState(ref newPath, ref newLB, ref newCostMatrix);
                        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);
        }
        /// <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 solveProblemBandB()
        {
            //initialize BSSF with a greedy algorithm
            Algorithms algorithms = new Algorithms();
            bssf = new TSPSolution(algorithms.greedy(Cities));
            Node.bssf = bssf.costOfRoute();

            int maxQsize = 0;
            int totalStates = 0;

            int timeSeconds = Convert.ToInt32(Program.MainForm.textBoxTime.Text);

            //set up priority queue and stopwatch
            PriorityQueue PQ = new PriorityQueue();
            PQ.insert(new Node(Cities));
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            while(PQ.getSize() > 0 && stopwatch.Elapsed.TotalSeconds < timeSeconds)
            {
                //pop node off of queue and check lower bound against bssf
                Node node = PQ.deleteMin();
                if(node.lowerBound > Node.bssf)
                {
                    Node.prunes++;
                    break;
                }

                Node include = null;
                Node exclude = null;
                double maxDif = Double.NegativeInfinity;

                //search for include/exclude edge that gives max difference in lower bound
                double[,] matrix = node.rCmatrix;
                for (int i = 0; i < node.matrixLength; i++)
                {
                    if (node.exited[i] == -1)
                    {
                        for (int j = 0; j < node.matrixLength; j++)
                        {
                            if (matrix[i, j] == 0)
                            {
                                Node tempInclude = new Node(node, true, i, j);
                                Node tempExclude = new Node(node, false, i, j);
                                double potentialMaxDif = tempExclude.lowerBound - tempInclude.lowerBound;
                                if (potentialMaxDif > maxDif)
                                {
                                    maxDif = potentialMaxDif;
                                    include = tempInclude;
                                    exclude = tempExclude;
                                }
                            }
                        }
                    }

                }

                //check if found a bssf
                if(include.totalEdges == include.matrixLength && include.lowerBound < Node.bssf)
                {
                    Node.bssfUpdates++;
                    Node.bssf = include.lowerBound;
                    Node.bssfNode = include;
                }
                else if(include.lowerBound < Node.bssf)//add include node to queue
                {
                    PQ.insert(include);
                    int currentQSize = PQ.getSize();
                    if(currentQSize > maxQsize)
                    {
                        maxQsize = currentQSize;
                    }
                }
                else//prune include node
                {
                    Node.prunes++;
                }

                if(exclude.lowerBound < Node.bssf)//add exclude node to queue
                {
                    PQ.insert(exclude);
                    int currentQSize = PQ.getSize();
                    if (currentQSize > maxQsize)
                    {
                        maxQsize = currentQSize;
                    }
                }
                else//prune exclude node
                {
                    Node.prunes++;
                }

                totalStates += 2;//2 states are created per while-loop iteration

            }

            stopwatch.Stop();

            //if stopwatch is < 30, then we have found an optimal solution
            bool isOptimal = false;
            if(stopwatch.Elapsed.TotalSeconds < timeSeconds)
            {
                isOptimal = true;
            }

            //prune number of items left in the queue
            Node.prunes += PQ.getSize();

            //if a bssf has been found better than the greedy solution
            if(Node.bssfNode != null)
            {
                Node solution = Node.bssfNode;

                ArrayList route = solution.getRoute(Cities);

                // call this the best solution so far.  bssf is the route that will be drawn by the Draw method.
                bssf = new TSPSolution(route);
            }

            //display stats
            if (isOptimal)
            {
                Program.MainForm.tbCostOfTour.Text = " " + bssf.costOfRoute() + "*";
            }
            else
            {
                Program.MainForm.tbCostOfTour.Text = " " + bssf.costOfRoute();
            }

            Program.MainForm.tbElapsedTime.Text = " " + stopwatch.Elapsed.TotalSeconds;

            // do a refresh.
            Program.MainForm.Invalidate();

            //print more stats
            Console.WriteLine();
            Console.WriteLine("Max # of stored states: " + maxQsize);
            Console.WriteLine("# of BSSF updates: " + Node.bssfUpdates);
            Console.WriteLine("Total # of states created: " + totalStates);
            Console.WriteLine("Total # of states pruned: " + Node.prunes);

            Node.resetStaticVariables();
        }
예제 #3
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];

            results[COST]  = "not implemented";   // load results into array here, replacing these dummy values
            results[TIME]  = "-1";
            results[COUNT] = "-1";

            int count = 0;

            Console.Out.WriteLine("City costs: ");
            for (int j = 0; j < Cities.Length; j++)
            {
                for (int h = 0; h < Cities.Length; h++)
                {
                    Console.Write(Cities[j].costToGetTo(Cities[h]) + ",");
                }
                Console.WriteLine();
            }

            Stopwatch timer = new Stopwatch();

            timer.Start();

            PriorityQueue queue = new PriorityQueue();

            queue.make_queue(Cities.Length * Cities.Length * Cities.Length * Cities.Length);

            //Here I run the greedy algorithm and use that BSSF result as my starting BSSF
            greedySolveProblem();
            Console.Out.WriteLine("Greedy BSSF: " + costOfBssf());

            matrix_and_bound initial_matrix = construct_initial_matrix();


            for (int j = 0; j < Cities.Length; j++)
            {
                for (int h = 0; h < Cities.Length; h++)
                {
                    Console.Write(initial_matrix.Matrix[j, h] + ",");
                }
                Console.WriteLine();
            }
            Console.WriteLine(initial_matrix.Lower_bound);
            //Console.WriteLine();


            //This loop will do my initial population of the queue by looping through each city and getting the lower bound
            for (int i = 0; i < Cities.Length; i++)
            {
                for (int k = 0; k < Cities.Length; k++)
                {
                    if (i != k)
                    {
                        //I need to get the lower bound of each reduced matrix and the bound
                        matrix_and_bound current = matrix_reduction(initial_matrix, i, k);


                        //Console.WriteLine();

                        //If the lower bound is less than current bssf add to queue for later checking, otherwise ignore
                        if (current.Lower_bound < costOfBssf())
                        {
                            //need to create new state_data object with state data set
                            state_data data = new state_data();
                            //I guess depth doesn't matter to be exact so long as it's relative, so I'll keep this first one as 0
                            data.Depth = 0;
                            data.Mb    = current;

                            data.add_city(Cities[i]);
                            data.add_city(Cities[k]);

                            data.add_city_index(i);
                            data.add_city_index(k);

                            data.set_priority();
                            Console.Out.WriteLine("bound " + data.Mb.Lower_bound);
                            //I'm not sure this id is necessary but I'll have to see
                            data.Id = id;

                            queue.insert(data, id);
                            id++;
                        }
                    }
                }
            }

            Console.Out.WriteLine("Queue length Initial " + queue.Length);
            //now run while queue is not empty and timer is less than 60
            while (timer.Elapsed.TotalSeconds < 60 && queue.Length > 0)
            {
                //pop off of queue and repeat above matrix reduction process
                state_data current = queue.delete_min();
                //if it's greater or equal to the current bssf I can just ignore it, this is the culling
                if (current.Mb.Lower_bound < costOfBssf())
                {
                    //Priority queue looks like it's working
                    //Console.Out.WriteLine(current.Mb.Lower_bound);

                    /*
                     * Now I need to matrix reduce each child of the current node,
                     * see if it's still smaller than the current bssf if it's a leaf node
                     * I put it as the current bssf, otherwise I push it on the queue
                     */

                    for (int k = 0; k < Cities.Length; k++)
                    {
                        if (!current.City_list.Contains(k))
                        {
                            matrix_and_bound child = matrix_reduction(current.Mb, (int)current.City_list[current.City_list.Count - 1], k);

                            //Console.Out.WriteLine("here");

                            //Console.Out.WriteLine("Current depth: " + );
                            for (int j = 0; j < Cities.Length; j++)
                            {
                                for (int h = 0; h < Cities.Length; h++)
                                {
                                    Console.Write(child.Matrix[j, h] + ",");
                                }
                                Console.WriteLine();
                            }
                            Console.WriteLine(child.Lower_bound);

                            if (child.Lower_bound < costOfBssf())
                            {
                                //need to create new state_data object with state data set
                                state_data data = new state_data();
                                //I guess depth doesn't matter to be exact so long as it's relative, so I'll keep this first one as 0
                                data.Depth = current.Depth + 1;
                                data.Mb    = child;

                                //The last value in the path is the current city
                                data.Path      = current.Path;
                                data.City_list = current.City_list;
                                data.add_city(Cities[k]);

                                /* Console.Out.WriteLine("The Current Path and length " + data.City_list.Count);
                                 * for (int j = 0; j < data.City_list.Count; j++)
                                 * {
                                 *   Console.Out.Write(data.City_list[j] + "->");
                                 * }
                                 * Console.Out.WriteLine();*/


                                data.City_list = current.City_list;
                                data.add_city_index(k);

                                data.set_priority();
                                //Console.Out.WriteLine("Set Priority " + data.Priority);
                                //I'm not sure this id is necessary but I'll have to see
                                data.Id = id;
                                id++;

                                // Console.Out.WriteLine("Intermediate Lower Bound " + data.Mb.Lower_bound);

                                if (data.City_list.Count < Cities.Length)
                                {
                                    queue.insert(data, id);
                                }
                                else if (data.Mb.Lower_bound < costOfBssf())//it's a leaf node and it's less than the current BSSF
                                {
                                    Console.Out.WriteLine("Current Lower Bound " + costOfBssf());
                                    Console.Out.WriteLine("Final Lower Bound " + data.Mb.Lower_bound);
                                    for (int j = 0; j < data.City_list.Count; j++)
                                    {
                                        Console.Out.Write(data.City_list[j] + "->");
                                    }


                                    bssf = new TSPSolution(data.Path);
                                    count++;
                                }
                            }
                        }
                    }
                }
            }

            results[COST]  = costOfBssf().ToString();
            results[TIME]  = timer.Elapsed.ToString();
            results[COUNT] = count.ToString();

            return(results);
        }
예제 #4
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];
            int                   solutionCount      = 0;
            Stopwatch             timer              = new Stopwatch();
            PriorityQueue <State> pQueue             = new PriorityQueue <State>();
            int                   maxStoredStates    = 0;
            int                   bssfUpdates        = 0;
            int                   totalStatesCreated = 0;
            int                   totalStatesPruned  = 0;

            timer.Start();
            string[] intialResults = defaultSolveProblem();
            double   bestCostSoFar = Int32.Parse(intialResults[COST]);

            Console.WriteLine("BestCostSoFar: " + bestCostSoFar);

            State initialState = initializeState();

            this.reduceState(ref initialState);
            pQueue.insert(initialState, (int)initialState.lowerBound);

            while (!pQueue.isEmpty() && timer.Elapsed.Seconds < 60)             // while queue is not empty or has not passed 60 seconds
            {
                State parentState = pQueue.deleteMin();
                if (parentState.lowerBound >= bestCostSoFar)                 // trim queue if state has worse bound than bssf
                {
                    totalStatesPruned++;
                    continue;
                }
                for (int i = 0; i < this.Cities.Length; i++)
                {
                    if (!parentState.visited.Contains(i))
                    {
                        // createChild
                        totalStatesCreated++;
                        State childState = parentState.getCopy();
                        this.addCityToRoute(ref childState, i);
                        this.reduceState(ref childState);
                        if (childState.route.Count == this.Cities.Count())                         // if route is complete
                        {
                            TSPSolution newSolution = new TSPSolution(childState.route);
                            double      cost        = newSolution.costOfRoute();
                            if (cost < bestCostSoFar)
                            {
                                bssfUpdates++;
                                bestCostSoFar = cost;
                                bssf.Route    = childState.route;
                            }
                        }
                        else                                           // route is not complete
                        {
                            if (childState.lowerBound < bestCostSoFar) // don't insert in queue if state has worse bound than bssf
                            {
                                pQueue.insert(childState, (int)childState.lowerBound);
                                if (pQueue.getCount() > maxStoredStates)
                                {
                                    maxStoredStates = pQueue.getCount();
                                }
                            }
                            else
                            {
                                totalStatesPruned++;
                            }
                        }
                    }
                }
            }

            timer.Stop();

            results[COST]  = costOfBssf().ToString();
            results[TIME]  = timer.Elapsed.ToString();
            results[COUNT] = solutionCount.ToString();


            Console.WriteLine("===================================");
            Console.WriteLine("StatesCreated: " + totalStatesCreated);
            Console.WriteLine("StatesPruned: " + totalStatesPruned);
            Console.WriteLine("bssfUpdates: " + bssfUpdates);
            Console.WriteLine("MaxStoredStates: " + maxStoredStates);


            return(results);
        }