--- /dev/null
+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))"""
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)
# 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
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
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:
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
d = 0.0
for i in route:
start, end = i
-
d += distance(start, end)
return d
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:
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():
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)
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()