Esempio n. 1
0
        /// <summary>
        ///     Combine both A -&gt; Z and Round Trip with optimize by many algorithm and distance,
        ///     duration by Google Matrix
        /// </summary>
        /// <param name="coordinates"> </param>
        /// <param name="mode">        </param>
        /// <param name="googleApiKey">
        ///     Use for FastestTripMode.RoundTrip - Optional, method still work without key but have
        ///     limitation by Google Policy.
        /// </param>
        /// <remarks>
        ///     Concorde TSP Solver algorithm combine with Ant colony optimization algorithms to find
        ///     wayCoordinate and best path
        /// </remarks>
        public FastestTrip(IReadOnlyCollection <Models.Coordinate> coordinates, FastestTripMode mode = FastestTripMode.AtoZ, string googleApiKey = "")
        {
            if (coordinates.Count < 1)
            {
                throw new NotSupportedException();
            }

            _tripMode = mode;

            _googleApiKey = googleApiKey;

            Coordinates = new List <Models.Coordinate>();

            Coordinates.AddRange(coordinates);

            // Get Distance Duration Matrix

            var coordinateModels = Coordinates.Select(x => new CoordinateModel(x.Longitude, x.Latitude)).ToArray();

            var getDistanceDurationMatrixTask = GoogleMapHelper.GetDistanceDurationMatrixAsync(coordinateModels, coordinateModels, googleApiKey: _googleApiKey);

            getDistanceDurationMatrixTask.Wait();

            DistanceDurationDurationMatrix = getDistanceDurationMatrixTask.Result;

            // Start Calculate Trip

            CalculateTrip(mode);
        }
Esempio n. 2
0
        private void CalculateTripBackTrackingImplementation(int start, FastestTripMode mode)
        {
            _currentCost = 0;

            _bestCost = MaxTripSentry;

            _currentPath = new int[Coordinates.Count];

            _visitTracks = new bool[Coordinates.Count];

            _min = new double[Coordinates.Count];

            for (int i = 0; i < Coordinates.Count; i++)
            {
                _min[i] = GetMinDistance(i);
            }

            _minCost = _min.Sum();

            if (mode == FastestTripMode.AtoZ)
            {
                _minCost -= _min[start];
            }

            _currentPath[0] = start;

            _visitTracks[start] = true;

            BackTrackingVisit(1);
        }
Esempio n. 3
0
        private void CalculateTrip(FastestTripMode mode)
        {
            if (Coordinates.Count <= 13)
            {
                CalculateTripBackTrackingImplementation(0, mode);
            }
            else if (Coordinates.Count <= 15)
            {
                TspDynamic(mode);
            }
            else
            {
                TspAntColonyK2(mode);

                TspK3();
            }
        }
Esempio n. 4
0
        /// <summary>
        ///     Ant colony optimization algorithms and Solves the TSP problem to optimality. Memory
        ///     requirement is O(numActive * 2^numActive)
        /// </summary>
        private void TspDynamic(FastestTripMode mode)
        {
            BestPath = new List <int>();

            NextSet = new List <int>();

            BestTrip = MaxTripSentry;

            int numActive = Coordinates.Count;

            var numCombos = 1 << Coordinates.Count;

            var c = new List <List <double> >();

            var parent = new List <List <int> >();

            for (var i = 0; i < numCombos; i++)
            {
                c.Add(new List <double>());

                parent.Add(new List <int>());

                for (var j = 0; j < numActive; ++j)
                {
                    c[i].Add(0.0);
                    parent[i].Add(0);
                }
            }

            int index;

            for (var k = 1; k < numActive; ++k)
            {
                index = 1 + (1 << k);

                c[index][k] = GetDistance(0, k);
            }
            for (var s = 3; s <= numActive; ++s)
            {
                for (var i = 0; i < numActive; ++i)
                {
                    NextSet.Add(0);
                }

                index = NextSetOf(s);

                while (index >= 0)
                {
                    for (var k = 1; k < numActive; ++k)
                    {
                        if (NextSet[k] != 0)
                        {
                            var previousIndex = index - (1 << k);

                            c[index][k] = MaxTripSentry;

                            for (var m = 1; m < numActive; ++m)
                            {
                                if (NextSet[m] != 0 && m != k)
                                {
                                    if (c[previousIndex][m] + GetDistance(m, k) < c[index][k])
                                    {
                                        c[index][k]      = c[previousIndex][m] + GetDistance(m, k);
                                        parent[index][k] = m;
                                    }
                                }
                            }
                        }
                    }
                    index = NextSetOf(s);
                }
            }
            for (var i = 0; i < numActive; ++i)
            {
                BestPath.Add(0);
            }
            index = (1 << numActive) - 1;

            int currentNode;

            // Case RoundTrip (A -> A), A -> Z START
            if (mode == FastestTripMode.RoundTrip)
            {
                currentNode = -1;

                BestPath.Add(0);

                for (var i = 1; i < numActive; ++i)
                {
                    if (c[index][i] + GetDistance(i, 0) < BestTrip)
                    {
                        BestTrip    = c[index][i] + GetDistance(i, 0);
                        currentNode = i;
                    }
                }

                BestPath[numActive - 1] = currentNode;
            }
            else
            {
                currentNode             = numActive - 1;
                BestPath[numActive - 1] = numActive - 1;
                BestTrip = c[index][numActive - 1];
            }

            // Case A->A, A->Z END

            for (var i = numActive - 1; i > 0; --i)
            {
                currentNode     = parent[index][currentNode];
                index          -= (1 << BestPath[i]);
                BestPath[i - 1] = currentNode;
            }
        }
Esempio n. 5
0
        /// <summary>
        ///     Computes a near-optimal solution to the TSP problem, using Ant Colony Optimization
        ///     and local optimization in the form of k2-opting each candidate route. Run time is
        ///     O(numWaves * numAnts * numActive ^ 2) for ACO and O(numWaves * numAnts * numActive ^
        ///     3) for rewiring? if mode is 1, we start at node 0 and end at node numActive-1.
        /// </summary>
        /// <param name="mode"></param>
        private void TspAntColonyK2(FastestTripMode mode)
        {
            BestTrip = MaxTripSentry;

            int numActive = Coordinates.Count;

            _currentPath = new int[numActive];

            _visitTracks = new bool[numActive];

            var currentPath = new int[numActive];

            if (mode == FastestTripMode.RoundTrip)
            {
                currentPath = new int[numActive + 1];
            }

            var alpha = 0.1;           // The importance of the previous trails

            var beta = 2.0;            // The importance of the durations

            var rho = 0.1;             // The decay rate of the pheromone trails

            var asymptoteFactor = 0.9; // The sharpness of the reward as the solutions approach the best solution

            double[,] pher = new double[numActive, numActive];

            double[,] nextPher = new double[numActive, numActive];

            double[] prob = new double[numActive];

            var numAnts = 20;

            var numWaves = 20;

            for (var i = 0; i < numActive; ++i)
            {
                for (var j = 0; j < numActive; ++j)
                {
                    pher[i, j] = 1;

                    nextPher[i, j] = 0.0;
                }
            }

            var lastNode = 0;

            const int startNode = 0;

            var numSteps = numActive - 1;

            var numValidDest = numActive;

            if (mode == FastestTripMode.AtoZ)
            {
                lastNode = numActive - 1;

                numSteps = numActive - 2;

                numValidDest = numActive - 1;
            }
            for (var wave = 0; wave < numWaves; ++wave)
            {
                for (var ant = 0; ant < numAnts; ++ant)
                {
                    var currentNode = startNode;

                    var currentDistance = 0;

                    for (var i = 0; i < numActive; ++i)
                    {
                        _visitTracks[i] = false;
                    }

                    currentPath[0] = currentNode;

                    for (var step = 0; step < numSteps; ++step)
                    {
                        _visitTracks[currentNode] = true;

                        var cumProb = 0.0;

                        for (var next = 1; next < numValidDest; ++next)
                        {
                            if (!_visitTracks[next])
                            {
                                prob[next] = Math.Pow(pher[currentNode, next], alpha) *
                                             Math.Pow(GetDuration(currentNode, next), 0.0 - beta);
                                cumProb += prob[next];
                            }
                        }

                        var guess = new Random().NextDouble() * cumProb;

                        var nextI = -1;

                        for (var next = 1; next < numValidDest; ++next)
                        {
                            if (!_visitTracks[next])
                            {
                                nextI = next;

                                guess -= prob[next];

                                if (guess < 0)
                                {
                                    nextI = next;
                                    break;
                                }
                            }
                        }

                        currentDistance += (int)GetDuration(currentNode, nextI);

                        currentPath[step + 1] = nextI;

                        currentNode = nextI;
                    }

                    currentPath[numSteps + 1] = lastNode;

                    currentDistance += (int)GetDuration(currentNode, lastNode);

                    // k2-rewire:

                    var lastStep = numActive;

                    if (mode == FastestTripMode.AtoZ)
                    {
                        lastStep = numActive - 1;
                    }

                    var changed = true;

                    var m = 0;

                    while (changed)
                    {
                        changed = false;

                        for (; m < lastStep - 2 && !changed; ++m)
                        {
                            var cost = GetDuration(currentPath[m + 1], currentPath[m + 2]);

                            var revCost = GetDuration(currentPath[m + 2], currentPath[m + 1]);

                            var iCost = GetDuration(currentPath[m], currentPath[m + 1]);

                            for (var j = m + 2; j < lastStep && !changed; ++j)
                            {
                                var nowCost = cost + iCost + GetDuration(currentPath[j], currentPath[j + 1]);

                                var newCost = revCost + GetDuration(currentPath[m], currentPath[j]) + GetDuration(currentPath[m + 1], currentPath[j + 1]);

                                if (nowCost > newCost)
                                {
                                    currentDistance += (int)(newCost - nowCost);

                                    // Reverse the detached road segment.
                                    for (var k = 0; k < Math.Floor((double)(j - m) / 2); ++k)
                                    {
                                        double tmp = currentPath[m + 1 + k];

                                        currentPath[m + 1 + k] = currentPath[j - k];

                                        currentPath[j - k] = (int)tmp;
                                    }

                                    changed = true;

                                    --m;
                                }

                                cost += GetDuration(currentPath[j], currentPath[j + 1]);

                                revCost += GetDuration(currentPath[j + 1], currentPath[j]);
                            }
                        }
                    }

                    if (currentDistance < BestTrip)
                    {
                        BestPath = currentPath.ToList();

                        BestTrip = currentDistance;
                    }

                    for (var i = 0; i <= numSteps; ++i)
                    {
                        nextPher[currentPath[i], currentPath[i + 1]] += (BestTrip - asymptoteFactor * BestTrip) / (numAnts * (currentDistance - asymptoteFactor * BestTrip));
                    }
                }

                for (var i = 0; i < numActive; ++i)
                {
                    for (var j = 0; j < numActive; ++j)
                    {
                        pher[i, j] = pher[i, j] * (1.0 - rho) + rho * nextPher[i, j];

                        nextPher[i, j] = 0.0;
                    }
                }
            }
        }