Advertisement
Guest User

Untitled

a guest
Jul 19th, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.45 KB | None | 0 0
  1. import csv
  2. import itertools
  3. import math
  4. import random
  5. import sys
  6.  
  7. """
  8. Takes a csv file of x,y coords e.g
  9. 20.8,21.3
  10. 29.1,26.2
  11. 30.6,33.7
  12. 31.5,11.8
  13. 9.3,15.0
  14. 16.3,18.7
  15. 20.5,8.9
  16. 15.8,22.3
  17. 30.0,19.3
  18. 35.1,27.0
  19. """
  20.  
  21.  
  22. def held_karp(dists):
  23. """
  24. Implementation of Held-Karp, an algorithm that solves the Traveling
  25. Salesman Problem using dynamic programming with memoization.
  26.  
  27. Parameters:
  28. dists: distance matrix
  29.  
  30. Returns:
  31. A tuple, (cost, path).
  32. """
  33. n = len(dists)
  34.  
  35. # Maps each subset of the nodes to the cost to reach that subset, as well
  36. # as what node it passed before reaching this subset.
  37. # Node subsets are represented as set bits.
  38. C = {}
  39.  
  40. # Set transition cost from initial state
  41. for k in range(1, n):
  42. C[(1 << k, k)] = (dists[0][k], 0)
  43.  
  44. # Iterate subsets of increasing length and store intermediate results
  45. # in classic dynamic programming manner
  46. for subset_size in range(2, n):
  47. for subset in itertools.combinations(range(1, n), subset_size):
  48. # Set bits for all nodes in this subset
  49. bits = 0
  50. for bit in subset:
  51. bits |= 1 << bit
  52.  
  53. # Find the lowest cost to get to this subset
  54. for k in subset:
  55. prev = bits & ~(1 << k)
  56.  
  57. res = []
  58. for m in subset:
  59. if m == 0 or m == k:
  60. continue
  61. res.append((C[(prev, m)][0] + dists[m][k], m))
  62. C[(bits, k)] = min(res)
  63.  
  64. # We're interested in all bits but the least significant (the start state)
  65. bits = (2**n - 1) - 1
  66.  
  67. # Calculate optimal cost
  68. res = []
  69. for k in range(1, n):
  70. res.append((C[(bits, k)][0] + dists[k][0], k))
  71. opt, parent = min(res)
  72.  
  73. # Backtrack to find full path
  74. path = []
  75. for _ in range(n - 1):
  76. path.append(parent)
  77. new_bits = bits & ~(1 << parent)
  78. _, parent = C[(bits, parent)]
  79. bits = new_bits
  80.  
  81. # Add implicit start state
  82. path.append(0)
  83.  
  84. return opt, list(reversed(path))
  85.  
  86.  
  87. def read_coords(filename):
  88. with open(filename) as file:
  89. dialect = csv.Sniffer().sniff(file.read(1024))
  90. csv_file = csv.reader(file, dialect, quotechar='"')
  91. coords = []
  92.  
  93. file.seek(0)
  94.  
  95. for row in csv_file:
  96. if len(row) != 2:
  97. sys.exit('invalid csv, expected list of x,y coords')
  98. coords.append([float(i) for i in row])
  99. return coords
  100.  
  101.  
  102. def compare_coords(a, b):
  103. x_dist = math.fabs(a[0] - b[0])
  104. y_dist = math.fabs(a[1] - b[1])
  105. return math.sqrt(x_dist**2 + y_dist**2)
  106.  
  107.  
  108. def get_distances(coords):
  109. dists = []
  110. n = len(coords)
  111. for i in range(0, n):
  112. new_list = []
  113. for j in range(0, n):
  114. new_list.append(compare_coords(coords[i], coords[j]))
  115. dists.append(new_list)
  116. return dists
  117.  
  118.  
  119. if __name__ == '__main__':
  120. arg = ""
  121. if len(sys.argv) > 1:
  122. arg = sys.argv[1]
  123.  
  124. if arg.endswith('.csv'):
  125. coords = read_coords(arg)
  126. dists = get_distances(coords)
  127. else:
  128. sys.exit('No coords csv provided')
  129.  
  130. # Pretty-print the distance matrix
  131. # for row in dists:
  132. # print(''.join([str(n).rjust(3, ' ') for n in row]))
  133.  
  134. print('')
  135. # print(held_karp(dists))
  136. [opt, path] = held_karp(dists)
  137. print('order', [i + 1 for i in path])
  138. coord_order = []
  139. for i in path:
  140. coord_order.append(coords[i])
  141. for row in coord_order:
  142. print(row)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement