Monday, March 27, 2017

Position of given city in tour

Using neighbor lists forces us to use some convenient and quick method to determine for given city (a neighbor) what is its position in current tour. We use an array indexed by city numbers and storing corresponding positions.

type
  City_Position_In_Tour = array[City_Number, Tour_Index]
proc Create_Position_In_Tour(tour: Tour_Array): City_Position_In_Tour =
  ## Creates array with position of each city in tour
  var
    position: City_Position_In_Tour

  for pos in 0 .. N-1:
    position[tour[pos]] = pos
  result = position

Note that array of positions should be updated during any action that changes the tour, be it reversing a segment:

proc Reverse_Segment(tour: var Tour_Array;
                     startIndex, endIndex: Tour_Index;
                     position: var City_Position_In_Tour) =
  ## Reverses order of elements in segment [startIndex, endIndex]
  ## of tour, and updates positon[] array used with neighbour lists
  var
    left, right: Tour_Index

  let inversionSize = ((endIndex - startIndex + 1 + N) mod N) div 2
 
  left  = startIndex
  right = endIndex

  for counter in 1 .. inversionSize:
    swap(tour[left], tour[right])

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

    left  = (left + 1) mod N
    right = (N + right - 1) mod N

...or shifting a segment:

proc Shift_Segment(tour: var Tour_Array; i, j, k: Tour_Index;
                   position: var City_Position_In_Tour) =
  ## Shifts the segment of tour:
  ## cities from t[i+1] to t[j] from their current position to position
  ## after current city t[k], that is between cities t[k] and t[k+1].
  ## Accordingly updates positon[] array.
  # Assumes:  k, k+1 are not within the segment [i+1..j]
  let
    segmentSize = (j - i + N) mod N
    shiftSize = ((k - i + N)  - segmentSize + N) mod N
    offset = i + 1 + shiftSize
  var
    pos, posNew: Tour_Index
    segment: seq[City_Number] = newSeq[City_Number](segmentSize)

  # make a copy of the segment before shift
  for pos in 0 .. segmentSize-1:
    segment[pos] = tour[(pos + i+1) mod N]

  # shift to the left by segmentSize all cities between old position
  # of right end of the segment and new position of its left end
  pos  = (i + 1) mod N
  for counter in 1 .. shiftSize:
    tour[pos] = tour[(pos + segmentSize) mod N]
    position[tour[pos]]  = pos
    pos  = (pos + 1) mod N
  #end_for counter loop

  # put the copy of the segment into its new place in the tour
  for pos in 0 .. segmentSize-1:
    posNew = (pos + offset) mod N 
    tour[posNew] = segment[pos]    
    position[tour[posNew]] = posNew

No comments:

Post a Comment