From abb169a2f36d1a4e5dde099d689a20a3b9ef77f1 Mon Sep 17 00:00:00 2001 From: Bartosz Date: Sat, 15 Jan 2022 18:07:49 +0100 Subject: [PATCH] Made some changes to bidirectional. Among them added handling of directed graphs. Added some descriptive comments to dijkstra. --- algorithms/bidirectional.py | 98 ++++++++++++++++++++++++++----------- algorithms/dijkstra.py | 14 +++++- 2 files changed, 82 insertions(+), 30 deletions(-) diff --git a/algorithms/bidirectional.py b/algorithms/bidirectional.py index 75ce52f..9dfd65a 100644 --- a/algorithms/bidirectional.py +++ b/algorithms/bidirectional.py @@ -2,7 +2,7 @@ def heuristic_cost(start, goal, graph): return 0 -def bidirectional_algorithm(graph, point_set, start, goal, h=heuristic_cost): +def bidirectional_algorithm(graph, start, goal, h=heuristic_cost, is_directed=False): def return_path_and_weight_front(c_f, c, s): current_node = c_f[c] shortest_path = [c, current_node] @@ -11,8 +11,11 @@ def bidirectional_algorithm(graph, point_set, start, goal, h=heuristic_cost): shortest_path.append(current_node) weight = 0 for k in range(len(shortest_path) - 1): - if shortest_path[k] > shortest_path[k+1]: - weight += graph[(shortest_path[k], shortest_path[k+1])] + if not is_directed: + if shortest_path[k] > shortest_path[k+1]: + weight += graph[(shortest_path[k], shortest_path[k+1])] + else: + weight += graph[(shortest_path[k + 1], shortest_path[k])] else: weight += graph[(shortest_path[k + 1], shortest_path[k])] return shortest_path, weight @@ -26,27 +29,46 @@ def bidirectional_algorithm(graph, point_set, start, goal, h=heuristic_cost): weight = 0 shortest_path.reverse() for k in range(len(shortest_path) - 1): - if shortest_path[k] > shortest_path[k+1]: - weight += graph[(shortest_path[k], shortest_path[k+1])] + if not is_directed: + if shortest_path[k] > shortest_path[k+1]: + weight += graph[(shortest_path[k], shortest_path[k+1])] + else: + weight += graph[(shortest_path[k + 1], shortest_path[k])] else: weight += graph[(shortest_path[k + 1], shortest_path[k])] return shortest_path, weight def return_path_and_weight_front_meet_back(c_f_f, c_f_b, c_f, s, g): - shortest_path_front, weight_front = return_path_and_weight_back(c_f_f, c_f, s) + shortest_path_front, weight_front = return_path_and_weight_front(c_f_f, c_f, s) shortest_path_back, weight_back = return_path_and_weight_back(c_f_b, c_f, g) shortest_path_back.reverse() + shortest_path_front.reverse() return shortest_path_front + shortest_path_back[1:], weight_front + weight_back def return_path_and_weight_back_meet_front(c_f_f, c_f_b, c_b, s, g): - shortest_path_front, weight_front = return_path_and_weight_back(c_f_f, c_b, s) + shortest_path_front, weight_front = return_path_and_weight_front(c_f_f, c_b, s) shortest_path_back, weight_back = return_path_and_weight_back(c_f_b, c_b, g) shortest_path_back.reverse() + shortest_path_front.reverse() return shortest_path_front + shortest_path_back[1:], weight_front + weight_back - for edge in graph.keys(): - point_set[edge[0]].append(edge[1]) - point_set[edge[1]].append(edge[0]) + point_set_front = dict() + point_set_back = dict() + for arc in g.keys(): + point_set_front[arc[0]] = [] + point_set_front[arc[1]] = [] + point_set_back[arc[0]] = [] + point_set_back[arc[1]] = [] + + for arc in graph.keys(): + point_set_front[arc[0]].append(arc[1]) + if not is_directed: + point_set_back[arc[1]].append(arc[0]) + point_set_front[arc[1]].append(arc[0]) + point_set_back[arc[0]].append(arc[1]) + else: + point_set_back[arc[1]].append(arc[0]) + open_set_front = set() open_set_front.add(start) @@ -56,16 +78,16 @@ def bidirectional_algorithm(graph, point_set, start, goal, h=heuristic_cost): came_from_front = {} came_from_back = {} - g_score_front = {k: float('inf') for k in point_set.keys()} + g_score_front = {k: float('inf') for k in point_set_front.keys()} g_score_front[start] = 0 - g_score_back = {k: float('inf') for k in point_set.keys()} + g_score_back = {k: float('inf') for k in point_set_back.keys()} g_score_back[goal] = 0 - f_score_front = {k: float('inf') for k in point_set.keys()} + f_score_front = {k: float('inf') for k in point_set_front.keys()} f_score_front[start] = h(start, goal, graph) - f_score_back = {k: float('inf') for k in point_set.keys()} + f_score_back = {k: float('inf') for k in point_set_back.keys()} f_score_back[goal] = h(goal, start, graph) while len(open_set_front) > 0 and len(open_set_back) > 0: @@ -86,6 +108,15 @@ def bidirectional_algorithm(graph, point_set, start, goal, h=heuristic_cost): if current_back == start: return return_path_and_weight_back(came_from_back, current_back, goal) + if current_front in came_from_back.keys() and current_back in came_from_front.keys(): + path1, weight1 = return_path_and_weight_front_meet_back(came_from_front, came_from_back, current_front, + start, goal) + path2, weight2 = return_path_and_weight_back_meet_front(came_from_front, came_from_back, current_back, + start, goal) + if weight1 < weight2: + return path1, weight1 + return path2, weight2 + if current_front in came_from_back.keys(): return return_path_and_weight_front_meet_back(came_from_front, came_from_back, current_front, start, goal) @@ -95,14 +126,16 @@ def bidirectional_algorithm(graph, point_set, start, goal, h=heuristic_cost): open_set_front.remove(current_front) open_set_back.remove(current_back) - for neighbor in point_set[current_front]: + for neighbor in point_set_front[current_front]: tentative_g_score = g_score_front[current_front] - if current_front > neighbor: - tentative_g_score += graph[(current_front, neighbor)] + if not is_directed: + if current_front > neighbor: + tentative_g_score += graph[(current_front, neighbor)] + else: + tentative_g_score += graph[(neighbor, current_front)] else: - tentative_g_score += graph[(neighbor, current_front)] - + tentative_g_score += graph[(current_front, neighbor)] if tentative_g_score < g_score_front[neighbor]: came_from_front[neighbor] = current_front g_score_front[neighbor] = tentative_g_score @@ -110,14 +143,15 @@ def bidirectional_algorithm(graph, point_set, start, goal, h=heuristic_cost): if neighbor not in open_set_front: open_set_front.add(neighbor) - for neighbor in point_set[current_back]: + for neighbor in point_set_back[current_back]: tentative_g_score = g_score_back[current_back] - - if current_back > neighbor: - tentative_g_score += graph[(current_back, neighbor)] + if not is_directed: + if current_back > neighbor: + tentative_g_score += graph[(current_back, neighbor)] + else: + tentative_g_score += graph[(neighbor, current_back)] else: tentative_g_score += graph[(neighbor, current_back)] - if tentative_g_score < g_score_back[neighbor]: came_from_back[neighbor] = current_back g_score_back[neighbor] = tentative_g_score @@ -143,9 +177,15 @@ if __name__ == "__main__": (9, 1): 8 } - v = dict() - for i in g.keys(): - v[i[0]] = [] - v[i[1]] = [] + g2 = { + (4, 1): 6, + (1, 3): 4, + (1, 2): 2, + (2, 4): 5, + (3, 4): 1, + (5, 3): 1 + } - print(bidirectional_algorithm(g, v, 7, 10, heuristic_cost)) + print(bidirectional_algorithm(g, 7, 10, heuristic_cost)) + print(bidirectional_algorithm(g2, 1, 4, heuristic_cost, is_directed=True)) + print(bidirectional_algorithm(g2, 1, 5, heuristic_cost, is_directed=True)) diff --git a/algorithms/dijkstra.py b/algorithms/dijkstra.py index ec117cf..7e9cfac 100644 --- a/algorithms/dijkstra.py +++ b/algorithms/dijkstra.py @@ -16,6 +16,7 @@ def dijkstra_algorithm(graph, start, goal, is_directed=False): # list which is used to keep priority queue with vertexes to be explored by the algorithm queue = [] + # dictionary for keeping neighbors of vertexes. point_set = dict() for arc in graph.keys(): point_set[arc[0]] = [] @@ -27,19 +28,31 @@ def dijkstra_algorithm(graph, start, goal, is_directed=False): if not is_directed: point_set[arc[1]].append(arc[0]) + # initialization of needed lists for vertex in point_set: + # setting distance of every vertex from the starting vertex to infinity dist[vertex] = float('inf') + # setting previous vertex in currently found shortest path for every vertex to None prev[vertex] = None + # setting flag for every vertex keeping track if it was already visited my the algorithm visited[vertex] = False + # pushing start vertex to priority queue heap.heappush(queue, (0, start)) + # setting distance to start for start vertex to 0 dist[start] = 0 + # setting start vertex not to be added to priority queue again visited[start] = True + # main loop while len(queue) > 0: + # getting first vertex from the priority queue and saving it in current variable current = heap.heappop(queue) + # iterating trough all neighbors of the current vertex for neighbor in point_set[current[1]]: + # initializing potential distance to be replaced with the current neighbors new_dist = 0 + # if not is_directed: if neighbor > current[1]: new_dist = dist[current[1]] + graph[(neighbor, current[1])] @@ -93,6 +106,5 @@ if __name__ == "__main__": (5, 3): 1 } - print('') print(dijkstra_algorithm(g, 7, 10)) print(dijkstra_algorithm(g2, 1, 5, is_directed=True))