def search(self, task, use_relaxed_plan=False): """ Searches for a plan in the given task using A* search. """ node = task.pop_open() task.close(node) if node in self.state_cost: del self.state_cost[node] rplan = None if use_relaxed_plan: (rh, rplan) = node.heuristic.calc_h_with_plan(searchspace.make_root_node(node.state)) for operator, successor_state in task.get_successor_states(node.state): # ignore this operator if we use the relaxed plan criterion if use_relaxed_plan and rplan and not op.name in rplan: continue newNode = searchspace.make_child_node(node, operator, successor_state) if task.goal_reached(newNode): return newNode # drop dead ends and explored nodes and nodes on open but with higher costs crapNode = self.state_cost[newNode] if newNode in self.state_cost else None if newNode.h == float('inf') or task.is_closed(newNode) \ or (crapNode and newNode.g > crapNode.g): continue #if there's a crapNode we now know it really is crap and we make it kick the bucket if crapNode and newNode.g < crapNode.g: task.del_open(crapNode) del self.state_cost[crapNode] task.push_open(newNode) self.state_cost[newNode] = newNode
def setup_root_node(self, task, heuristic): rnode = searchspace.make_root_node(task.initial_state, heuristic, self.sorting_rule) if (task.goal_reached(rnode)): return rnode else: task.push_open(rnode) self.best_heuristic_value = rnode.h
def gbfs(task, heuristic=BlindHeuristic): """ Searches for a plan in the given task using Greedy Best First Search search. @param task The task to be solved @param heuristic A heuristic callable which computes the estimated steps from a search node to reach the goal. """ startSearchNode = searchspace.make_root_node(task.initial_state) heap = [] heapq.heappush(heap, (heuristic(startSearchNode), 0, startSearchNode)) count = 0 res = None nodeCount = 0 vis = set() while True: if not heap: return 0 _, _, tempSearchNode = heapq.heappop(heap) nodeCount += 1 if tempSearchNode.state in vis: continue vis.add(tempSearchNode.state) for action, state in Task.get_successor_states(task, tempSearchNode.state): nextSearchNode = searchspace.make_child_node( tempSearchNode, action, state) if Task.goal_reached(task, state): logging.info("Node Expansion: " + str(nodeCount)) return nextSearchNode.extract_solution() else: count += 1 heapq.heappush( heap, (heuristic(nextSearchNode), count, nextSearchNode))
def gbfs(task, heuristic=BlindHeuristic): """ Searches for a plan in the given task using Greedy Best First Search search. @param task The task to be solved @param heuristic A heuristic callable which computes the estimated steps from a search node to reach the goal. """ heap = [] root_node = searchspace.make_root_node(task.initial_state) # def __init__(self, state, parent, action, g): explored = set() explored.add(root_node.state) counter = 1 # incase the heapq get stuck heapq.heappush(heap,( heuristic(root_node) ,counter , root_node )) node_expansion = 0 # the number of nodes expansion while (True): node = heapq.heappop(heap)[2] node_expansion = node_expansion + 1 # POP = node expansion if task.goal_reached(node.state): print("------------------") print("node expasion:") print(node_expansion) # print the node_expansion for question 3 print("------------------") return node.extract_solution() for successor in task.get_successor_states(node.state): # pair successor(1) or [1] succ_state = successor[1] succ_action = successor[0] if succ_state not in explored: # in order loop new_node = searchspace.make_child_node(node,succ_action,succ_state) #make_child_node(parent_node, action, state): explored.add(succ_state) counter = counter + 1 heapq.heappush(heap,( heuristic(new_node) , counter ,new_node ))
def a_star(task, heuristic=BlindHeuristic): expandedNodes = 0 ## couting the number of nodes flag = 0 Que = frontiers.PriorityQueue() ## stack que for saving nodes root_node = searchspace.make_root_node( task.initial_state) ## creating nodes out of vertices. h_root_node = heuristic( root_node) ## creating a node containing its heuristic values. Que.push(root_node, root_node.g + h_root_node) node_dict1 = dict() ## dictionary to save nodes based on their cost. node_dict1[root_node.state] = (root_node.g + h_root_node) ''' A loop to traverse the priority que in order to find the best solution. ''' while not (Que.is_empty()): node = Que.pop() expandedNodes = expandedNodes + 1 succ_act_state_list = task.get_successor_states(node.state) for succ_tuple in succ_act_state_list: succ_node = searchspace.make_child_node(node, succ_tuple[0], succ_tuple[1]) if task.goal_reached(succ_node.state): last_node = succ_node flag = 1 break else: h_succ_state = heuristic(succ_node) if (succ_node.state in node_dict1.keys()): if (node_dict1[succ_node.state] > (succ_node.g + h_succ_state)): node_dict1[ succ_node.state] = succ_node.g + h_succ_state Que.change_priority(succ_node, succ_node.g + h_succ_state) else: node_dict1[succ_node.state] = succ_node.g + h_succ_state Que.push(succ_node, succ_node.g + h_succ_state) if flag == 1: break current_node = last_node action_list = [] ''' Finding the most optimal path to the solution. ''' while current_node != root_node: action_list.append(current_node.action) current_node = current_node.parent action_list.reverse() print("Expanded Nodes= ", expandedNodes) return action_list """
def a_star(task, heuristic=BlindHeuristic): """ Searches for a plan in the given task using A* search. @param task The task to be solved @param heuristic A heuristic callable which computes the estimated steps from a search node to reach the goal. """ import time start = time.time() explored = {} queue = [] # create initial node and push into the queue sn_0 = searchspace.make_root_node(task.initial_state) heapq.heappush(queue, (heuristic(sn_0) + sn_0.g, 0, sn_0)) temp = 0 # counter for the queue to break overlab num_nodes = 0 # number of pxpanded nodes while len(queue) != 0: # timer to timeout the program # if time.time() - start > 60: # print("time out") # exit() # dequeue a top priority node current_node = heapq.heappop(queue)[2] # count the number of expanded nodes num_nodes += 1 # check if the state is the goal or not if task.goal_reached(current_node.state): print(current_node.extract_solution()) logging.info("Number of nodes: " + str(num_nodes)) return current_node.extract_solution() # put this node's state in the explored dictionary with its cost explored[current_node.state] = heuristic(current_node) + current_node.g for action, state in task.get_successor_states(current_node.state): # create new node for the successor new_node = searchspace.make_child_node(current_node, action, state) # calculate the heuristic value for this new node heuristic_new_node = heuristic(new_node) + current_node.g # if this state is not visited yet or the cost to get this state is cheper than current cost, register/update the cost to get this state if state not in explored or explored[state] > heuristic_new_node: explored[state] = heuristic_new_node temp += 1 heapq.heappush(queue, (heuristic_new_node, temp, new_node))
def pyperplan_hill_climbing(task): # assert False current = searchspace.make_root_node(task.initial_state) current_h = heuristic(current.state) iterations = 0 while not task.goal_reached(current.state): iterations += 1 if iterations % 1000 == 0: logging.debug( "Number of visited states in hill-climbing: {}".format( iterations)) improvement_found = False successors = task.get_successor_states(current.state) if not successors: logging.error("State without successors found: {}".format( current.state)) return None # This implements steepest-ascent hill climbing. # If we want to test in problems with very large branching factors, we might want to jump to # an heuristic-improving child as soon as we find one. succesor_h_values = [(heuristic(succ), succ, op) for op, succ in successors] h_succ, succ, op = min(succesor_h_values, key=lambda x: x[0]) if h_succ < current_h: current = searchspace.make_child_node(current, op, succ) current_h = h_succ else: logging.error( "Heuristic local minimum of {} found on state {}".format( current_h, current.state)) logging.error("Children nodes:") print("\t" + "\n\t".join("h: {}, s: {}".format(h, s) for h, s, _ in succesor_h_values)) return None logging.info("Goal found") return current.extract_solution()
def a_star(task, heuristic=BlindHeuristic): """ Searches for a plan in the given task using A* search. @param task The task to be solved @param heuristic A heuristic callable which computes the estimated steps from a search node to reach the goal. """ startSearchNode = searchspace.make_root_node(task.initial_state) heap = [] h0 = heuristic(startSearchNode) count = 0 heapq.heappush(heap, (h0, count, startSearchNode)) count += 1 nodeCount = 0 vis = set() res = None while heap: tempH, _, tempSearchNode = heapq.heappop(heap) nodeCount += 1 if tempSearchNode.state in vis: continue vis.add(tempSearchNode.state) if res and res.g <= tempH: break for action, state in Task.get_successor_states(task, tempSearchNode.state): nextSearchNode = searchspace.make_child_node( tempSearchNode, action, state) if Task.goal_reached(task, state): if res and res.g <= nextSearchNode.g: continue res = nextSearchNode else: count += 1 heapq.heappush(heap, (nextSearchNode.g + heuristic(nextSearchNode), count, nextSearchNode)) logging.info("Node Expansion: " + str(nodeCount)) return res.extract_solution()
def gbfs(task, heuristic=BlindHeuristic): expandedNodes = 0 flag = 0 Que = frontiers.PriorityQueue() root_node = searchspace.make_root_node(task.initial_state) heur = heuristic(root_node) Que.push(root_node, heur) node_dict1 = dict() node_dict1[root_node.state] = heur while not (Que.is_empty()): node = Que.pop() expandedNodes = expandedNodes + 1 succ_act_state_list = task.get_successor_states(node.state) for succ_tuple in succ_act_state_list: succ_node = searchspace.make_child_node(node, succ_tuple[0], succ_tuple[1]) if task.goal_reached(succ_node.state): last_node = succ_node flag = 1 break else: if (succ_node.state in node_dict1): pass else: heur = heuristic(succ_node) node_dict1[succ_node.state] = heur Que.push(succ_node, heur) if flag == 1: break current_node = last_node action_list = [] while current_node != root_node: action_list.append(current_node.action) current_node = current_node.parent action_list.reverse() print("Expanded Nodes", expandedNodes) return action_list
def astar_search(task, heuristic, make_open_entry=ordered_node_astar, use_relaxed_plan=False): """ Searches for a plan in the given task using A* search. @param task The task to be solved @param heuristic A heuristic callable which computes the estimated steps from a search node to reach the goal. @param make_open_entry An optional parameter to change the bahavior of the astar search. The callable should return a search node, possible values are ordered_node_astar, ordered_node_weighted_astar and ordered_node_greedy_best_first with obvious meanings. """ open = [] state_cost = {task.initial_state: 0} node_tiebreaker = 0 root = searchspace.make_root_node(task.initial_state) # There is often a one-step error in estimation here init_h = heuristic(root) heapq.heappush(open, make_open_entry(root, init_h, node_tiebreaker)) logging.info("Initial h value: %f" % init_h) besth = float('inf') counter = 0 expansions = 0 while open: (f, h, _tie, pop_node) = heapq.heappop(open) if h < besth: besth = h logging.debug("Found new best h: %d after %d expansions" % (besth, counter)) pop_state = pop_node.state # Only expand the node if its associated cost (g value) is the lowest # cost known for this state. Otherwise we already found a cheaper # path after creating this node and hence can disregard it. if (state_cost[pop_state] == pop_node.g) and (state_cost[pop_state] != float('inf')): expansions += 1 if task.goal_reached(pop_state): logging.info("Goal reached. Start extraction of solution.") logging.info("%d Nodes expanded" % expansions) return pop_node.extract_solution(), expansions rplan = None if use_relaxed_plan: (rh, rplan) = heuristic.calc_h_with_plan( searchspace.make_root_node(pop_state)) logging.debug("relaxed plan %s " % rplan) for op, succ_state in task.get_successor_states(pop_state): if use_relaxed_plan: if rplan and not op.name in rplan: # ignore this operator if we use the relaxed plan # criterion logging.debug('removing operator %s << not a ' 'preferred operator' % op.name) continue else: logging.debug('keeping operator %s' % op.name) ## Visual scoring algorithm ## visual_score = 0.0 if 'join-' in op.name: # Keep track of constructions that are already attempted action_part, handle_part, tool_type = actionParser(op) if (action_part, handle_part) in object_combinations: visual_score = -float('inf') # Compute visual score if flag enabled elif settings_flag['vs_flag']: # Check if parts can be attached if attCompute(action_part, handle_part): visual_score = scoreCompute( action_part, handle_part, tool_type) else: visual_score = -float('inf') # Check flag for sensor_trust parameter if settings_flag['trust'] and visual_score == -float( 'inf'): # Use shape score only if visual_score is infinity visual_score = scoreCompute( action_part, handle_part, tool_type, True) succ_node = searchspace.make_child_node( pop_node, op, succ_state) # We subtract from 2 because max visual score is 2, and we need to retain admissibility of heuristic h = heuristic(succ_node) - visual_score if settings_flag[ 'ff_flag'] else 2.0 - visual_score if h == float('inf'): # don't bother with states that can't reach the goal anyway continue old_succ_g = state_cost.get(succ_state, float("inf")) if succ_node.g < old_succ_g: # We either never saw succ_state before, or we found a # cheaper path to succ_state than previously. node_tiebreaker += 1 heapq.heappush( open, make_open_entry(succ_node, h, node_tiebreaker)) state_cost[succ_state] = succ_node.g counter += 1 logging.info("No operators left. Task unsolvable.") logging.info("%d Nodes expanded" % expansions) return None, expansions
def astar_search(task, heuristic, make_open_entry=ordered_node_astar, use_relaxed_plan=False): """ Searches for a plan in the given task using A* search. @param task The task to be solved @param heuristic A heuristic callable which computes the estimated steps from a search node to reach the goal. @param make_open_entry An optional parameter to change the bahavior of the astar search. The callable should return a search node, possible values are ordered_node_astar, ordered_node_weighted_astar and ordered_node_greedy_best_first with obvious meanings. """ open = [] state_cost = {task.initial_state: 0} node_tiebreaker = 0 root = searchspace.make_root_node(task.initial_state) init_h = heuristic(root) heapq.heappush(open, make_open_entry(root, init_h, node_tiebreaker)) logging.info("Initial h value: %f" % init_h) besth = float('inf') counter = 0 expansions = 0 while open: (f, h, _tie, pop_node) = heapq.heappop(open) if h < besth: besth = h logging.debug("Found new best h: %d after %d expansions" % (besth, counter)) pop_state = pop_node.state # Only expand the node if its associated cost (g value) is the lowest # cost known for this state. Otherwise we already found a cheaper # path after creating this node and hence can disregard it. if state_cost[pop_state] == pop_node.g: expansions += 1 if task.goal_reached(pop_state): logging.info("Goal reached. Start extraction of solution.") logging.info("%d Nodes expanded" % expansions) return pop_node.extract_solution() rplan = None if use_relaxed_plan: (rh, rplan) = heuristic.calc_h_with_plan( searchspace.make_root_node(pop_state)) logging.debug("relaxed plan %s " % rplan) for op, succ_state in task.get_successor_states(pop_state): if use_relaxed_plan: if rplan and not op.name in rplan: # ignore this operator if we use the relaxed plan # criterion logging.debug('removing operator %s << not a ' 'preferred operator' % op.name) continue else: logging.debug('keeping operator %s' % op.name) succ_node = searchspace.make_child_node(pop_node, op, succ_state) h = heuristic(succ_node) if h == float('inf'): # don't bother with states that can't reach the goal anyway continue old_succ_g = state_cost.get(succ_state, float("inf")) if succ_node.g < old_succ_g: # We either never saw succ_state before, or we found a # cheaper path to succ_state than previously. node_tiebreaker += 1 heapq.heappush(open, make_open_entry(succ_node, h, node_tiebreaker)) state_cost[succ_state] = succ_node.g counter += 1 logging.info("No operators left. Task unsolvable.") logging.info("%d Nodes expanded" % expansions) return None
def astar_state_sampling(task, heuristic, max_fn, sample_size): """ Samples states in the heuristic search cone @param task The task defining the state model @param heuristic The heuristic to be used """ import random open = [] state_cost = {task.initial_state: 0} node_tiebreaker = 0 root = searchspace.make_root_node(task.initial_state) root.g = 0 root.tie = node_tiebreaker init_h = heuristic(root) root.h = init_h heapq.heappush(open, ordered_node_astar(root, init_h, node_tiebreaker)) besth = float('inf') counter = 0 expansions = 0 witnesses = [] while open: (f, h, _tie, pop_node) = heapq.heappop(open) if pop_node.g > max_fn: continue pop_state = pop_node.state # Only expand the node if its associated cost (g value) is the lowest # cost known for this state. Otherwise we already found a cheaper # path after creating this node and hence can disregard it. if state_cost[pop_state] == pop_node.g: expansions += 1 if random.randint(0, max_fn) > pop_node.g: witnesses.append((pop_node, h)) sample_size -= 1 if sample_size == 0: return witnesses # we're done if task.goal_reached(pop_state): continue for op, succ_state in task.get_successor_states(pop_state): succ_node = searchspace.make_child_node( pop_node, op, succ_state) h = heuristic(succ_node) if h == float('inf'): # don't bother with states that can't reach the goal anyway continue old_succ_g = state_cost.get(succ_state, float("inf")) if succ_node.g < old_succ_g: # We either never saw succ_state before, or we found a # cheaper path to succ_state than previously. node_tiebreaker += 1 succ_node.tie = node_tiebreaker succ_node.h = h heapq.heappush( open, ordered_node_astar(succ_node, h, node_tiebreaker)) state_cost[succ_state] = succ_node.g counter += 1 return witnesses
import py.test # create 4 dummy tasks task1 = dummy_task.get_search_space_at_goal() task2 = dummy_task.get_simple_search_space() task3 = dummy_task.get_simple_search_space_2() task4 = dummy_task.get_search_space_no_solution() # call the heuristic for each task h1 = dummy_task.DummyHeuristic(task1) h2 = dummy_task.DummyHeuristic(task2) h3 = dummy_task.DummyHeuristic(task3) h4 = dummy_task.DummyHeuristic(task4) # create root node for each task root1 = searchspace.make_root_node(task1.initial_state) root2 = searchspace.make_root_node(task2.initial_state) root3 = searchspace.make_root_node(task3.initial_state) root4 = searchspace.make_root_node(task4.initial_state) # Testing each function if it returns the correct values def test_ordered_node_astar1(): h_val = h1(root1) assert a_star.ordered_node_astar(root1, h_val, 0) == (0, 0, 0, root1) def test_ordered_node_astar2(): h_val = h2(root2) assert a_star.ordered_node_astar(root2, h_val, 0) == (5, 5, 0, root2)
def test_blind_heuristic_start(): task = _get_simple_task() bh = BlindHeuristic(task) assert bh(searchspace.make_root_node(task.initial_state)) == 1
def astar_search(task, heuristic, make_open_entry=ordered_node_astar, use_relaxed_plan=False): """ Searches for a plan in the given task using A* search. @param task The task to be solved @param heuristic A heuristic callable which computes the estimated steps from a search node to reach the goal. @param make_open_entry An optional parameter to change the bahavior of the astar search. The callable should return a search node, possible values are ordered_node_astar, ordered_node_weighted_astar and ordered_node_greedy_best_first with obvious meanings. """ open = [] state_cost = {task.initial_state: 0} node_tiebreaker = 0 root = searchspace.make_root_node(task.initial_state) init_h = heuristic(root) heapq.heappush(open, make_open_entry(root, init_h, node_tiebreaker)) logging.info("Initial h value: %f" % init_h) besth = float('inf') counter = 0 expansions = 0 while open: (f, h, _tie, pop_node) = heapq.heappop(open) if h < besth: besth = h logging.debug("Found new best h: %d after %d expansions" % (besth, counter)) pop_state = pop_node.state # Only expand the node if its associated cost (g value) is the lowest # cost known for this state. Otherwise we already found a cheaper # path after creating this node and hence can disregard it. if state_cost[pop_state] == pop_node.g: expansions += 1 if task.goal_reached(pop_state): logging.info("Goal reached. Start extraction of solution.") logging.info("Nodes expanded: %d" % expansions) return pop_node.extract_solution() rplan = None if use_relaxed_plan: (rh, rplan) = heuristic.calc_h_with_plan( searchspace.make_root_node(pop_state)) logging.debug("relaxed plan %s " % rplan) for op, succ_state in task.get_successor_states(pop_state): if use_relaxed_plan: if rplan and not op.name in rplan: # ignore this operator if we use the relaxed plan # criterion logging.debug('removing operator %s << not a ' 'preferred operator' % op.name) continue else: logging.debug('keeping operator %s' % op.name) succ_node = searchspace.make_child_node( pop_node, op, succ_state) h = heuristic(succ_node) print(80 * '*') print("HEURISTIC:", h) print("STATE:", succ_node.state) print(80 * '*') if h == float('inf'): # don't bother with states that can't reach the goal anyway continue old_succ_g = state_cost.get(succ_state, float("inf")) if succ_node.g < old_succ_g: # We either never saw succ_state before, or we found a # cheaper path to succ_state than previously. node_tiebreaker += 1 heapq.heappush( open, make_open_entry(succ_node, h, node_tiebreaker)) state_cost[succ_state] = succ_node.g counter += 1 logging.info("No operators left. Task unsolvable.") logging.info("Nodes expanded: %d" % expansions) return None
def pref_partial_astar_search(task, heuristic, succ_fn=None, make_open_entry=ordered_node_astar): """ Searches for a plan in the given task using A* search. @param task The task to be solved @param heuristic A heuristic callable which computes the estimated steps from a search node to reach the goal. @param make_open_entry An optional parameter to change the bahavior of the astar search. The callable should return a search node, possible values are ordered_node_astar, ordered_node_weighted_astar and ordered_node_greedy_best_first with obvious meanings. """ if succ_fn is None: succ_fn = task.compute_successor_state open = [] node_tiebreaker = 0 root = searchspace.make_root_node(task.initial_state) init_h = heuristic(root) heapq.heappush(open, make_open_entry(root, init_h, tie_breaking_function(root))) logging.info("Initial h value: %f" % init_h) # try: # heuristic.print_relaxed_plan() # except: # pass pending = {task.initial_state: root} closed = {} if init_h == float('inf'): logging.info('Problem has no solution, h(s0) = infty') return None besth = float('inf') maxf = root.g + root.h counter = 0 expansions = 0 while open: entry = heapq.heappop(open) # this is the best node in Open f, h, _tie, pop_node = entry check_f = pop_node.g + h if check_f < f: # this node was re-inserted with a lower f-value, so it has already # been expanded. continue elif check_f > f: logging.info( 'PrefPEA*: ASSERT FAIL! f={0}, h={1}, g={2}, po(n)={3}, s={4}, n={5}' .format( f, h, pop_node.g, len(pop_node.preferred_ops) - pop_node.preferred_ops_counter, str(pop_node.state.primary), [act.name for act in pop_node.extract_solution()])) assert check_f <= f #assert pop_node.state in pending pending.pop(pop_node.state) if f > maxf: maxf = f logging.info("f = %d, nodes = %d" % (maxf, expansions)) if h < besth: besth = h logging.debug("Found new best h: %d after %d evaluations" % (besth, counter)) pop_state = pop_node.state if h == float('inf'): # Remove from open closed[pop_state] = pop_node continue if task.goal_reached(pop_state): logging.info("Goal reached. Start extraction of solution.") logging.info("{0} Nodes expanded, {1} Nodes evaluated".format( expansions, counter)) return pop_node.extract_solution() logging.debug( 'PrefPEA*: Expanding f={0}, h={1}, g={2}, po(n)={3}, s={4}, n={5}'. format( f, h, pop_node.g, len(pop_node.preferred_ops) - pop_node.preferred_ops_counter, str(pop_node.state.primary), [act.name for act in pop_node.extract_solution()])) if pop_node.preferred_ops_counter < len(pop_node.preferred_ops): # get next preferred operator, and increase the counter action = pop_node.preferred_ops[pop_node.preferred_ops_counter] pop_node.preferred_ops_counter += 1 # generate successor (expensive!) succ_state = succ_fn(pop_state, action) if succ_state is None: heapq.heappush(open, (f, h, _tie, pop_node)) pending[pop_state] = pop_node continue logging.debug('Applying helpful action: {0} with cost: {1}'.format( action.name, action.cost)) succ_node = searchspace.make_child_node(pop_node, action, succ_state) if new_state(succ_node, heuristic, make_open_entry, open, pending, closed): counter += 1 #assert succ_node.state in pending heapq.heappush(open, (f, h, _tie, pop_node)) pending[pop_state] = pop_node continue for a in task.actions: if a in pop_node.preferred_ops: continue #logging.info( 'PrefPEA*: Generating successor through non-preferred op...' ) succ_state = succ_fn(pop_state, a) if succ_state is None: continue succ_node = searchspace.make_child_node(pop_node, a, succ_state) if new_state(succ_node, heuristic, make_open_entry, open, pending, closed): counter += 1 #assert succ_node.state in pending # Remove from open logging.debug( 'PrefPEA*: closing f={0}, h={1}, g={2}, po(n)={3}, s={4}, n={5}'. format( pop_node.f, pop_node.h, pop_node.g, len(pop_node.preferred_ops) - pop_node.preferred_ops_counter, str(pop_node.state.primary), [act.name for act in pop_node.extract_solution()])) closed[pop_state] = pop_node expansions += 1 logging.info("No operators left. Task unsolvable.") logging.info("{0} Nodes expanded, {1} Nodes evaluated".format( expansions, counter)) return None
def restarting_pref_partial_astar_search(task, heuristic, make_open_entry=ordered_node_astar): """ Searches for a plan in the given task using A* search. @param task The task to be solved @param heuristic A heuristic callable which computes the estimated steps from a search node to reach the goal. @param make_open_entry An optional parameter to change the bahavior of the astar search. The callable should return a search node, possible values are ordered_node_astar, ordered_node_weighted_astar and ordered_node_greedy_best_first with obvious meanings. """ succ_fn = task.compute_successor_state_ngl_dyn_model open = [] node_tiebreaker = 0 root = searchspace.make_root_node(task.initial_state) init_h = heuristic(root) heapq.heappush(open, make_open_entry(root, init_h, tie_breaking_function(root))) logging.info("Initial h value: %f" % init_h) pending = {task.initial_state: root} closed = {} besth = float('inf') counter = 0 expansions = 0 while open: entry = open[0] # this is the best node in Open (f, h, _tie, pop_node) = entry if h < besth: besth = h logging.debug("Found new best h: %d after %d evaluations" % (besth, counter)) pop_state = pop_node.state if h == float('inf'): # Remove from open heapq.heappop(open) pending.pop(pop_state) closed[pop_state] = pop_node continue if task.goal_reached(pop_state): logging.info("Goal reached. Start extraction of solution.") logging.info("{0} Nodes expanded, {1} Nodes evaluated".format( expansions, counter)) return pop_node.extract_solution(), False logging.debug( 'PrefPEA*: Expanding f={0}, h={1}, g={2}, po(n)={3}'.format( f, h, pop_node.g, len(pop_node.preferred_ops) - pop_node.preferred_ops_counter)) if pop_node.preferred_ops_counter < len(pop_node.preferred_ops): # get next preferred operator, and increase the counter action = pop_node.preferred_ops[pop_node.preferred_ops_counter] pop_node.preferred_ops_counter += 1 # generate successor (expensive!) succ_state, needs_restart = succ_fn(pop_state, action) if succ_state is None: if needs_restart: return [], True continue succ_node = searchspace.make_child_node(pop_node, action, succ_state) if new_state(succ_node, heuristic, make_open_entry, open, pending, closed): counter += 1 continue for a in task.actions: if a in pop_node.preferred_ops: continue #logging.info( 'PrefPEA*: Generating successor through non-preferred op...' ) succ_state, needs_restart = succ_fn(pop_state, a) if succ_state is None: if needs_restart: return [], True continue succ_node = searchspace.make_child_node(pop_node, a, succ_state) if new_state(succ_node, heuristic, make_open_entry, open, pending, closed): counter += 1 # Remove from open logging.debug( 'PrefPEA*: closing f={0}, h={1}, g={2}, po(n)={3}'.format( pop_node.h, pop_node.h, pop_node.g, len(pop_node.preferred_ops) - pop_node.preferred_ops_counter)) heapq.heappop(open) pending.pop(pop_state) closed[pop_state] = pop_node expansions += 1 logging.info("No operators left. Task unsolvable.") logging.info("{0} Nodes expanded, {1} Nodes evaluated".format( expansions, counter)) return None, False
""" Unit Testing for the search space module """ from search.searchspace import make_root_node, make_child_node # Construct a small tree in order to perform some needed test methods root = make_root_node("state1") child1 = make_child_node(root, "action1", "state2") child2 = make_child_node(root, "action2", "state3") grandchild1 = make_child_node(child1, "action3", "state4") grandchild2 = make_child_node(child2, "action4", "state5") def test_extract_solution(): """ Tests whether extract_solution method within class searchspace returns the list of actions starting from the root """ assert root.extract_solution() == [] assert grandchild1.extract_solution() == ["action1", "action3"] assert grandchild2.extract_solution() == ["action2", "action4"] def test_g_values(): """ Tests whether the distance of the node from the root is computed properly """ assert root.g == 0 assert child1.g == 1
def test_blind_heuristic_goal(): task = _get_simple_task() bh = BlindHeuristic(task) assert bh(searchspace.make_root_node(task.goals)) == 0
def a_star(task, heuristic=BlindHeuristic): """ Searches for a plan in the given task using A* search. @param task The task to be solved @param heuristic A heuristic callable which computes the estimated steps from a search node to reach the goal. """ heap = [] root_node = searchspace.make_root_node(task.initial_state) # def __init__(self, state, parent, action, g): explored = {} explored [root_node.state] = root_node.g counter = 1 heapq.heappush(heap,( root_node.g+ heuristic(root_node) ,counter , root_node )) node_expansion = 0 while (True): node = heapq.heappop(heap)[2] node_expansion = node_expansion + 1 if task.goal_reached(node.state): print("------------------") print("node expasion:") print(node_expansion) print("------------------") return node.extract_solution() for successor in task.get_successor_states(node.state): # pair successor(1) or [1] succ_state = successor[1] succ_action = successor[0] new_node = searchspace.make_child_node(node,succ_action,succ_state) #make_child_node(parent, action, state): if (succ_state in explored and explored[succ_state] > new_node.g) or (succ_state not in explored) : # reopen! counter = counter + 1 heapq.heappush(heap,( new_node.g+ heuristic(new_node) , counter ,new_node )) explored [succ_state] = new_node.g ''' skip = False # if the state is already in the heapq, then update it rather than push it for elem in heap : if elem[2].state == succ_state: a_counter = a_counter +1 skip = True elem[2].parent = new_node.parent elem[2].action = succ_action elem[2].g = new_node.g ''' #if not skip: ''' if succ_state not in explored: counter = counter + 1 heapq.heappush(heap,( new_node.g+ heuristic(new_node) , counter ,new_node )) explored [succ_state] = new_node.g ''' ''' def find(heap, f): """ Returns some item n from the queue such that f(n) == True and None if there is no such item. (PriorityQueue, (object) -> object/None) -> object """ for elem in heap: if f(elem[2]): return elem[2] return None def change_priority(heap, item, priority,counter): """ Change the priority of the given item to the specified value. If the item is not in the queue, a ValueError is raised. (PriorityQueue, object, int) -> None """ for eid, elem in enumerate(heap): if elem[2] == item: heap[eid] = (priority, count, item) count += 1 heapq.heapify(heap) return raise ValueError("Error: " + str(item) + " is not in the PriorityQueue.") '''
# create 4 dummy tasks task1 = dummy_task.get_search_space_at_goal() task2 = dummy_task.get_simple_search_space() task3 = dummy_task.get_simple_search_space_2() task4 = dummy_task.get_search_space_no_solution() # call the heuristic for each task h1 = dummy_task.DummyHeuristic(task1) h2 = dummy_task.DummyHeuristic(task2) h3 = dummy_task.DummyHeuristic(task3) h4 = dummy_task.DummyHeuristic(task4) # create root node for each task root1 = searchspace.make_root_node(task1.initial_state) root2 = searchspace.make_root_node(task2.initial_state) root3 = searchspace.make_root_node(task3.initial_state) root4 = searchspace.make_root_node(task4.initial_state) # Testing each function if it returns the correct values def test_ordered_node_astar1(): h_val = h1(root1) assert a_star.ordered_node_astar(root1, h_val, 0) == (0, 0, 0, root1) def test_ordered_node_astar2(): h_val = h2(root2)
""" Unit Testing for the search space module """ from search.searchspace import make_root_node, make_child_node # Construct a small tree in order to perform some needed test methods root = make_root_node("state1") child1 = make_child_node(root, "action1", "state2") child2 = make_child_node(root, "action2", "state3") grandchild1 = make_child_node(child1, "action3", "state4") grandchild2 = make_child_node(child2, "action4", "state5") def test_extract_solution(): """ Tests whether extract_solution method within class searchspace returns the list of actions starting from the root """ assert root.extract_solution() == [] assert grandchild1.extract_solution() == ["action1", "action3"] assert grandchild2.extract_solution() == ["action2", "action4"] def test_g_values(): """ Tests whether the distance of the node from the root is computed properly """ assert root.g == 0
import os import py from task import Task, Operator import pyperplan as planner from search import breadth_first_search, searchspace benchmarks = os.path.abspath( os.path.join(os.path.abspath(__file__), '../../../benchmarks')) # Collect problem files problem_file = os.path.join(benchmarks, 'parcprinter', 'task01.pddl') domain_file = planner.find_domain(problem_file) problem = planner._parse(domain_file, problem_file) task = planner._ground(problem) # Manually do the "search" node = searchspace.make_root_node(task.initial_state) for step, op_name in enumerate(optimal_plan, start=1): for op, successor_state in task.get_successor_states(node.state): if not op.name.strip('()') == op_name: continue node = searchspace.make_child_node(node, op, successor_state) # Check that we reached the goal assert len(task.goals - node.state) == 0
import os import py from task import Task, Operator import pyperplan as planner from search import breadth_first_search, searchspace benchmarks = os.path.abspath(os.path.join(os.path.abspath(__file__), '../../../benchmarks')) # Collect problem files problem_file = os.path.join(benchmarks, 'parcprinter', 'task01.pddl') domain_file = planner.find_domain(problem_file) problem = planner._parse(domain_file, problem_file) task = planner._ground(problem) # Manually do the "search" node = searchspace.make_root_node(task.initial_state) for step, op_name in enumerate(optimal_plan, start=1): for op, successor_state in task.get_successor_states(node.state): if not op.name.strip('()') == op_name: continue node = searchspace.make_child_node(node, op, successor_state) # Check that we reached the goal assert len(task.goals - node.state) == 0