Пример #1
0
 def tree_search(self, max_expand=float('inf')):
     """initialize state tree using the initial state of problem"""
     expand_count = 0
     while True:
         # if there are no candidates for expansion, return fail
         if self.fringe.is_empty():
             raise Exception("Tree search failed!")
         # choose which node to expand based on strategy: use heuristic to determine the best option to expand
         option = self.fringe.extract_min()
         self.hist.append(option)  # for debug
         # if the node contains a goal state, return the solution
         if option.state.is_goal():
             # check if the chosen node is a goal node
             debug("goal reached:")
             option.state.describe()
             return expand_count, self.backtrack(option)
         elif expand_count < max_expand:
             # otherwise, expand the node
             self.expand_node(option)
             expand_count += 1
         else:
             print(
                 'Maximum number of expansions reached. Returning best strategy so far'
             )
             return expand_count, self.backtrack(option)
Пример #2
0
    def act(self, env: Environment):
        if not self.is_available(env):
            return

        debug("# NOOPS left: {}".format(self.noop_counter))
        if self.noop_counter != 0:
            self.noop_counter -= 1
            self.no_op(env)
            return

        u = self.loc
        if self.last_action_type() == ActionType.BLOCK:
            targets = self.get_possible_steps(env)
        else:
            targets = env.G.neighbours(self.loc)

        edges = [env.G.get_edge(u, v) for v in targets]
        if not edges:
            self.terminate(env)
            return

        def comp(e: Edge):
            dest = e.v1 if u != e.v1 else e.v2
            return e.w, dest.label  # sort by weight, tie-breaker is destination node's name

        e_min = min(edges, key=comp)
        if self.last_action_type() == ActionType.BLOCK:
            # traverse road with lowest weight, i.e move to second vertex of respective edge
            v = e_min.v1 if u != e_min.v1 else e_min.v2
            self.goto2(env, v)
        else:
            # block the accessible road with the lowest weight, i.e remove it from graph
            self.block2(env, e_min)
Пример #3
0
    def heuristic_helper(self, agent, state: State):
        """given a state for an max_player, returns how many people can (!) be saved by the max_player"""
        self.env.apply_state(state, active_agent=agent)
        if agent.terminated:
            return agent.n_saved

        def num_rescuable_carrying():
            can_reach_a_shelter = any([
                self.env.can_reach_before_deadline(v)
                for v in self.env.get_shelters()
            ])
            return agent.n_carrying if can_reach_a_shelter else 0

        def get_evac_candidates():
            """find nodes that can be reached before hurricane hits them.
                :returns: a list of (node, pickup_time, pickup_path) tuples"""
            src = agent.loc
            self.env.G.dijkstra(src)
            evacuation_candidates = []
            require_evac_nodes = self.env.get_require_evac_nodes()
            for v in require_evac_nodes:
                if self.env.can_reach_before_deadline(
                        v) and self.env.can_reach_before_other_agent(agent, v):
                    # nodes we can reach in time
                    time_after_pickup = self.env.time + v.d
                    pickup_shortest_path = list(
                        self.env.G.get_shortest_path(src, v))
                    evacuation_candidates.append(
                        (v, time_after_pickup, pickup_shortest_path))
            return evacuation_candidates

        def can_reach_shelter(evacuation_candidates):
            can_save = []
            V = self.env.G.get_vertices()
            for u, time_after_pickup, pickup_shortest_path in evacuation_candidates:
                self.env.G.dijkstra(
                    u)  # calculate minimum distance from node after pickup
                shelter_candidates = [
                    (v, time_after_pickup + v.d,
                     list(self.env.G.get_shortest_path(u, v))) for v in V
                    if v.is_shelter() and time_after_pickup + v.d <= v.deadline
                ]
                if len(shelter_candidates) != 0:
                    can_save.append(u)
            return can_save

        evac_candidates = get_evac_candidates()
        can_save_nodes = can_reach_shelter(evac_candidates)
        n_already_saved = agent.n_saved
        self.env.G.dijkstra(agent.loc)  # TODO: remove if all goes to shit
        n_can_save_carrying = num_rescuable_carrying()
        n_can_save_new = sum([v.n_people for v in can_save_nodes])
        total_can_save = n_can_save_carrying + n_can_save_new + n_already_saved
        debug(
            '[#{0}]: {1.name} can save {2} (nodes:{3} (={4}) + rescuable carrying ={5} + saved before={1.n_saved})'
            .format(state.ID, agent, total_can_save, can_save_nodes,
                    n_can_save_new, n_can_save_carrying))
        return total_can_save
Пример #4
0
 def try_evacuate(self, env: Environment, v: EvacuateNode):
     if self.terminated:
         return
     if v.is_shelter():
         if self.n_carrying > 0:
             debug('Dropped off {.n_carrying} people'.format(self))
             self.n_saved += self.n_carrying
             self.n_carrying = 0
     elif not v.evacuated:
         debug('Picked up {} people'.format(v.n_people))
         self.n_carrying += v.n_people
         v.evacuated = True
         v.n_people = 0
         env.require_evac_nodes.remove(v)
Пример #5
0
 def expand_node(self, plan: Plan):
     """Expands fringe, adding (path, state) pair of all possible moves."""
     self.env.apply_state(plan.state)
     agent = plan.state.agent
     debug("Expanding node ID={0.ID} (cost = {0.cost}):".format(plan))
     plan.state.describe()
     neighbours = agent.get_possible_steps(
         self.env, verbose=True)  # options to proceed
     for dest in neighbours + [ActionType.TERMINATE]:
         action, result_state = self.successor(plan.state, dest)
         debug("\ncreated state:")
         result_state.describe()
         cost = self.total_cost(result_state)
         new_plan = Plan(cost=cost,
                         state=result_state,
                         action=action,
                         parent=plan)
         debug("plan ID={}".format(new_plan.ID))
         self.fringe.insert(new_plan)
Пример #6
0
 def heuristic(self, state: State = None):
     """given a state for an agent, returns how many people cannot be saved by the agent"""
     self.env.apply_state(state)
     agent = state.agent
     src = agent.loc
     self.env.G.dijkstra(src)
     V = self.env.G.get_vertices()
     require_evac_nodes = list(self.env.require_evac_nodes)
     # find nodes that can be reached before hurricane hits them. create (node, required_pickup_time) pairs
     evac_candidates, doomed_nodes = [], []
     for v in require_evac_nodes:
         if self.env.time + v.d > v.deadline:
             doomed_nodes.append(
                 v)  # nodes we cannot save from the imminent hurricane
         else:
             evac_candidates.append(
                 (v, self.env.time + v.d,
                  list(self.env.G.get_shortest_path(src, v))))
     for u, time_after_pickup, pickup_shortest_path in evac_candidates:
         self.env.G.dijkstra(
             u)  # calculate minimum distance from node after pickup
         shelter_candidates = [
             (v, time_after_pickup + v.d,
              list(self.env.G.get_shortest_path(u, v))) for v in V
             if v.is_shelter() and time_after_pickup + v.d <= v.deadline
         ]
         if not shelter_candidates:
             doomed_nodes.append(u)
         debug('\npossible routes for evacuating {}:'.format(u))
         for shelter, total_time, dropoff_shortest_path in shelter_candidates:
             debug('pickup:(T{}){}(T{}) | drop-off:{}(T{}): Shelter(D{})'.
                   format(self.env.time, pickup_shortest_path,
                          time_after_pickup, dropoff_shortest_path,
                          total_time, shelter.deadline))
     n_doomed_people = sum([v.n_people for v in doomed_nodes])
     debug('h(x) = {} = # of doomed people (doomed_nodes = {})'.format(
         n_doomed_people, doomed_nodes))
     return n_doomed_people
Пример #7
0
 def tie_breaker(agent, option, current_best_option):
     debug('Tie: %s VS. %s' %
           (current_best_option.state.ID, option.state.ID))
     agent_state = agent is option.state.agent and option.state.agent_state or option.state.agent2_state
     return (Configurator.tie_breaker is 'goal' and option.state.is_goal()) or \
            (Configurator.tie_breaker is 'shelter' and agent_state.loc.is_shelter())
Пример #8
0
 def total_cost(self, state):
     # assumes environment's state was updated before calling this function
     h = 0 if state.is_goal() else self.heuristic(state)
     g = state.agent.penalty
     debug('cost = g + h = {} + {} = {}'.format(g, h, g + h))
     return g + h