def __init__(self, graph_file, agent_file, f): self.graph_file = graph_file self.time = 0 # track time of the world self.evacuated = 0 # total number of people evacuated self.f_constant = f self.agents_history = [] # search paths of smart agents world = World(graph_file=graph_file, k=self.prompt_k()) self.deadline = world.get_deadline() agents = self.get_agents_data(agent_file=agent_file, world=world) super(HurricaneEvacuationSimulator, self).__init__(state=world, agents=agents) self.vandal_records = {} # pairs of <edge>:<time-of-blocking>
class HurricaneGameSimulator(Simulator): def __init__(self, graph_file, agent_file, cutoff_depth, ping_pong, mode='adversarial'): self.ping_pong = ping_pong self.graph_file = graph_file self.time = 0 # track time of the world self.evacuated = 0 # total number of people evacuated self.agents_history = [] # search paths of smart agents self.cutoff_depth = int(cutoff_depth) self.world = World(graph_file=graph_file, k=self.prompt_k()) self.deadline = self.world.get_deadline() self.agents = self.get_agents_data(agent_file=agent_file, world=self.world) self.init_state = self.create_init_states(self.world, self.agents) self.mode = mode if not ping_pong: self.game_tree = GameTree(self.init_state, self.world, self.agents, mode=mode, cutoff_depth=self.cutoff_depth) super(HurricaneGameSimulator, self).__init__(state=self.world, agents=self.agents) # return num of actions for each agent def get_all_actions(self): agent_actions = {} for agent in self.agents: agent_actions[agent.name] = len(agent.get_actions()) return agent_actions # return number of all people evacuated for ALL agents def get_total_evacuated(self): acc = 0 for agent in self.agents: acc += agent.get_evacuated() return acc # move agent to the destination def move_agent_to(self, agent, dest, edge): agent.vertex = dest # move the agent moving_time = self.calculate_price(agent=agent, edge=edge) self.time += moving_time # add total time of simulator # if deadline has passed, return if self.time > self.deadline: return False if agent.observation.is_house(agent.vertex): agent.pick_up() elif agent.get_people_in_car() > 0: # if in a Shelter vertex agent.drop_off() return True # time it takes to traverse on 'edge' def calculate_price(self, agent, edge): w = edge.weight k = self.state.get_slow_down() p = agent.get_people_in_car() return w * (1 + k * p) # Do a 1step for a Human & Greedy Agent def do_agent(self, agent): next_move = agent.do() # do action for Human Agent agent.add_action(next_move) if next_move == 'NOP': self.time += 1 else: # Traverse if next_move[0].upper() != 'T': raise Exception('Unknown action') dest = int(next_move[1:]) # number of the destination vertex edge_to_traverse = self.state.get_edge(agent.vertex, dest) return self.move_agent_to(agent=agent, edge=edge_to_traverse, dest=dest) # input in the format of : H1 G3; <Type|Vertex> def get_agents_data(self, world, agent_file=None): num_human = 0 num_gamers = 0 agents = [] if agent_file is not None: with open(agent_file) as agents_file: for line in agents_file.readlines(): for agent_symbol in line.split(): vertex_number = int(agent_symbol[1:]) choice = 'MAX' if len(agents) == 0 else 'MIN' if agent_symbol.upper().startswith('H'): name = 'Human-{}'.format(str(num_human)) agent = Human(world=world, name=name, init_vertex=vertex_number, choice=choice) agents.append(agent) num_human += 1 elif agent_symbol.upper().startswith('G'): choice = 'MAX' if len(agents) == 0 else 'MIN' name = 'Gamer-{}'.format(str(num_gamers)) agent = GameTreeAgent(world=world, name=name, init_vertex=vertex_number, choice=choice) agents.append(agent) num_gamers += 1 return agents # prompt the user for the K - slow down constant def prompt_k(self): k = float(input('Enter the slow-down constant: ')) # 0 < K < 1 if 0 < k <= 1: return k raise Exception('K must be in range (0,1)') # create a path of states from the final node. the path is the agent's actions. def get_state_path(self, final_node): path = [final_node] if final_node == 'FAILURE': return ['FAILURE'] runner_node = final_node.parent while runner_node is not None: path.insert(0, runner_node) runner_node = runner_node.parent return path # get the number of people saved by the Agent def get_score_from_path(self, state_path): score = 0 for i in range(len(state_path))[1:]: in_car = state_path[i].get_people_in_car() # if 0 people in car, it means last state was a drop-off if in_car is 0: score += state_path[i - 1].get_people_in_car() return score def print_run(self): if len(self.agents_history) is 0: print('Nothing to print!') return for agent, state_path in self.agents_history: actions = [node.action for node in state_path] score = self.get_score_from_path(state_path) expands = self.agents[-1].expands p = self.f_constant * score + expands print('**********\nShowing steps of {}.\nscore:{}\nExpands:{}'. format(agent, score, expands)) print('Performance: {} = {} * {} + {}'.format( p, self.f_constant, score, expands)) print('Final State: {}\n\n'.format(state_path[len(state_path) - 1].state)) print('Action Trace:\n {}\n'.format(actions)) # create a state for 2 agent problem def create_init_states(self, world, agents): state = dict() for agent in agents: people = world.get_vertex_for_tag( agent.vertex).people if world.is_house(agent.vertex) else 0 state[agent.name] = { 'position': agent.vertex, 'people_in_car': people, 'people_saved': 0 } state['time'] = 0 return state # run each agent in turn. in case of human agent, CHANGE the parent according to the human's choice. def run(self): print('initial state : {}'.format(self.game_tree.root.get_state())) node = self.game_tree.root i = 0 # first agent to "run" while node.type is not 'CUTOFF' and node.type is not 'TERMINAL': agent = self.agents[i] action = agent.get_move(node) # update to next node for child in node.children: if child.action == action: child.parent = node node = child state_path = self.get_state_path(node) print('path here : {}'.format([n.action for n in state_path])) print( '------\nagent:{} action {}\ntime: {}\nminimax value: {}\nstate: {}\n------\n' .format(agent.name, action, node.get_time(), node.get_minimax_value(), node.get_state())) # next agent i = (i + 1) % len(self.agents) def run_ping_pong(self): turn = 0 actions = [] visited = [] state = self.create_init_states(self.world, self.agents) visited.append( state[self.agents[0].name]['position']) # append initial positions visited.append( state[self.agents[1].name]['position']) # append initial positions while True: current_agent = self.agents[turn] if isinstance(current_agent, Human): result_node = current_agent.get_move(state=state, visited=visited, world=self.world) else: result_node = current_agent.get_move_new_tree( state=state, visited=visited, world=self.world, cutoff_depth=self.cutoff_depth, mode=self.mode) actions.append(result_node.action) visited.append(result_node.get_position(current_agent.name)) visited.append(result_node.get_position(current_agent.name)) print('path here : {}'.format(actions)) print( '------\nagent:{} action {}\ntime: {}\nminimax value: {}\nstate: {}\n------\n' .format(self.agents[turn].choice, result_node.action, result_node.get_time(), result_node.get_minimax_value(), result_node.get_state())) if result_node.type == 'CUTOFF' or result_node.type == 'TERMINAL': print("final state: {}".format(result_node.get_state())) break turn = (turn + 1) % len(self.agents) # next agent's turn state = result_node.get_state() result_node = None
class HurricaneEvacuationSimulator(object): def __init__(self, graph_file, start_vertex): self.graph_file = graph_file self.world = World(graph_file=graph_file) self.deadline = self.world.get_deadline() self.shelter_tag = self.world.get_shelter_tag() # create agent self.start_vertex = start_vertex self.time = 0 # track time of the world self.evacuated = 0 # total number of people evacuated self.belief_space = self.init_belief_space() self.val_iterator = ValueIteration(self.belief_space, self.world) self.utilities = self.val_iterator.value_iteration() print(self.utilities.values()) # initialize the belief space for the graph def init_belief_space(self): bs = BeliefSpace(self.world, init_vertex=int(args.start_vertex)) bs.create_all_belief_states(self.start_vertex) return bs # generate all possible blockage combinations def all_blockage_instances(self): # edge that can be blocked maybe_blocked = map( lambda e: e.edge_num, filter(lambda e: e.prob_blockage > 0, self.world.get_edges(one_way=True))) blockages = set(product({True, False}, repeat=len(maybe_blocked))) return [dict(zip(maybe_blocked, blockage)) for blockage in blockages] def random_blockage(self): # blockable edges blockables = map( lambda e: e.edge_num, filter(lambda e: e.prob_blockage > 0, self.world.get_edges(one_way=True))) # NONE at first blockage_dict = {key: None for key in blockables} for e in blockage_dict: prob = self.world.get_edge_for_num(e).prob_blockage blockage_dict[e] = self.true_in_prob(prob) return blockage_dict # return 'True' in probability of 'prob' def true_in_prob(self, prob): rand = random.random() return True if rand <= prob else False def run_an_agent(self, times=10000): util_acc = 0.0 init_s = None for i in range(times): blockage_instance = self.random_blockage() init_states = self.belief_space.init_states # remove from init state/s init_state = filter( lambda d: self.consistent_state(d, blockage_instance), init_states)[0] init_s = init_state agent = PlanningAgent(world=self.world, belief_space=self.belief_space, utilities=self.utilities, \ init_state=init_state, init_vertex=self.start_vertex, blockage=blockage_instance) next_state = agent.state while not self.belief_space.goal_state(next_state) and not (len( next_state.successors) == 0): next_state = agent.do() util_acc += self.utilities[ next_state] #self.belief_space.states.index(next_state)] print('i: {}\nacc: {}'.format(i, util_acc)) #print('accumulated: {}'.format(util_acc)) print('average: {}'.format(util_acc / times)) print('init value: {}'.format( self.utilities[self.belief_space.states[0]])) def consistent_state(self, belief_state, blockage_instance): state_blocked = belief_state.blocked_edges for edge_num in state_blocked: if blockage_instance[edge_num] != state_blocked[edge_num]: return False return True
class Main(object): def __init__(self, graph_file): self.graph_file = graph_file self.world = World(graph_file=graph_file) self.deadline = self.world.get_deadline() self.bayes_network = BayesNetwork(world=self.world) self.reports = {} def clear_screen(self, stupid=False): if stupid: print('\n') * 100 else: os.system('cls' if os.name == 'nt' else 'clear') def get_numbers(self, prompt, smallest, biggest): while True: choice = raw_input(prompt).split() if 'exit' in choice or 'quit' in choice or 'q' in choice: exit() elif not any( int(x) < smallest or int(x) > biggest for x in choice) and not len(choice) == 0: # self.clear_screen(stupid=True) return choice else: # self.clear_screen(stupid=True) print('illegal input.') return False # get query evidence from user def prompt_query_evidence(self): all_reports = {} num_edges = len(self.world.get_edges(one_way=True)) num_vertices = len(self.world.get_vertices()) report_prompt = 'What would you like to report? \n 1. Flood\n 2. Blockage\n 3. Evacuees\n-------\n ' \ '4. No Flood\n 5. No Blockage\n 6. No Evacuees\n-------\n 7. Non-Blocked Path\n 8. Print Reasoning\n 9. Bonus\n 10. Reset\n choice: ' short_report_prompt = '\nAnother report?' blockage_prompt = 'report Blocking at edges : range-({},{}) '.format( 1, num_edges) flooding_prompt = 'report Flooding at vertices range-({},{}) : '.format( 1, num_vertices) evacuees_prompt = 'report Evacuees at vertices range-({},{}): '.format( 1, num_vertices) non_blockage_prompt = 'report NON Blocking at edges : range-({},{}) '.format( 1, num_edges) non_flooding_prompt = 'report NON Flooding at vertices range-({},{}) : '.format( 1, num_vertices) non_evacuees_prompt = 'report NON Evacuees at vertices range-({},{}): '.format( 1, num_vertices) iteration = 0 while True: iteration += 1 print( '\n----------------\nReported so far : \n{}\n----------------' .format(all_reports)) if iteration is 1: report_choice = int( self.get_numbers(report_prompt, smallest=1, biggest=10)[0]) else: report_choice = int( self.get_numbers(short_report_prompt, smallest=1, biggest=10)[0]) if report_choice == 1: floodings = set( self.get_numbers(flooding_prompt, smallest=1, biggest=num_vertices)) floodings = set(['flooding ' + str(num) for num in floodings]) for report in floodings: all_reports[report] = True elif report_choice == 2: blockages = set( self.get_numbers(blockage_prompt, smallest=1, biggest=num_edges)) blockages = set(['blockage ' + str(num) for num in blockages]) for report in blockages: all_reports[report] = True elif report_choice == 3: evacuees = set( self.get_numbers(evacuees_prompt, smallest=1, biggest=num_vertices)) evacuees = set(['evacuees ' + str(num) for num in evacuees]) for report in evacuees: all_reports[report] = True elif report_choice == 4: floodings = set( self.get_numbers(non_flooding_prompt, smallest=1, biggest=num_vertices)) floodings = set(['flooding ' + str(num) for num in floodings]) for report in floodings: all_reports[report] = False elif report_choice == 5: blockages = set( self.get_numbers(non_blockage_prompt, smallest=1, biggest=num_edges)) blockages = set(['blockage ' + str(num) for num in blockages]) for report in blockages: all_reports[report] = False elif report_choice == 6: evacuees = set( self.get_numbers(non_evacuees_prompt, smallest=1, biggest=num_vertices)) evacuees = set(['evacuees ' + str(num) for num in evacuees]) for report in evacuees: all_reports[report] = False elif report_choice == 7: print('Overall Reported: {}'.format(all_reports)) prompt = 'Enter a set of Edges as a path. range-({},{}) '.format( 1, num_edges) path = set( int(n) for n in self.get_numbers( prompt, smallest=1, biggest=num_edges)) if len(path) > 1: self.reports = all_reports p = self.get_probability_path_free(path) non_blocked = ', '.join( ['not blockage {}'.format(str(e)) for e in path]) given = self.evidence_as_string(all_reports) s = 'P({of} | {given} ) = {p}'.format(of=non_blocked, given=given, p=p) print(s) else: print('A single edge can computed normally') elif report_choice == 8: print('Overall Reported: {}'.format(all_reports)) self.reports = all_reports self.perform_reasoning() elif report_choice == 9: self.reports = all_reports print('Overall Reported: {}'.format(all_reports)) prompt = 'Enter a source Vertex and a Destination Vertex. range-({},{}) '.format( 1, num_vertices) user_input = [ int(n) for n in self.get_numbers( prompt, smallest=1, biggest=num_vertices) ] if len(user_input) is not 2: print('usage : <source> <destination>') else: self.reports = all_reports self.do_bonus(source=user_input[0], destination=user_input[1]) elif report_choice == 10: all_reports = dict() # print the network def print_network(self): self.bayes_network.print_network() def perform_reasoning(self): self.query_type('evacuees') self.query_type('flooding') self.query_type('blockage') def query_type(self, node_type, for_print=True): nodes = self.bayes_network.get_nodes_of_type(node_type) vals = [] for node in nodes: # self.enumerate_prob(node) if node.node_type != 'blockage': vals.append((node.get_vertex().tag, self.enumerate_prob(node))) else: vals.append( (node.get_edge().edge_num, self.enumerate_prob(node))) return vals def do_bonus(self, source, destination): paths = self.world.all_paths(source=source, destination=destination) probabilities = [self.get_probability_path_free(p) for p in paths] print( 'Printing the Probability of free from blockages - path from {} to {} :' .format(source, destination)) min_path = ([], 0.0) for (path, prob) in zip(paths, probabilities): if prob >= min_path[1]: min_path = (path, prob) print('Path: {} , Probability(free) = {}'.format(path, prob)) print('\n===========================\n') if min_path[1] == 0.0: print('all paths from {} to {} are blocked with probability 1'. format(source, destination)) else: print('Best path is : {} with probability {}'.format( min_path[0], min_path[1])) # and print def enumerate_prob(self, node): enumerator = Enumerator(query_var=node, evidence=self.reports, network=self.bayes_network) p = enumerator.pretty_string(query_value=True) p_val = enumerator.enumeration_ask() s = p + str(p_val[0]) print(s) # print("\n") return p_val[0] def get_probability_path_free(self, path): reported_evidence = self.reports.copy() query_vars = filter(lambda n: n.get_edge().edge_num in path, self.bayes_network.get_nodes_of_type('blockage')) multi_query = MultiQuery(query_vars=query_vars, evidence=reported_evidence, network=self.bayes_network) # vars_true is False - we want blockages to be false. p = multi_query.query_to_value(vars_true=False) return p def evidence_as_string(self, evidence): s = '' for e in evidence.keys(): if s != '': s += ',' if evidence[e]: s += e else: s += 'not ' + e return s