Beispiel #1
0
        public IEnumerable<int> FindRandomDisjointTour(IntegerPermutation otherTour)
        {
            this.InitializeVisit();
            this.tabuEdgeList = TabuEdgeCollection.CreateFromTour(otherTour);

            var randomEdge = this.GetRandomEdge();

            while (tabuEdgeList.IsTabu(randomEdge))
                randomEdge = this.GetRandomEdge();

            this.VisitNode(randomEdge.Head);
            yield return randomEdge.Head;

            this.VisitNode(randomEdge.Tail);
            yield return randomEdge.Tail;

            int currentNode = randomEdge.Tail;

            TaskLogger.Text = "Computing greedy and tabu search to generate a disjoint tour...";

            while (unvisitedNodes.ItemsCount > 0)
            {
                int nearestUnvisitedNode = this.FindNearestUnvisitedNonTabuNode(currentNode);

                this.VisitNode(nearestUnvisitedNode);
                yield return nearestUnvisitedNode;

                currentNode = nearestUnvisitedNode;

                TaskLogger.Progress = 100.0 * visitedNodes.ItemsCount / nodes.Length;
            }
        }
Beispiel #2
0
        public static bool CheckDisjointness(IntegerPermutation tour1, IntegerPermutation tour2)
        {
            var tabuList = TabuEdgeCollection.CreateFromTour(tour1);

            for (int i = 1; i < tour2.Length; i++)
            {
                int head = tour2[i - 1];
                int tail = tour2[i];

                if (tabuList.IsTabu(head, tail))
                    return false;
            }

            return true;
        }
Beispiel #3
0
        public static TabuEdgeCollection CreateFromTour(IntegerPermutation otherTour)
        {
            var result = new TabuEdgeCollection();

            result.tabuDirectArcs = new int[otherTour.Length];
            result.tabuReverseArcs = new int[otherTour.Length];

            int upperBound = otherTour.Length - 1;

            for (int i = 0; i < upperBound; i++)
            {
                int head = otherTour[i];
                int tail = otherTour[i + 1];

                result.tabuDirectArcs[head] = tail;
                result.tabuReverseArcs[tail] = head;
            }

            result.tabuDirectArcs[otherTour[upperBound]] = otherTour[0];
            result.tabuReverseArcs[otherTour[0]] = otherTour[upperBound];

            return result;
        }
Beispiel #4
0
        public void CrossOptimize(IntegerPermutation solution, IntegerPermutation betterSolution)
        {
            var tabuList = TabuEdgeCollection.CreateFromTour(betterSolution);
            var currentDistance = nodes.GetDistance(solution);
            var betterDistance = nodes.GetDistance(betterSolution);
            int end = nodes.Length - 1;

            this.currentSolution = solution;
            this.betterSolution = betterSolution;
            this.tabuList = tabuList;

            double overallGain = 0, overallCost = 0;

            TaskLogger.Text = "Running cross 2-opt heuristic on both solutions...";

            for (int i = 0; i < end; i++)
            {
                for (int j = i + 2; j < end; j++)
                {
                    int a = solution[i];
                    int b = solution[i + 1];
                    int c = solution[j];
                    int d = solution[j + 1];

                    bool acTabu = tabuList.IsTabu(a, c);
                    bool bdTabu = tabuList.IsTabu(b, d);

                    // Only one edge can be swapped between solution, otherwise it's a mess
                    if (acTabu && bdTabu)
                        continue;

                    var acDistance = nodes.GetDistance(a, c);
                    var bdDistance = nodes.GetDistance(b, d);
                    var abDistance = nodes.GetDistance(a, b);
                    var cdDistance = nodes.GetDistance(c, d);

                    bool improvable = (acDistance + bdDistance < abDistance + cdDistance);

                    // If the solution cannot be improved, skip this
                    if (!improvable)
                        continue;

                    // If target edge switches are not prohibited, proceed as usual
                    if (!acTabu && !bdTabu)
                    {
                        solution.ReverseSubsequence(i + 1, j);
                    }
                    else
                    {
                        int startNode, middleNode, endNode;
                        double delta = 0;

                        if (acTabu)
                        {
                            startNode = a;
                            endNode = c;
                            middleNode = this.FindTwoEdgesPathMiddleNode(a, c);
                            delta = this.ComputeCostOfTraversing(a, middleNode, c);
                        }
                        else // if (bdTabu)
                        {
                            startNode = b;
                            endNode = d;
                            middleNode = this.FindTwoEdgesPathMiddleNode(b, d);
                            delta = this.ComputeCostOfTraversing(b, middleNode, d);
                        }

                        // Increase in distance of the best solution
                        var cost = delta;
                        // Decerase in distance of the second solution
                        var gain = (abDistance + cdDistance) - (acDistance + bdDistance);

                        if ((gain > 0) && (gain > cost))
                        {
                            var newBetterDistance = betterDistance + cost;
                            var newCurrentDistance = currentDistance - gain;

                            // By performing this move, the solution would be worse, so end here
                            if (newBetterDistance > newCurrentDistance)
                                return;

                            solution.ReverseSubsequence(i + 1, j);

                            int destinationIndex = betterSolution.IndexOf(endNode);
                            betterSolution.MoveBefore(middleNode, destinationIndex);

                            betterDistance = newBetterDistance;
                            currentDistance = newCurrentDistance;

                            overallGain += gain;
                            overallCost += cost;

                            TaskLogger.Text = String.Format("Overall gain: {0:N0}, Overall cost: {1:N0}", overallGain, overallCost);
                        }
                    }
                }

                TaskLogger.Progress = 100.0 * i / end;
            }
        }
Beispiel #5
0
        public void OptimizeDisjoint(IntegerPermutation solution, IntegerPermutation tabuSolution)
        {
            var tabuList = TabuEdgeCollection.CreateFromTour(tabuSolution);

            int jend = nodes.Length - 1;

            TaskLogger.Text = "Running 2-opt heuristic on disjoint solutions...";

            for (int i = 0; i < jend; i++)
            {
                for (int j = i + 2; j < jend; j++)
                {
                    int a = solution[i];
                    int b = solution[i + 1];
                    int c = solution[j];
                    int d = solution[j + 1];

                    if (tabuList.IsTabu(a, c) || tabuList.IsTabu(b, d))
                        continue;

                    /*   before          after
                     * -- a  c --     -- a - c --
                     *     \/
                     *     /\
                     * -- d  b --     -- d - b --
                     */
                    if (nodes.GetDistance(a, c) + nodes.GetDistance(b, d) <
                        nodes.GetDistance(a, b) + nodes.GetDistance(c, d))
                    {
                        solution.ReverseSubsequence(i + 1, j);
                    }
                }

                TaskLogger.Progress = 100.0 * i / jend;
            }
        }
Beispiel #6
0
        public void Optimize(IntegerPermutation solution)
        {
            int jend = nodes.Length - 1;

            TaskLogger.Text = "Running 2-opt heuristic on solution...";

            for (int i = 0; i < jend; i++)
            {
                for (int j = i + 2; j < jend; j++)
                {
                    int a = solution[i];
                    int b = solution[i + 1];
                    int c = solution[j];
                    int d = solution[j + 1];

                    /*   before          after
                     * -- a  c --     -- a - c --
                     *     \/
                     *     /\
                     * -- d  b --     -- d - b --
                     */
                    if (nodes.GetDistance(a, c) + nodes.GetDistance(b, d) <
                        nodes.GetDistance(a, b) + nodes.GetDistance(c, d))
                    {
                        solution.ReverseSubsequence(i + 1, j);
                    }
                }

                TaskLogger.Progress = 100.0 * (double)i / jend;
            }
        }
Beispiel #7
0
 internal Solution(PointArray nodesPosition, IntegerPermutation permutation)
     : base(permutation)
 {
     this.nodePositions = nodesPosition;
 }
Beispiel #8
0
        private void Mutate(IntegerPermutation solution)
        {
            int magnitude = (int)(solution.Length * 0.01 * (0.5 + random.NextDouble()));

            for (int i = 0; i < magnitude; i++)
            {
                int random1 = random.Next(0, solution.Length);
                int random2 = random.NextDifferent(0, solution.Length, random1);

                var temp = solution[random1];
                solution[random1] = solution[random2];
                solution[random2] = temp;
            }
        }
Beispiel #9
0
        private Solution GenerateRandomSolution()
        {
            double discriminator = random.NextDouble();
            IntegerPermutation result;

            if (discriminator > this.NNProbability)
            {
                var availableNumbers = IntegerRandomAccessSet.CreateFullSet(nodePositions.Length);
                int index = 0;

                result = new IntegerPermutation(nodePositions.Length);
                while (availableNumbers.ItemsCount > 0)
                {
                    int randomValue = random.Next(0, availableNumbers.ItemsCount);
                    result[index++] = availableNumbers[randomValue];
                    availableNumbers.RemoveAt(randomValue);
                }
            }
            else
            {
                int random1 = random.Next(0, nodePositions.Length);
                int random2 = random.NextDifferent(0, nodePositions.Length, random1);

                var startEdge = new Edge(random1, random2);
                var nnTourFinder = new NNTourFinder(nodePositions);

                result = new IntegerPermutation(nnTourFinder.FindTourStartingFrom(startEdge));
            }

            return this.CreateSolution(result);
        }
Beispiel #10
0
        private IEnumerable<Solution> Crossover(IntegerPermutation parent1, IntegerPermutation parent2)
        {
            // Uses 0x3 heuristic

            var offspring1 = new IntegerPermutation(parent1.Length);
            var offspring2 = new IntegerPermutation(parent2.Length);

            int subsequenceLength = random.Next(3, Math.Max(3, parent1.Length / 3));

            int start1 = random.Next(0, parent1.Length - subsequenceLength);
            int end1 = start1 + subsequenceLength;
            int start2 = random.Next(0, parent2.Length - subsequenceLength);
            int end2 = start2 + subsequenceLength;

            // Selected segments are copied
            var copiedSubsequence1 = parent1[start1, end1].ToArray();
            var copiedSubsequence2 = parent2[start2, end2].ToArray();
            offspring1[start1, end1] = copiedSubsequence1;
            offspring2[start2, end2] = copiedSubsequence2;

            // Sort elements in array subsequence for binary search
            Array.Sort(copiedSubsequence1);
            Array.Sort(copiedSubsequence2);

            // Copies remaining cities of parent2 in offspring1
            int parentIndex = parent2.GetNextIndex(end2);
            int offspringIndex = offspring1.GetNextIndex(end1);

            while (offspringIndex != start1)
            {
                int current = parent2[parentIndex];

                // If this item already belongs to the offspring, skips it
                if (Array.BinarySearch(copiedSubsequence1, current) >= 0)
                {
                    parentIndex = parent2.GetNextIndex(parentIndex);
                    continue;
                }

                offspring1[offspringIndex] = current;
                offspringIndex = offspring1.GetNextIndex(offspringIndex);
                parentIndex = parent2.GetNextIndex(parentIndex);
            }

            // Copies remaining cities of parent1 in offspring2
            parentIndex = parent1.GetNextIndex(end1);
            offspringIndex = offspring2.GetNextIndex(end2);

            while (offspringIndex != start2)
            {
                int current = parent1[parentIndex];

                // If this item already belongs to the offspring, skips it
                if (Array.BinarySearch(copiedSubsequence2, current) >= 0)
                {
                    parentIndex = parent1.GetNextIndex(parentIndex);
                    continue;
                }

                offspring2[offspringIndex] = current;
                offspringIndex = offspring2.GetNextIndex(offspringIndex);
                parentIndex = parent1.GetNextIndex(parentIndex);
            }

            yield return this.CreateSolution(offspring1);
            yield return this.CreateSolution(offspring2);
        }
Beispiel #11
0
 private Solution CreateSolution(IntegerPermutation permutation)
 {
     return new Solution(nodePositions, permutation);
 }
Beispiel #12
0
        static void InitializeBestTour()
        {
            TaskLogger.TaskName = "Initializing first tour";
            if (TourExists(BestTourFileName))
            {
                bestTour = LoadTour(BestTourFileName);
            }
            else
            {
                Edge shortestEdge;

                if (TourExists(OneEdgeTourFileName))
                {
                    shortestEdge = LoadOneEdgeTour();
                }
                else
                {
                    var shortestEdgeFinder = new ShortestEdgeFinder(InitializationThreadCount);
                    shortestEdge = shortestEdgeFinder.FindInCompleteGraph(cities);
                    SaveOneEdgeTour(shortestEdge);
                }

                var nnTourFinder = new NNTourFinder(cities);
                bestTour = new IntegerPermutation(nnTourFinder.FindTourStartingFrom(shortestEdge));
                SaveTour(bestTour, BestTourFileName);
            }

            bestTourDistance = cities.GetDistance(bestTour);
        }
Beispiel #13
0
        static void Main(string[] args)
        {
            TaskLogger.Start();

            ParseData();

            InitializeClusterSet();
            InitializeBestTour();
            InitializeSecondBestTour();

            UpdateLoggerFooter();

            CrossOptimize();

            Console.WriteLine("Genetic?");
            Console.ReadKey();

            var optimizer = new TwoOptimizer(cities);
            var geneticEngine = new GeneticTspEngine(cities);
            var nnTourFinder = new NNTourFinder(cities);

            while (secondBestTourDistance > TargetDistance)
            {
                TaskLogger.TaskName = "Genetic algorithm on first tour";

                geneticEngine.StartFromKnownSolutions(bestTour);
                while (geneticEngine.CurrentGeneration < 1000)
                {
                    geneticEngine.NextGeneration();

                    var currentSolution = geneticEngine.CurrentBestSolution;
                    if (currentSolution.Distance < bestTourDistance)
                    {
                        bestTour = currentSolution;
                        bestTourDistance = currentSolution.Distance;
                        SaveTour(bestTour, BestTourFileName);
                        UpdateLoggerFooter();
                    }
                }

                TaskLogger.TaskName = "Optimizationg of first tour";
                TaskLogger.ShowProgress();
                var gain = 0.0;
                do
                {
                    var oldDistance = bestTourDistance;

                    optimizer.Optimize(bestTour);
                    bestTourDistance = cities.GetDistance(bestTour);
                    UpdateLoggerFooter();

                    gain = oldDistance - bestTourDistance;

                    if (gain > 0)
                        SaveTour(bestTour, BestTourFileName);
                } while (gain > 1000.0);

                TaskLogger.TaskName = "Genetic algorithm on second disjoint tour";
                geneticEngine.Reset();
                geneticEngine.StartFromKnownSolutions(
                    secondBestTour,
                    new IntegerPermutation(nnTourFinder.FindRandomDisjointTour(bestTour)));

                while (geneticEngine.CurrentGeneration < 1000)
                {
                    geneticEngine.NextGeneration();

                    foreach (var currentSolution in geneticEngine.CurrentSolutionPool)
                    {
                        if (currentSolution.Distance > secondBestTourDistance)
                            break;

                        if (!CheckDisjointness(bestTour, secondBestTour))
                            continue;

                        if (currentSolution.Distance < secondBestTourDistance)
                        {
                            secondBestTour = currentSolution;
                            secondBestTourDistance = currentSolution.Distance;
                            SaveTour(secondBestTour, SecondBestTourFileName);
                            UpdateLoggerFooter();
                        }
                    }
                }

                TaskLogger.TaskName = "Optimization of second disjoint tour";
                TaskLogger.ShowProgress();
                do
                {
                    var oldDistance = secondBestTourDistance;

                    optimizer.OptimizeDisjoint(secondBestTour, bestTour);
                    secondBestTourDistance = cities.GetDistance(secondBestTour);
                    UpdateLoggerFooter();

                    gain = oldDistance - secondBestTourDistance;

                    if (gain > 0)
                        SaveTour(secondBestTour, SecondBestTourFileName);
                } while (gain > 1000.0);
            }

            TaskLogger.Stop();
        }
Beispiel #14
0
        static void InitializeSecondBestTour()
        {
            TaskLogger.TaskName = "Initializing second disjoint tour";
            if (TourExists(SecondBestTourFileName))
            {
                secondBestTour = LoadTour(SecondBestTourFileName);
            }
            else
            {
                var nnTourFinder = new NNTourFinder(cities);
                secondBestTour = new IntegerPermutation(nnTourFinder.FindRandomDisjointTour(bestTour));
                SaveTour(secondBestTour, SecondBestTourFileName);
            }

            secondBestTourDistance = cities.GetDistance(secondBestTour);
        }