def greedy(matrix, start, goal): """ Find the path from start to the goal using Greedy Best-first Search Algorithm The algorithm is implemented based on the description on Wikipedia: https://en.wikipedia.org/wiki/Best-first_search#Greedy_BFS Notice: GBFS is suboptimal algorithm, so the solution MAY NOT BE OPTIMAL! :param matrix: Search space, as a 2D list :param start: Start point, as a tuple :param goal: Goal point, as a tuple :return: The path (if found) from start to goal, or None """ print('Analytics: start node ' + str(start) + ', goal node ' + str(goal)) # The set of nodes already evaluated visited = set() partially_expanded = set() # The set of currently discovered nodes that are not evaluated yet. # Initially, only the start node is known. # frontier is implemented as a priority queue frontier = Frontier() frontier.add(start, manhattan_dist(start, goal)) # For each node, which node it can most efficiently be reached from. # If a node can be reached from many nodes, came_from will eventually contain the # most efficient previous step. came_from = {} while frontier: current, current_distance = frontier.nearest if current == goal: print('Analytics: ' + str(len(partially_expanded)) + ' expanded nodes out of ' + str(count_nodes(matrix)) + ' nodes , among which ' + str(len(visited)) + ' are fully expanded (all successors evaluated)') return reconstruct_path(came_from, current) partially_expanded.add(current) is_interrupted = False for neighbor in expand(current, matrix): if neighbor not in visited: neighbor_distance = manhattan_dist(neighbor, goal) if neighbor not in frontier: # Discover a new node came_from[neighbor] = current frontier.add(neighbor, neighbor_distance) if current_distance > neighbor_distance: is_interrupted = True break if not is_interrupted: frontier.pop_nearest() visited.add(current) return None
def a_star(matrix, start, goal, estimate=manhattan_dist): """ Find the path from start to the goal using Greedy Best-first Search Algorithm The algorithm is implemented based on the description on Wikipedia: https://en.wikipedia.org/wiki/Best-first_search#Greedy_BFS Notice: GBFS is suboptimal algorithm, so the solution MAY NOT BE OPTIMAL! :param estimate: Heuristics used in a_star search :param matrix: Search space, as a 2D list :param start: Start point, as a tuple :param goal: Goal point, as a tuple :return: The path (if found) from start to goal, or None """ print('Analytics: start node ' + str(start) + ', goal node ' + str(goal)) # The set of nodes already evaluated visited = set() # For each node, the cost of getting from the start node to that node. # The cost of going from start to start is zero. g_score = {start: 0} # For each node, the total cost of getting from the start node to the goal # by passing by that node. That value is partly known, partly heuristic. # For the first node, that value is completely heuristic. f_score = {start: estimate(start, goal)} # The set of currently discovered nodes that are not evaluated yet. # Initially, only the start node is known. # frontier is implemented as a priority queue frontier = Frontier() frontier.add(start, f_score[start]) # For each node, which node it can most efficiently be reached from. # If a node can be reached from many nodes, came_from will eventually contain the # most efficient previous step. came_from = {} while frontier: current, current_f_score = frontier.pop_nearest() if current == goal: print('Analytics: ' + str(len(visited)) + ' expanded nodes, out of ' + str(count_nodes(matrix)) + ' nodes') # draw_expanded_nodes(matrix, visited) return reconstruct_path(came_from, current) visited.add(current) for neighbor in expand(current, matrix): if neighbor not in visited: g_through_current = g_score[ current] + 1 # every neighbor has distance 1 if (neighbor not in frontier or g_through_current < g_score[neighbor]): # Discover a new node or a better path came_from[neighbor] = current g_score[neighbor] = g_through_current f_score[neighbor] = (g_score[neighbor] + estimate(neighbor, goal)) frontier.add(neighbor, f_score[neighbor]) return None
def a_star_multidots(edges, start: tuple, goals: tuple, estimate=mst_estimator): """ Find the path from start to the goal using Greedy Best-first Search Algorithm The algorithm is implemented based on the description on Wikipedia: https://en.wikipedia.org/wiki/Best-first_search#Greedy_BFS Notice: GBFS is suboptimal algorithm, so the solution MAY NOT BE OPTIMAL! :param estimate: Heuristics used in a_star search :param edges: Search space, as a 2D list :param start: Start point, as a tuple :param goals: Goal points, as a set of all dots :return: The path (if found) from start to goal, or None """ print('Analytics: start node ' + str(start) + ', dots node ' + str(goals)) goals_to_indices = {g: i for i, g in enumerate(goals, 2)} start = init_state(start, goals) if start[0:2] in goals: start = mark_visited(start[0:2], goals_to_indices, start) # The set of nodes already evaluated visited = set() # For each node, the cost of getting from the start node to that node. # The cost of going from start to start is zero. g_score = {start: 0} # For each node, the total cost of getting from the start node to the dots # by passing by that node. That value is partly known, partly heuristic. # For the first node, that value is completely heuristic. # f_score = {start: naive_estimator(start, dots_visited[start], goals)} f_score = {start: estimate(start, goals, edges)} # The set of currently discovered nodes that are not evaluated yet. # Initially, only the start node is known. # frontier is implemented as a priority queue frontier = Frontier() frontier.add(start, f_score[start]) # For each node, which node it can most efficiently be reached from. # If a node can be reached from many nodes, came_from will eventually contain the # most efficient previous step. came_from = {} while frontier: current, current_f_score = frontier.pop_nearest() if current[2:].count(1) == len(current) - 2: print('Analytics: ' + str(len(visited)) + ' expanded nodes, out of ' + str(len(edges) * (2**(len(current) - 2))) + ' nodes') return reconstruct_path(came_from, current) visited.add(current) for neighbor in expand_multidots(current, edges): if neighbor[0:2] in goals: neighbor = mark_visited(neighbor[0:2], goals_to_indices, neighbor) if neighbor not in visited: # Subtract 1 here because the edge_maps contains both start and end for # the shortest path between dots g_through_current = g_score[current] + len( edges[current[0:2]][neighbor[0:2]]) - 1 if (neighbor not in frontier or g_through_current < g_score[neighbor]): # Discover a new node or a better path came_from[neighbor] = current g_score[neighbor] = g_through_current f_score[neighbor] = (g_score[neighbor] + estimate(neighbor, goals, edges)) frontier.add(neighbor, f_score[neighbor]) return None