Monday, May 8, 2017

2-opt move speedup

If segment reversing is used as an independent 2-opt move, not as a part of sequence (e.g. to apply 3-opt move), then we can take advantage of the fact that the tour is cyclic. Therefore reversing a segment has the same effect as reversing its complementary segment and changing "natural orientation" of the tour array.

p1 p2 p3 p4
p1 p2 p3 p4

Using array representation of tour causes that reversing a segment is done by swapping elements of array. The number of swaps (thus the amount of time) needed to reverse a segment is proportional to the number of cities the segment consists of. So when the segment to reverse is longer than half of tour, then can we reverse the complementary segment to speed-up the transformation.

proc t_pred(pos: Tour_Index): Tour_Index {.inline.} =
  ## returns position of tour predecessor for given position 
  result = (N + pos - 1) mod N

proc t_succ(pos: Tour_Index): Tour_Index {.inline.} =
  ## returns position of tour successor for given position 
  result = (pos + 1) mod N
proc Make_2_Opt_Move_Fast(tour: var Tour_Array;
                          p1, p2, p3, p4: Tour_Index;
                          position: var City_Position_In_Tour) =
  ## Reverses order of elements in segment [p2, p3] of tour:
  ## if the complementary segment is shorter, reverses the complementary
  # Assumes: p1==t_pred(p2), p4==t_succ(p3)
  var
    city: City_Number
    left, right: Tour_Index
    inversionSize: int

  inversionSize = (p3 - p2 + 1)
  if inversionSize < 0:
    inversionSize = inversionSize + N

  if (2 * inversionSize > N):  # segment longer than half of tour
    left  = p4  # t_succ(p3)
    right = p1  # t_pred(p2)
    inversionSize = N - inversionSize
  else:
    left  = p2
    right = p3

  inversionSize = inversionSize div 2

  for counter in 1 .. inversionSize:
    city        = tour[right]
    tour[right] = tour[left]
    tour[left]  = city

    position[tour[left]]  = left
    position[tour[right]] = right

    left  = t_succ(left)
    right = t_pred(right)
  #end_for counter loop

2 comments:

  1. Hi,
    Great blog! I think this is only works if you are dealing with symmetric TSP and won't work in asymmetric case.

    ReplyDelete
  2. The title of this blog says:
    "Basics of Local Optimization in the Symmetric Traveling Salesman Problem (STSP)"

    ReplyDelete