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; } }
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; }
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; }
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; } }
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; } }
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; } }
internal Solution(PointArray nodesPosition, IntegerPermutation permutation) : base(permutation) { this.nodePositions = nodesPosition; }
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; } }
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); }
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); }
private Solution CreateSolution(IntegerPermutation permutation) { return new Solution(nodePositions, permutation); }
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); }
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(); }
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); }