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 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; } }