예제 #1
0
        private TspState GreedyCalc(TspState state)
        {
            var n = state.CostMatrix.GetLength(0);

            while (!state.IsComplete)
            {
                TspState cheapestBranch      = null;
                var      cheapestBranchValue = double.PositiveInfinity;
                for (var toCity = 0; toCity < n; ++toCity)
                {
                    if (!state.CanVisit(toCity))
                    {
                        continue;
                    }
                    var testBranch = state.Visit(toCity);
                    if (testBranch.LowerBound >= cheapestBranchValue)
                    {
                        continue;
                    }
                    cheapestBranch      = testBranch;
                    cheapestBranchValue = testBranch.LowerBound;
                }
                if (cheapestBranch == null)
                {
                    return(null);
                }
                state = cheapestBranch;
            }
            return(state);
        }
예제 #2
0
        private TspState(TspState fromState, int toCity)
        {
            _size      = fromState._size;
            CostMatrix = (double[, ])fromState.CostMatrix.Clone();
            LowerBound = fromState.LowerBound;
            var fromCity = fromState.CurrentCity;

            Debug.Assert(toCity < _size && toCity >= 0);
            Debug.Assert(fromCity == -1 || !double.IsPositiveInfinity(CostMatrix[fromCity, toCity]), "Navigating to illegal city");
            Debug.Assert(fromState.NearComplete ? fromState.Path[0] == toCity : !fromState.Path.Contains(toCity), "Path contains illegal duplicate");
            Path        = fromState.Path.AppendToCopy(toCity);
            CurrentCity = toCity;

            // The cost matrix does not change when starting from nothing
            if (fromCity == -1)
            {
                return;
            }

            // Cannot go from toCity to CurrentCity (backwards)
            CostMatrix[toCity, fromCity] = double.PositiveInfinity;
            // The lower bound is increased by the cost of the path
            LowerBound += CostMatrix[fromCity, toCity];

            // Nothing else can go to toCity (inf toCity column)
            for (var row = 0; row < _size; ++row)
            {
                CostMatrix[row, toCity] = double.PositiveInfinity;
            }

            // The current node now can't go to anything as it's no longer the head of the path (inf fromCity row)
            for (var col = 0; col < _size; ++col)
            {
                CostMatrix[fromCity, col] = double.PositiveInfinity;
            }

            // Reduce the new state
            Reduce();
        }
예제 #3
0
        //if (_mode == HardMode.Modes.Hard)
        //{
        //    var upperBound = double.PositiveInfinity;
        //    for (var startCity = 0; startCity < _cities.Length; ++startCity)
        //    {
        //        var testState = BranchBoundCalc(baseState, startCity);
        //        if (testState == null || testState.LowerBound >= upperBound) continue;
        //        upperBound = testState.LowerBound;
        //        bestState = testState;
        //    }
        //}
        //else

        /////////////////////////////////////////////////////////////////////////////////////////////
        // These additional solver methods will be implemented as part of the group project.
        ////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        ///     finds the greedy tour starting from each city and keeps the best (valid) one
        /// </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[] GreedySolveProblem()
        {
            var results = new string[3];
            var timer   = new Stopwatch();

            Debug.Assert(_cities.Length > 0);
            timer.Start();
            var costMatrix = new TspState(_cities).CostMatrix;

            if (_mode == HardMode.Modes.Hard)
            {
                // CostOfBssf() is still used because new TspState reduces the matrix once
                var cost = double.PositiveInfinity;
                for (var startCity = 0; startCity < _cities.Length; ++startCity)
                {
                    var thisResult = FastGreedyCalc(startCity, costMatrix);
                    if (thisResult.Item1 >= cost)
                    {
                        continue;
                    }
                    cost  = thisResult.Item1;
                    _bssf = new TspSolution(thisResult.Item2.Select(i => _cities[i]));
                }
            }
            else
            {
                var cityIndexes = FastGreedyCalc(0, costMatrix);
                _bssf = new TspSolution(cityIndexes.Item2.Select(i => _cities[i]));
            }
            timer.Stop();

            results[Cost]  = CostOfBssf().ToString(CultureInfo.InvariantCulture);
            results[Time]  = timer.Elapsed.ToString();
            results[Count] = (_cities.Length + 1).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[] BranchBoundSolveProblem()
        {
            var results = new string[3];

            var timer = new Stopwatch();

            Debug.Assert(_cities.Length > 0);
            var baseState = new TspState(_cities);

            timer.Start();

            var n     = _cities.Length;
            var queue = new FastPriorityQueue <TspState>(n * n * n);

            baseState = baseState.Visit(0);
            queue.Enqueue(baseState, baseState.Heuristic());
            // The current best complete route
            var bestState  = GreedyCalc(baseState);
            var upperBound = bestState?.LowerBound ?? double.PositiveInfinity;
            var stored     = 0;
            var pruned     = 0;
            var maxStates  = 0;
            var updates    = 0;

            while (queue.Count > 0)
            {
                if (queue.Count > maxStates)
                {
                    maxStates = queue.Count;
                }
                // Get best state to check based on heuristic.
                // Runs in O(log n) time.
                var state = queue.Dequeue();
                // Branch
                for (var toCity = 0; toCity < n; ++toCity)
                {
                    // If we can't visit the city, no need to consider it
                    if (!state.CanVisit(toCity))
                    {
                        continue;
                    }
                    var branchState = state.Visit(toCity);
                    // Bound
                    if (branchState.LowerBound < upperBound)
                    {
                        if (branchState.IsComplete)
                        {
                            ++updates;
                            // On a complete instance, no need to add it to the queue.
                            Debug.Assert(branchState.CostMatrix.Cast <double>().All(double.IsPositiveInfinity),
                                         "Cost Matrix is not all infinity");
                            upperBound = branchState.LowerBound;
                            bestState  = branchState;
                            continue;
                        }
                        ++stored;
                        if (queue.Count + 5 >= queue.MaxSize)
                        {
                            queue.Resize(queue.MaxSize * 2);
                        }
                        // Runs in O(log n) time
                        queue.Enqueue(branchState, branchState.Heuristic());
                    }
                    else
                    {
                        ++pruned;
                    }
                }
                // Abandon ship and give the best result otherwise
                if (timer.ElapsedMilliseconds > _timeLimit)
                {
                    break;
                }
            }
            timer.Stop();

            Debug.Assert(bestState != null && bestState.IsComplete);
            _bssf = StateToSolution(bestState);

            results[Cost]  = CostOfBssf().ToString(CultureInfo.InvariantCulture); // load results array
            results[Time]  = timer.Elapsed.ToString();
            results[Count] = $"{maxStates}/{updates}/{stored}/{pruned}";

            return(results);
        }
예제 #5
0
 private TspSolution StateToSolution(TspState state)
 {
     return(new TspSolution(state.Path.Select(cityIndex => _cities[cityIndex])));
 }