From: Skullheadx <704277@pdsb.net> Date: Thu, 29 Dec 2022 16:24:59 +0000 (-0500) Subject: christofides start X-Git-Url: http://git.skullheadx.com/nixos/static/simulation.png?a=commitdiff_plain;h=f6fc81d914c86a4cd97b0f618747f0306f7db099;p=The-Traveling-Salesman-Problem.git christofides start --- diff --git a/Christofides.py b/Christofides.py new file mode 100644 index 0000000..352b1b9 --- /dev/null +++ b/Christofides.py @@ -0,0 +1,74 @@ +from graph import distance, find_MST, calculate_route, linker +from queue import Queue + + +def christofides(graph: list): + route = [] + _, mst = find_MST(graph) + g = {town: [] for town in graph} + for i in mst: + start, end = i + g[start].append(end) + g[end].append(start) + + odd_degree_vertices = [] + + for town in g: + degree = len(g[town]) + if degree % 2 == 1: + odd_degree_vertices.append(town) + + def is_seen(points, value): + for i in points: + s, e = i + if value == s or value == e: + return True + return False + + perfect_matching = [] + q = Queue() + q.put([]) + + min_weight = None + while not q.empty(): + current = q.get() + if len(current) == len(odd_degree_vertices) / 2: + d = calculate_route(current, "points") + if min_weight is None or d < min_weight: + min_weight = d + perfect_matching = current + + for i in odd_degree_vertices: + if not is_seen(current, i): + for j in odd_degree_vertices: + if j != i and not is_seen(current,j): + c = current[:] + c.append((i, j)) + q.put(c) + + + multigraph = mst + perfect_matching + print(f"{odd_degree_vertices=}") + + print(f"{mst=}") + print() + print(f"{perfect_matching=}") + print() + print(f"{multigraph=}") + + eulerian_tour = linker(multigraph) + + print(eulerian_tour) + + print(g) + return mst + +""" + + +((396, 559), (300, 438)), 1 +((300, 438), (141, 520)), 2 +((300, 438), (490, 227)), +((300, 438), (24, 97)), +((396, 559), (141, 520)), 3 +((24, 97), (490, 227))""" diff --git a/display.py b/display.py index 80aefc7..8f26b13 100644 --- a/display.py +++ b/display.py @@ -21,11 +21,13 @@ class Node: radius = 6 thickness = 1 - # font = pygame.font.SysFont("arial", 20) + font = pygame.font.SysFont("arial", 20) def __init__(self, position: tuple, number: int) -> None: self.position = pygame.Vector2(position) # self.text = self.font.render(str(number), True, self.text_colour) + self.coord_text = self.font.render(str((self.position)), True, (0, 0, 0)) + def draw(self, surf: pygame.Surface) -> None: pygame.draw.circle(surf, self.background_colour, self.position, self.radius) @@ -33,6 +35,9 @@ class Node: # surf.blit(self.text, self.text.get_rect(center=self.position)) + surf.blit(self.coord_text, self.coord_text.get_rect(center=self.position)) + + class Salesman: background_colour = ORANGE outline_colour = BLACK @@ -90,14 +95,14 @@ class Display: if mode == "points": self.route = linker(self.route) - self.salesman = Salesman(self.route) + # self.salesman = Salesman(self.route) self.mst = mst self.one_tree = one_tree self.removed_vertex = removed_vertex - def update(self, delta: float) -> None: - self.salesman.update(delta) + # def update(self, delta: float) -> None: + # self.salesman.update(delta) def show(self) -> None: is_running = True @@ -109,7 +114,7 @@ class Display: if event.type == pygame.QUIT: is_running = False - self.salesman.update(delta) + # self.salesman.update(delta) self.screen.fill(WHITE) if self.one_tree is not None: @@ -129,9 +134,8 @@ class Display: for i, node in enumerate(self.nodes): node.draw(self.screen) - # text = self.font.render(str((node.position)), True, (0, 0, 0)) - # self.screen.blit(text, text.get_rect(center=node.position)) - self.salesman.draw(self.screen) + + # self.salesman.draw(self.screen) pygame.display.update() delta = clock.tick(60) / 1000 # Seconds diff --git a/graph.py b/graph.py index 141fb64..3648c9b 100644 --- a/graph.py +++ b/graph.py @@ -70,7 +70,6 @@ def calculate_route(route: list, mode="direct") -> float: d = 0.0 for i in route: start, end = i - d += distance(start, end) return d @@ -204,8 +203,14 @@ def linker(points): while True: start, end = current direct.append(end) - - a, b = graph[end] + if len(graph[end]) > 2: + a = start + for i in graph[end]: + if i != a: + b = i + break + else: + a, b = graph[end] if a == start: current = (end, b) else: diff --git a/main.py b/main.py index 14e8b55..c2eb294 100644 --- a/main.py +++ b/main.py @@ -3,11 +3,12 @@ from display import Display from brute_force import brute_force from nearest_neighbor import nearest_neighbor from greedy import greedy +from Christofides import christofides from time import perf_counter import os GRAPH_PATH = "graphs/" -CREATE_NEW_GRAPHS = True +CREATE_NEW_GRAPHS = False def main(): @@ -22,7 +23,7 @@ def main(): print("The file does not exist") if CREATE_NEW_GRAPHS: - graph, filename = create(GRAPH_PATH, 640, 640, 100) + graph, filename = create(GRAPH_PATH, 640, 640, 5) else: filename = "graph1.txt" graph = read(GRAPH_PATH, filename) @@ -30,22 +31,24 @@ def main(): route_time_start = perf_counter() # route = brute_force(graph) # 10 nodes in 85.042 seconds. Optimal = 2,262.29 # route = nearest_neighbor(graph) # 100 nodes in 0.5762094999663532 seconds. Distance = 6,270.568142156188 - route = greedy(graph) # 100 nodes in 0.1383088999427855 seconds. Distance = 5,523.211501332208 OTLB: 4, + # route = greedy(graph) # 100 nodes in 0.1383088999427855 seconds. Distance = 5,523.211501332208 OTLB: 4, # 344.881943246125 Approx. 27.119944188995277% + route = christofides(graph) route_time_end = perf_counter() - # MST_distance, MST = find_MST(graph) - # print("MST_DISTANCE:", MST_distance) + MST_distance, MST = find_MST(graph) + print("MST_DISTANCE:", MST_distance) one_tree_time_start = perf_counter() - # one_tree_distance, one_tree = find_one_tree(graph) - lower_bound, one_tree, removed_vertex = find_lower_bound(graph) + lower_bound,one_tree = find_one_tree(graph) + removed_vertex = graph[0] + # lower_bound, one_tree, removed_vertex = find_lower_bound(graph) one_tree_time_end = perf_counter() - print_info(route, route_time_end - route_time_start, "Greedy Heuristic", lower_bound, + print_info(route, route_time_end - route_time_start, "Christofides Algorithm", lower_bound, one_tree_time_end - one_tree_time_start, r=3000, mode="points") - display = Display(os.path.join(GRAPH_PATH, filename), route, mst=None, one_tree=one_tree, - removed_vertex=removed_vertex, mode="points") + display = Display(os.path.join(GRAPH_PATH, filename), [], mst=MST, one_tree=route, + removed_vertex=removed_vertex, mode="direct") display.show()