Not really any significant improvements.
This commit is contained in:
98
tsp/tsp.py
98
tsp/tsp.py
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user