]> Skullheadx's Git Forge - The-Traveling-Salesman-Problem.git/commitdiff
christofides start
authorSkullheadx <704277@pdsb.net>
Thu, 29 Dec 2022 16:24:59 +0000 (11:24 -0500)
committerSkullheadx <704277@pdsb.net>
Thu, 29 Dec 2022 16:24:59 +0000 (11:24 -0500)
Christofides.py [new file with mode: 0644]
display.py
graph.py
main.py

diff --git a/Christofides.py b/Christofides.py
new file mode 100644 (file)
index 0000000..352b1b9
--- /dev/null
@@ -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))"""
index 80aefc71a483d6fc027b34b8c4e30627319acc7d..8f26b13688b6fd3d60d82eba76f336e830acc664 100644 (file)
@@ -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
index 141fb6457aa51082d7cd7ab59a3135ecde5fa7ea..3648c9b10f37b01e70bfe17a78159b83b347e0bd 100644 (file)
--- 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 14e8b55d8dedee92bc92b8ef8d125193562a9458..c2eb29426d559f6becd270b9d9a0bc2eff8b03c9 100644 (file)
--- 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()