Not really any significant improvements.

This commit is contained in:
2020-01-16 16:34:27 -05:00
parent 955f1def0b
commit d543cd5d80

View File

@@ -5,7 +5,7 @@ from random import shuffle, choice
from map import Map from map import Map
@lru_cache(maxsize=1000000) @lru_cache(maxsize=10000000000)
def distance(p1, p2): def distance(p1, p2):
""" Returns the distance between two points. """ """ Returns the distance between two points. """
return math.sqrt((p1.x - p2.x)**2 + (p1.y - p2.y)**2) return math.sqrt((p1.x - p2.x)**2 + (p1.y - p2.y)**2)
@@ -62,7 +62,7 @@ class Point(object):
def __str__(self): def __str__(self):
# m = "P_{}({}, {})".format(self.index, self.x, self.y) # m = "P_{}({}, {})".format(self.index, self.x, self.y)
# m = "P_{}({}, {})".format(self.index, self.cluster_x, self.cluster_y) # m = "P_{}({}, {})".format(self.index, self.cluster_x, self.cluster_y)
m = "P(id={}, index={})".format(self.id, self.index) m = "{}".format(self.index)
return m return m
def __repr__(self): def __repr__(self):
@@ -120,44 +120,45 @@ def swap_edges(i, j, points, current_distance=0):
def k_opt(p1, route): def k_opt(p1, route):
steps = [] steps = []
ignore_set = set() ignore_set = set()
for _ in range(10): for _ in range(10):
p2 = route.points[(p1.index + 1) % route.len_points] p2 = route.points[(p1.index + 1) % route.len_points]
dist_p1p2 = distance(p1, p2) dist_p1p2 = distance(p1, p2)
ignore_set.add(p2) ignore_set.add(p2)
p4 = None
for p3, dist_p2p3 in p2.neighbors: for p3, dist_p2p3 in p2.neighbors:
if p3 is p2 or p3 is p1 or p3 in ignore_set: if p3 is p1 or p3 in ignore_set:
continue continue
p4_ = route.points[(p3.index - 1) % route.len_points] p4 = route.points[(p3.index - 1) % route.len_points]
if p4_ in ignore_set or p4_ is p1: if p4 in ignore_set or p4 is p1:
continue continue
# dist_p2p3 = distance(p2, p3)
if dist_p2p3 < dist_p1p2: if dist_p2p3 < dist_p1p2:
dist_p1p2 = dist_p2p3 break
p4 = p4_ p4 = None
if p4 is None: if p4 is None:
break break
step = (p1.index, p4.index) step = (p1.index, p4.index)
new_total = route.swap(p1, p4) new_total = route.swap(p1, p4)
steps.append((new_total, step)) steps.append((new_total, step))
return steps return steps
def local_search_k_opt(route, goal): def local_search_k_opt(route, goal):
current_total = route.total_distance current_total = route.total_distance
longest_segment = 0
no_improvement_iterations = 0 no_improvement_iterations = 0
while no_improvement_iterations < 8: while True:
print("{} {}".format(no_improvement_iterations, current_total)) # print("{} {}".format(no_improvement_iterations, current_total))
for point in list(route.points): for point in list(route.points):
before_k_opt = current_total before_k_opt = route.total_distance
point_2 = route.points[(point.index + 1) % route.len_points]
len_segment = distance(point, point_2)
if len_segment > longest_segment:
longest_segment = len_segment
longest_point = point
steps = k_opt(point, route) steps = k_opt(point, route)
if not steps: if not steps:
@@ -180,10 +181,12 @@ def local_search_k_opt(route, goal):
break break
assert(float_is_equal(route.total_distance, current_total)) assert(float_is_equal(route.total_distance, current_total))
no_improvement_iterations = 0 no_improvement_iterations = 0
factor = 1
no_improvement_iterations += 1 no_improvement_iterations += 1
if no_improvement_iterations > 3: if no_improvement_iterations > 3:
current_total = route.swap(choice(route.points), choice(route.points)) current_total = route.swap(longest_point, choice(route.points))
longest_segment = 0
if current_total < goal: if current_total < goal:
return return
@@ -263,39 +266,29 @@ class Route(object):
return self.total_distance return self.total_distance
def reorder_points_greedy(self): def reorder_points_greedy(self):
best_distance = float("inf")
best_solution = None
points = self.points
for i in range(1000): points = list(self.points)
shuffle(points) shuffle(points)
current_point, points = points[0], points[1:] current_point, points = points[0], points[1:]
solution = [current_point] self.points = [current_point]
while points: while points:
next_point = None next_point = None
# Select the closest point as the following one. # Select the closest point as the following one.
for neighbor, _ in current_point.neighbors: for neighbor, _ in current_point.neighbors:
if neighbor in points: if neighbor in points:
next_point = neighbor next_point = neighbor
points.remove(next_point) points.remove(next_point)
break break
# If none of the neighbors could be selected use any point. # If none of the neighbors could be selected use any point.
if next_point is None: if next_point is None:
next_point = points.pop() next_point = points.pop()
solution.append(next_point) self.points.append(next_point)
current_point = next_point current_point = next_point
total_distance = self.get_total_distance(solution) self.total_distance = self.get_total_distance(self.points)
points = solution
if total_distance < best_distance:
best_distance = total_distance
best_solution = solution.copy()
self.points = best_solution
self.total_distance = best_distance
for i, p in enumerate(self.points): for i, p in enumerate(self.points):
p.index = i p.index = i
return self.points return self.points
@@ -304,14 +297,16 @@ class Route(object):
def solve_it(input_data): def solve_it(input_data):
r = Route(parse_input_data(input_data)) r = Route(parse_input_data(input_data))
m = Map() m = Map()
m.cluster(r.points)
goal = {51: 429, goal = {51: 429,
100: 20800, 100: 20800,
200: 30000, 200: 30000,
574: 39000}[r.len_points] 574: 37600}[r.len_points]
m.cluster(r.points) # r.reorder_points_greedy()
local_search_k_opt(r, goal) local_search_k_opt(r, goal)
m.plot(r.points) # m.plot(r.points)
r.verify_total_distance() r.verify_total_distance()
return prepare_output_data(r.points) return prepare_output_data(r.points)
@@ -319,9 +314,10 @@ def solve_it(input_data):
if __name__ == "__main__": if __name__ == "__main__":
file_location = "data/tsp_51_1" file_location = "data/tsp_51_1"
file_location = "data/tsp_100_3" # file_location = "data/tsp_100_3"
file_location = "data/tsp_200_2" # file_location = "data/tsp_200_2"
# file_location = "data/tsp_574_1" file_location = "data/tsp_574_1"
# file_location = "data/tsp_1880_1"
# file_location = "data/tsp_6_1" # file_location = "data/tsp_6_1"
with open(file_location, 'r') as input_data_file: with open(file_location, 'r') as input_data_file:
input_data = input_data_file.read() input_data = input_data_file.read()