Saturday, March 11, 2017

Node Shift

Node Shift move

Node Shift is a simple tour optimization heuristics: it consists in shifting a city to other position in tour.

The idea:

A
A

Diagrams:

X0 X0_pred X0_succ Y1 Y2
X0 X0_pred X0_succ Y1 Y2

Node Shift move is obtained by removing three links and adding three new links, and therefore it is a special case of 3-opt move:

Gain from Node Shift move

proc Gain_From_Node_Shift(X0_pred, X0, X0_succ,
                          Y1, Y2: City_Number): Length_Gain =
  ## Gain of tour length which can be obtained by performing Node Shift
  # City X0 would be moved from its current position, between X0_pred
  # and X0_succ, to position between cities Y1 and Y2.
  # Assumes: X0_pred!=Y1 (the same as: X0!=Y2);
  #   X0==successor(X0_pred); X0_succ==successor(X0); Y2==successor(Y1)
  let del_Length = distance(X0_pred, X0) + distance(X0, X0_succ) +
                   distance(Y1, Y2)
  let add_Length = distance(X0_pred, X0_succ) +
                   distance(Y1, X0) + distance(X0, Y2)
  result = del_Length - add_Length

Node Shift move implementation

proc Make_Node_Shift_Move(tour: var Tour_Array;
                          i, j: Tour_Index) =
  ## Performs given Node Shift move
  # Shifts the city t[i] from its current position to position
  # after current city t[j], i.e. between cities t[j] and t[j+1].
  # This is a special, simple case of segment shift, thus a special
  # case of 3-opt move.
  var
    left, right: Tour_Index
    X0: City_Number

  let shiftSize = (j - i + 1 + N) mod N

  X0 = tour[i]
  left = i
  for counter in 1 .. shiftSize:
    right = (left + 1) mod N
    tour[left] = tour[right]
    left = right
  # end_for counter loop
  tour[j] = X0

Iterative Node Shift optimization

proc LS_Node_Shift(tour: var Tour_Array) =
  ## Iteratively optimizes given tour using Node_Shift moves.
  # Shortens tour by repeating Node Shift moves until no improvement
  # can by done: in every iteration immediatelly makes permanent
  # the first move found that gives any length gain.
  var
    locallyOptimal: bool = false
    i, j: Tour_Index
    X0_pred, X0, X0_succ, Y1, Y2: City_Number

  while not locallyOptimal:
    locallyOptimal = true

    for counter_1 in 0 .. N-1:
      i = counter_1  # current position of city to shift
      X0_pred = tour[(i + N - 1) mod N]
      X0      = tour[i]
      X0_succ = tour[(i + 1) mod N]

      for counter_2 in 1 .. N-2:
        j  = (i + counter_2) mod N  # new position of the city
        Y1 = tour[j]
        Y2 = tour[(j + 1) mod N]

        if Gain_From_Node_Shift(X0_pred, X0, X0_succ, Y1, Y2) > 0:
          Make_Node_Shift_Move(tour, i, j)
          locallyOptimal = false
          break

Some simple statistics

Relative time, best length, average length and worst length for all tours created by NN heuristic and improved by 2-opt and 2-opt plus Node Shift algorithms. Random planar problems, N=100.
Problem # Method Time Best Avg Worst
1NN100100.00106.01114.87
NN + 2opt125384.3889.8396.82
NN + 2opt + NodeShift145983.9487.9091.71
2NN100100.00107.45116.93
NN + 2opt156288.0592.4096.60
NN + 2opt + NodeShift156287.1690.3494.04
3NN100100.00111.21121.46
NN + 2opt156687.4191.5295.76
NN + 2opt + NodeShift166684.9988.7992.92
4NN100100.00106.14116.83
NN + 2opt114690.5293.4296.88
NN + 2opt + NodeShift135390.1891.9095.45
5NN100100.00106.30111.75
NN + 2opt83389.6393.3598.55
NN + 2opt + NodeShift125388.5891.6895.80
6NN100100.00112.73120.18
NN + 2opt125389.4693.6098.49
NN + 2opt + NodeShift145988.2792.0096.30
7NN100100.00109.50124.34
NN + 2opt146088.6691.0596.24
NN + 2opt + NodeShift156686.4789.2792.40
8NN100100.00108.63117.53
NN + 2opt114692.4796.80102.24
NN + 2opt + NodeShift156691.8695.44101.14
9NN100100.00105.75112.56
NN + 2opt40088.7091.6896.63
NN + 2opt + NodeShift46587.8590.0394.57
10NN100100.00115.43123.97
NN + 2opt146091.7795.11100.35
NN + 2opt + NodeShift145990.8893.8798.72

No comments:

Post a Comment