def my_astar_search_graph(problem, h=None): """A* search is best-first graph search with f(n) = g(n)+h(n). You need to specify the h function when you call astar_search, or else in your Problem subclass.""" h = search.memoize(h or problem.h, 'h') iterations, node = my_best_first_graph_search_for_vis( problem, lambda n: n.path_cost + h(n)) return (iterations, node)
def my_best_first_graph_search(problem, f): """ Taken from Lab 3 Search the nodes with the lowest f scores first. You specify the function f(node) that you want to minimize; for example, if f is a heuristic estimate to the goal, then we have greedy best first search; if f is node.depth then we have breadth-first search. There is a subtlety: the line "f = memoize(f, 'f')" means that the f values will be cached on the nodes as they are computed. So after doing a best first search you can examine the f values of the path returned. """ # keep a track of the number of iterations for use in evaluation iterations = 0 f = memoize(f, 'f') node = Node(problem.initial) iterations += 1 # This is the goal state if problem.goal_test(node.state): iterations += 1 return (iterations, node) # Create a priority queue that is ordered by its distance # from the distance travelled so far (g) + the straight line distance # from the new node to the goal state (h) frontier = PriorityQueue('min', f) frontier.append(node) iterations += 1 explored = set() # Loop until there is no more nodes to visit while frontier: # Get the node with minimum f(n) = g(n) + h(n) node = frontier.pop() iterations += 1 # We have reached the goal, return the solution if problem.goal_test(node.state): iterations += 1 return iterations # Mark the node as visited explored.add(node.state) # Loop over the nodes neighbours and find the next node # with minimum f(n) for child in node.expand(problem): # Only consider new nodes which havent been explored yet # and the ones which we are about to explore in the # loop if child.state not in explored and child not in frontier: frontier.append(child) iterations += 1 # Update the new distance (f(n)) for this node # if it is smaller than the previous known one elif child in frontier: incumbent = frontier[child] if f(child) < f(incumbent): del frontier[incumbent] frontier.append(child) iterations += 1 iterations += 1 return iterations
def my_astar_search(agent_program, heur=None): """ Taken from Lab 3 A* search is best-first graph search with f(n) = g(n)+h(n). You need to specify the h function when you call astar_search, or else in your Problem subclass. """ # define the heuristic function heur = memoize(heur or agent_program.problem.h, 'h') return my_best_first_graph_search(agent_program.problem, lambda n: n.path_cost + heur(n))
def my_best_first_graph_search_for_vis(problem, f): """Search the nodes with the lowest f scores first. You specify the function f(node) that you want to minimize; for example, if f is a heuristic estimate to the goal, then we have greedy best first search; if f is node.depth then we have breadth-first search. There is a subtlety: the line "f = memoize(f, 'f')" means that the f values will be cached on the nodes as they are computed. So after doing a best first search you can examine the f values of the path returned.""" # we use these two variables at the time of visualisations iterations = 0 f = search.memoize(f, 'f') node = search.Node(problem.initial) iterations += 1 if problem.goal_test(node.state): iterations += 1 return (iterations, node) frontier = search.PriorityQueue('min', f) frontier.append(node) iterations += 1 explored = set() while frontier: node = frontier.pop() iterations += 1 if problem.goal_test(node.state): iterations += 1 return (iterations, node) explored.add(node.state) for child in node.expand(problem): if child.state not in explored and child not in frontier: frontier.append(child) iterations += 1 elif child in frontier: incumbent = frontier[child] if f(child) < f(incumbent): del frontier[incumbent] frontier.append(child) iterations += 1 iterations += 1 return None
def iterative_deepening_astar(problem, h, main_limit=100): h = search.memoize(h or problem.h) # Base A* heuristic - adding path cost to passed-in heuristic. def heuristic(n): return n.path_cost + h(n) # Find the initial state Node, and create the initial bound heuristic. initial = search.Node(problem.initial) bound = heuristic(initial) # Algorithm based off psuedocode from # https://en.wikipedia.org/wiki/Iterative_deepening_A*#Pseudocode def recursive_search(node, current_cost, limit): # Ensure the current heuristic hasn't gone over the limit. node_heuristic = heuristic(node) if current_cost + node_heuristic > limit: return current_cost + node_heuristic # Check if the search has found a goal state. if problem.goal_test(node.state): return node value = main_limit # Large value at the start. # Recursively search over all child nodes. for child in node.expand(problem): inner_result = recursive_search( child, current_cost + problem.value(node.state), limit) if type(inner_result) is search.Node: return inner_result elif type(inner_result) is int and inner_result < value: value = inner_result return value while True: result = recursive_search(initial, 0, bound) if type(result) is search.Node: return result elif type(result) is int: if result == main_limit: return None bound = result else: print(str(type(result)) + " is an unhandled type")
def best_first_search_for_vis(problem, f): f = memoize(f, 'f') node = Node(problem.initial) frontier = PriorityQueue('min', f) frontier.append(node) explored = set() reached = [] while frontier: node = frontier.pop() reached.append(node.state) if problem.goal_test(node.state): return (node, reached) explored.add(node.state) for child in node.expand(problem): if child.state not in explored and child not in frontier: frontier.append(child) elif child in frontier: if f(child) < frontier[child]: del frontier[child] frontier.append(child) return (failure, reached)
def astar_search_for_vis(problem, h=None): h = memoize(h or problem.h, 'h') return best_first_search_for_vis(problem, lambda n: n.path_cost + h(n))