1

I'm trying to implement 2-opt optimization for finding "good enough" solutions to the TSP, with no edge crossings. I was under the impression running 2-opt until no more improvements can be made, will result in a tour with no crossings. However the below code isn't removing all crossed edges for some reason. In some runs with 1000's of cities there remain several crossings.

Code notes: _solution is a List. Rather than creating a new tour and calculating the entire distance the code computes the difference between the two edges removed and the two edges created for speed. Also I duplicate the first point and add to the end of the list for making calculations simpler. Hence the i & j ranges.

Can anyone see why this isn't working?

        while (!done)
        {
            bool improved = false;

            for (int i = 1; i < _solution.Count - 2; i++)
            {
                OptimizeSteps++;

                for (int j = i + 1; j < _solution.Count - 1; j++)
                {
                    // calculate new tour distance 
                    double newDist = TourLength - CalcPointDistanceL2(_solution[i-1], _solution[i]);
                    newDist -= CalcPointDistanceL2(_solution[j], _solution[j + 1]);
                    newDist += CalcPointDistanceL2(_solution[i-1], _solution[j]);
                    newDist += CalcPointDistanceL2(_solution[i], _solution[j + 1]);

                    // if shorter make the improved tour
                    if (newDist < TourLength)
                    {
                        // reverse subtour
                        TSPPoint[] reversedSubTour = new TSPPoint[j-i+1];
                        _solution.CopyTo( i, reversedSubTour, 0, reversedSubTour.Length );
                        Array.Reverse( reversedSubTour );

                        for ( int n = 0; n < reversedSubTour.Length; n++ )
                        {
                            _solution[n + i] = reversedSubTour[n];
                        }
                        TourLength = newDist;

                        // debug
                        double d = GetTotalDistance(_solution);

                        improved = true;
                    }

                    if ( improved ) break;
                }

                DoNotify(500);

                if ( improved ) break;
            }
            if (!improved) done = true;
        }

2 Answers2

0

You are right that the tour should not cross itself after completing the 2-opt process (i.e., after performing all 2-opts that lead to a shorter tour).

Your current code ignores moves where "j+1" = the start node. Your for j loop should go one iteration further:

for (int j = i + 1; j < _solution.Count; j++)

If j == _solution.Count-1, then instead of using _solution[j + 1] as your j+1 node you should use _solution[0].

LarrySnyder610
  • 2,277
  • 12
  • 24
  • Are you sure? As stated above the last TSPPoint in _solution is a copy of _solution[0]. That's why I don't iterate over it. It's just there to make calculating j+1 easier than wrapping around to the beginning. – user3572255 Feb 22 '15 at 05:59
  • Oh -- I think you are right -- your duplicate node at the end takes care of the problem I was suggesting. How about this then: Does your code for making the improved tour correctly handle the duplicate node at the end? If the duplicate node is an endpoint of one of the edges that is being swapped, I don't think you correctly adjust the start node -- and the same thing if node 0 is an endpoint of a swap edge. – LarrySnyder610 Feb 22 '15 at 16:12
  • I think you're describing what I discovered by doing some tests on paper. My method of calculating distance is flawed around the end-start link. I found a cleaner way of implementing it. Shame I can't select your comment as answer. – user3572255 Feb 25 '15 at 07:24
  • Added my comment as an answer. – LarrySnyder610 Feb 26 '15 at 02:23
0

Does your code for making the improved tour correctly handle the duplicate node at the end? If the duplicate node is an endpoint of one of the edges that is being swapped, I don't think you correctly adjust the start node -- and the same thing if node 0 is an endpoint of a swap edge.

LarrySnyder610
  • 2,277
  • 12
  • 24