コード例 #1
0
ファイル: model.py プロジェクト: o-date/abm
class BoltzmannWealthModelNetwork(Model):
    """A model with some number of agents."""

    def __init__(self, num_agents=7, num_nodes=10):

        self.num_agents = num_agents
        self.num_nodes = num_nodes if num_nodes >= self.num_agents else self.num_agents
        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=0.5)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.datacollector = DataCollector(
            model_reporters={"Gini": compute_gini},
            agent_reporters={"Wealth": lambda _: _.wealth}
        )

        list_of_random_nodes = random.sample(self.G.nodes(), self.num_agents)

        # Create agents
        for i in range(self.num_agents):
            a = MoneyAgent(i, self)
            self.schedule.add(a)
            # Add the agent to a random node
            self.grid.place_agent(a, list_of_random_nodes[i])

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
コード例 #2
0
class COVID_model(Model):
    def __init__(self):
        super().__init__(Model)

        self.susceptible = 0
        self.dead = 0
        self.recovered = 0
        self.infected = 0
        interactions = model_params.parameters['interactions']
        self.population = model_params.parameters['population']
        self.SIR_instance = SIR.Infection(
            self,
            ptrans=model_params.parameters['ptrans'],
            reinfection_rate=model_params.parameters['reinfection_rate'],
            I0=model_params.parameters["I0"],
            severe=model_params.parameters["severe"],
            progression_period=model_params.parameters["progression_period"],
            progression_sd=model_params.parameters["progression_sd"],
            death_rate=model_params.parameters["death_rate"],
            recovery_days=model_params.parameters["recovery_days"],
            recovery_sd=model_params.parameters["recovery_sd"])

        G = SIR.build_network(interactions, self.population)
        self.grid = NetworkGrid(G)
        self.schedule = RandomActivation(self)
        self.dead_agents = []
        self.running = True

        for node in range(self.population):
            new_agent = agent.human(node, self)  #what was self.next_id()
            self.grid.place_agent(new_agent, node)
            self.schedule.add(new_agent)

        #self.meme = 0
        self.datacollector = DataCollector(
            model_reporters={
                "infected": lambda m: c_p.compute(m, 'infected'),
                "recovered": lambda m: c_p.compute(m, 'recovered'),
                "susceptible": lambda m: c_p.compute(m, "susceptible"),
                "dead": lambda m: c_p.compute(m, "dead"),
                "R0": lambda m: c_p.compute(m, "R0"),
                "severe_cases": lambda m: c_p.compute(m, "severe")
            })
        self.datacollector.collect(self)

    def step(self):
        self.schedule.step()

        self.datacollector.collect(self)
        '''
        for a in self.schedule.agents:
            if a.alive == False:
                self.schedule.remove(a)
                self.dead_agents.append(a.unique_id)
        '''

        if self.dead == self.schedule.get_agent_count():
            self.running = False
        else:
            self.running = True
コード例 #3
0
class NormModel(Model):
    def __init__(self, size):
        self.num_agents = size
        self.num_nodes = self.num_agents
        # self.G = the_network[0]
        self.G = another_network
        self.grid = NetworkGrid(self.G)
        self.schedule = SimultaneousActivation(self)
        self.running = True

        for i, node in enumerate(self.G.nodes()):
            a = NormAgent(i, self)
            self.schedule.add(a)
            self.grid.place_agent(a, node)

        self.datacollector = DataCollector(
            model_reporters={
                "PerHate": percent_haters,
                "AverageSens": average_sensitivity,
            },
            agent_reporters={"Hate": "behavior"})

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
        if percent_haters(
                self
        ) > 0.8:  # When the percentage of haters in the model exceeds 80,
            self.running = False  # the simulation is stopped, data collected, and next one is started.
コード例 #4
0
ファイル: model.py プロジェクト: bangtree/mesa
class BoltzmannWealthModelNetwork(Model):
    """A model with some number of agents."""

    def __init__(self, num_agents=7, num_nodes=10):

        self.num_agents = num_agents
        self.num_nodes = num_nodes if num_nodes >= self.num_agents else self.num_agents
        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=0.5)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.datacollector = DataCollector(
            model_reporters={"Gini": compute_gini},
            agent_reporters={"Wealth": lambda _: _.wealth}
        )

        list_of_random_nodes = self.random.sample(self.G.nodes(), self.num_agents)

        # Create agents
        for i in range(self.num_agents):
            a = MoneyAgent(i, self)
            self.schedule.add(a)
            # Add the agent to a random node
            self.grid.place_agent(a, list_of_random_nodes[i])

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
コード例 #5
0
class propagation_model(Model):
    
    def __init__(self):
        super().__init__(Model)
        
        density = model_params.parameters['density']
        nodes = model_params.parameters['network_size']
        neg_bias = model_params.parameters['neg_bias']
        meme_density = model_params.parameters['meme_density']
        self.num_agents = nodes
        self.meme = 0
        
        G = model_functions.build_network(density, nodes)
        self.grid = NetworkGrid(G)
        self.schedule = RandomActivation(self)
        
        self.running = True
    
        for node in range(nodes):
            new_agent = agent.tweeter(self.next_id(), node, self, neg_bias, meme_density)
            self.grid.place_agent(new_agent, node)
            self.schedule.add(new_agent)
    
        #self.meme = 0
        self.datacollector = DataCollector(model_reporters={"meme_density": model_functions.compute_meme_density})
        self.datacollector.collect(self)
    
    def step(self):
        self.schedule.step()
        
        self.datacollector.collect(self)
        
        if self.meme == self.schedule.get_agent_count():
            self.running = False
コード例 #6
0
class OpinionNetwork(Model):
    '''An opinion model with N agents on an Erdos-Renyi network.'''
    def __init__(self, N, avg_node_degree, rule='CMR', zero_prob=0.5):
        self.num_agents = N
        self.rule = rule
        self.schedule = RandomActivation(self)
        prob = avg_node_degree / self.num_agents
        self.G = nx.erdos_renyi_graph(n=self.num_agents, p=prob)
        self.grid = NetworkGrid(self.G)

        #create the agents
        for i, node in enumerate(self.G.nodes()):
            a = OpinionAgent(
                i,
                self,
                initial_opinion=self.random.choices(
                    [0, 1], weights=[zero_prob, 1 - zero_prob],
                    k=1)[0])  #we can seed w/a non-equal probability
            self.schedule.add(a)
            self.grid.place_agent(a, node)

        self.datacollector = DataCollector(model_reporters={
            'opinion_0': opinion_0_ct,
            'opinion_1': opinion_1_ct
        })

        self.running = True  #we could check to see if we've reached a steady state
        self.datacollector.collect(self)

    def step(self):
        self.schedule.step()  #each agent gets a step
        self.datacollector.collect(self)  #collect data
コード例 #7
0
class TestSingleNetworkGrid(unittest.TestCase):
    GRAPH_SIZE = 10

    def setUp(self):
        '''
        Create a test network grid and populate with Mock Agents.
        '''
        G = nx.complete_graph(TestSingleNetworkGrid.GRAPH_SIZE)
        self.space = NetworkGrid(G)
        self.agents = []
        for i, pos in enumerate(TEST_AGENTS_NETWORK_SINGLE):
            a = MockAgent(i, None)
            self.agents.append(a)
            self.space.place_agent(a, pos)

    def test_agent_positions(self):
        '''
        Ensure that the agents are all placed properly.
        '''
        for i, pos in enumerate(TEST_AGENTS_NETWORK_SINGLE):
            a = self.agents[i]
            assert a.pos == pos

    def test_get_neighbors(self):
        assert len(self.space.get_neighbors(
            0, include_center=True)) == TestSingleNetworkGrid.GRAPH_SIZE
        assert len(self.space.get_neighbors(
            0, include_center=False)) == TestSingleNetworkGrid.GRAPH_SIZE - 1

    def test_move_agent(self):
        initial_pos = 1
        agent_number = 1
        final_pos = TestSingleNetworkGrid.GRAPH_SIZE - 1

        _agent = self.agents[agent_number]

        assert _agent.pos == initial_pos
        assert _agent in self.space.G.node[initial_pos]['agent']
        assert _agent not in self.space.G.node[final_pos]['agent']
        self.space.move_agent(_agent, final_pos)
        assert _agent.pos == final_pos
        assert _agent not in self.space.G.node[initial_pos]['agent']
        assert _agent in self.space.G.node[final_pos]['agent']

    def test_is_cell_empty(self):
        assert not self.space.is_cell_empty(0)
        assert self.space.is_cell_empty(TestSingleNetworkGrid.GRAPH_SIZE - 1)

    def test_get_cell_list_contents(self):
        assert self.space.get_cell_list_contents([0]) == [self.agents[0]]
        assert self.space.get_cell_list_contents(
            list(range(TestSingleNetworkGrid.GRAPH_SIZE))) == [
                self.agents[0], self.agents[1], self.agents[2]
            ]

    def test_get_all_cell_contents(self):
        assert self.space.get_all_cell_contents() == [
            self.agents[0], self.agents[1], self.agents[2]
        ]
コード例 #8
0
ファイル: model.py プロジェクト: eescriba/smart-cities-drl
class WasteNet(Model):
    """Waste collection network model"""
    def __init__(self, mode, nb_nodes=10, nb_episodes=1):

        # Network
        self.G = generate_graph(nb_nodes)
        self.grid = NetworkGrid(self.G)

        # Gym Environment
        env_config = dict(graph=self.G)
        self.env = WasteNetEnv(env_config)

        # RL Agent
        if mode == WasteNetMode.PPO.name:
            rl_agent = PPOAgent("WasteNet", WasteNetEnv, env_config,
                                best_config)
            rl_agent.load("./checkpoints/checkpoint-best")
        else:
            rl_agent = None

        # Scheduler
        self.schedule = WasteNetActivation(self, mode, rl_agent)

        # Data Collector
        self.datacollector = DataCollector(
            model_reporters={
                "Empty": nb_empty,
                "Medium": nb_medium,
                "Full": nb_full,
                "Overflow": nb_overflow,
            },
            agent_reporters={
                "Fill level (%)": fill_level,
                "": lambda a: 100
            },
        )

        # Mesa Agents
        for i, node in enumerate(self.G.nodes()):
            if i in (0, self.G.number_of_nodes() - 1):
                a = BaseAgent(i, self)
            else:
                a = DumpsterAgent(i, self, self.env.fill_levels[i - 1])
            self.schedule.add(a)
            self.grid.place_agent(a, node)

        self.remaining_episodes = nb_episodes
        self.running = True
        self.datacollector.collect(self)

    def step(self):
        done = self.schedule.step()
        self.datacollector.collect(self)
        if done:
            self.env.reset()
            self.remaining_episodes -= 1
        if self.remaining_episodes == 0:
            self.running = False
コード例 #9
0
ファイル: model.py プロジェクト: joekroese/math-of-revolution
class VirusModel(Model):
    """A virus model with some number of agents"""
    def __init__(self, num_nodes, avg_node_degree, initial_outbreak_size,
                 alpha, beta, gamma, k, n):

        self.num_nodes = num_nodes
        self.avg_node_degree = avg_node_degree
        self.G = nx.barabasi_albert_graph(n=self.num_nodes, m=avg_node_degree)
        # _graph(n=self.num_nodes, p=prob)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.initial_outbreak_size = initial_outbreak_size if initial_outbreak_size <= num_nodes else num_nodes
        self.alpha = alpha
        self.beta = beta
        self.gamma = gamma

        self.k = k
        self.n = n

        self.datacollector = DataCollector({
            "Infected": number_active,
            "Susceptible": number_susceptible,
            "Carrier": number_inactive,
            "Removed": number_removed
        })
        # Create agents
        for i, node in enumerate(self.G.nodes()):
            a = VirusAgent(i, self, State.SUSCEPTIBLE, self.alpha, self.beta,
                           self.gamma, self.k, self.n)
            self.schedule.add(a)
            # Add the agent to the node
            self.grid.place_agent(a, node)

        # Infect some nodes
        active_nodes = random.sample(self.G.nodes(),
                                     self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(active_nodes):
            a.state = State.ACTIVE

        self.running = True
        self.datacollector.collect(self)

    def removed_susceptible_ratio(self):
        try:
            return number_state(self, State.REMOVED) / number_state(
                self, State.SUSCEPTIBLE)
        except ZeroDivisionError:
            return math.inf

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
コード例 #10
0
class VirusModel(Model):
    """A virus model with some number of agents"""
    def __init__(self, num_nodes, avg_node_degree, initial_outbreak_size,
                 virus_spread_chance, virus_check_frequency, recovery_chance,
                 gain_resistance_chance):

        self.num_nodes = num_nodes
        prob = avg_node_degree / self.num_nodes
        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.initial_outbreak_size = initial_outbreak_size if initial_outbreak_size <= num_nodes else num_nodes
        self.virus_spread_chance = virus_spread_chance
        self.virus_check_frequency = virus_check_frequency
        self.recovery_chance = recovery_chance
        self.gain_resistance_chance = gain_resistance_chance

        self.datacollector = DataCollector({
            "Infected": number_infected,
            "Susceptible": number_susceptible,
            "Resistant": number_resistant
        })

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            a = VirusAgent(i, self, State.SUSCEPTIBLE,
                           self.virus_spread_chance,
                           self.virus_check_frequency, self.recovery_chance,
                           self.gain_resistance_chance)
            self.schedule.add(a)
            # Add the agent to the node
            self.grid.place_agent(a, node)

        # Infect some nodes
        infected_nodes = random.sample(self.G.nodes(),
                                       self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.state = State.INFECTED

        self.running = True
        self.datacollector.collect(self)

    def resistant_susceptible_ratio(self):
        try:
            return number_state(self, State.RESISTANT) / number_state(
                self, State.SUSCEPTIBLE)
        except ZeroDivisionError:
            return math.inf

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
コード例 #11
0
class VirusModel(Model):
    def __init__(self, num_nodes, avg_node_degree, initial_outbreak_size,
                 alpha, beta):
        self.num_nodes = num_nodes
        prob = avg_node_degree / self.num_nodes
        self.initial_outbreak_size = initial_outbreak_size if initial_outbreak_size <= num_nodes else num_nodes
        self.alpha = alpha
        self.beta = beta

        self.G = nx.barabasi_albert_graph(n=self.num_nodes, m=3)
        # self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob)
        self.grid = NetworkGrid(self.G)

        self.schedule = RandomActivation(self)

        self.datacollector = DataCollector({
            "Susceptible": number_susceptible,
            "Infected": number_infected,
            "Removed": number_removed
        })

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            a = VirusAgent(
                i,
                self,
                State.SUSCEPTIBLE,
                self.alpha,
                self.beta,
            )
            self.schedule.add(a)
            self.grid.place_agent(a, node)

        # Infect some nodes
        infected_nodes = random.sample(self.G.nodes(),
                                       self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.state = State.INFECTED

        self.running = True
        self.datacollector.collect(self)

    def removed_susceptible_ratio(self):
        try:
            return number_state(self, State.REMOVED) / number_state(
                self, State.SUSCEPTIBLE)
        except ZeroDivisionError:
            return math.inf

    def step(self):
        self.schedule.step()
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
コード例 #12
0
ファイル: test_space.py プロジェクト: bangtree/mesa
class TestSingleNetworkGrid(unittest.TestCase):
    GRAPH_SIZE = 10

    def setUp(self):
        '''
        Create a test network grid and populate with Mock Agents.
        '''
        G = nx.complete_graph(TestSingleNetworkGrid.GRAPH_SIZE)
        self.space = NetworkGrid(G)
        self.agents = []
        for i, pos in enumerate(TEST_AGENTS_NETWORK_SINGLE):
            a = MockAgent(i, None)
            self.agents.append(a)
            self.space.place_agent(a, pos)

    def test_agent_positions(self):
        '''
        Ensure that the agents are all placed properly.
        '''
        for i, pos in enumerate(TEST_AGENTS_NETWORK_SINGLE):
            a = self.agents[i]
            assert a.pos == pos

    def test_get_neighbors(self):
        assert len(self.space.get_neighbors(0, include_center=True)) == TestSingleNetworkGrid.GRAPH_SIZE
        assert len(self.space.get_neighbors(0, include_center=False)) == TestSingleNetworkGrid.GRAPH_SIZE - 1

    def test_move_agent(self):
        initial_pos = 1
        agent_number = 1
        final_pos = TestSingleNetworkGrid.GRAPH_SIZE - 1

        _agent = self.agents[agent_number]

        assert _agent.pos == initial_pos
        assert _agent in self.space.G.node[initial_pos]['agent']
        assert _agent not in self.space.G.node[final_pos]['agent']
        self.space.move_agent(_agent, final_pos)
        assert _agent.pos == final_pos
        assert _agent not in self.space.G.node[initial_pos]['agent']
        assert _agent in self.space.G.node[final_pos]['agent']

    def test_is_cell_empty(self):
        assert not self.space.is_cell_empty(0)
        assert self.space.is_cell_empty(TestSingleNetworkGrid.GRAPH_SIZE - 1)

    def test_get_cell_list_contents(self):
        assert self.space.get_cell_list_contents([0]) == [self.agents[0]]
        assert self.space.get_cell_list_contents(list(range(TestSingleNetworkGrid.GRAPH_SIZE))) == [self.agents[0],
                                                                                                    self.agents[1],
                                                                                                    self.agents[2]]

    def test_get_all_cell_contents(self):
        assert self.space.get_all_cell_contents() == [self.agents[0],
                                                      self.agents[1],
                                                      self.agents[2]]
コード例 #13
0
class Population(Model):
    """Population
    Adapted from https://www.medrxiv.org/content/10.1101/2020.03.18.20037994v1.full.pdf

    Model Parameters:
    spread_chance: probability of infection based on contact
    gamma: mean incubation period
    alpha: probability of become asymptomatic vs symptomatic
    gamma_AR: infectious period for asymptomatic people
    gamma_YR: infectious period for symptomatic people
    delta: death rate due to disease
    """
    def __init__(self, graph, model_parameters):

        # Model initialization
        self.population_size = model_parameters['population_size']
        self.initial_outbreak_size = model_parameters['initial_outbreak_size']
        self.graph = graph
        self.grid = NetworkGrid(self.graph)
        self.schedule = SimultaneousActivation(self)

        self.datacollector = DataCollector({
            "Exposed": count_exposed,
            "Susceptible": count_susceptible,
            "Removed": count_removed,
            "Asymptomatic": count_asymptomatic,
            "Symptomatic": count_symptomatic
        })
        self.model_parameters = model_parameters

        for i, node in enumerate(self.graph.nodes()):
            a = Person(i, self, State.SUSCEPTIBLE, model_parameters)
            self.schedule.add(a)
            self.grid.place_agent(a, i)
            if i % 100 == 0:
                logger.info("Finished with agent " + str(i))

        infected_nodes = self.random.sample(self.graph.nodes(),
                                            self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.status = State.EXPOSED

        self.datacollector.collect(self)
        print("Model initialized...\n", str(self.model_parameters))

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()

    def run(self, n):
        for i in range(n):
            #logger.info("Steps Completed: " + str(i))
            #print("Steps completed: ", i)
            self.step()
コード例 #14
0
class PopuNetwork(Model):
    """
    The population network which initializes:
    - the number of agents
    - the number of incarcerated agents at start
    - the race of the simulated community
    - the average number of relationships per individual
    """
    def __init__(self,
                 num_nodes=1000,
                 avg_node_degree=3,
                 initial_outbreak_size=10,
                 race="black"):
        self.num_nodes = num_nodes
        self.race = race
        self.months = 0
        prob = avg_node_degree / self.num_nodes

        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob)
        self.sentence = generate_sentence(race)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.initial_outbreak_size = initial_outbreak_size if initial_outbreak_size <= num_nodes else num_nodes

        self.datacollector = DataCollector({
            "Incarcerated": number_incarcerated,
            "Susceptible": number_susceptible,
            "Released": number_released
        })

        for i, node in enumerate(self.G.nodes()):
            a = Person(i, self, State.SUSCEPTIBLE, self.sentence)
            self.schedule.add(a)
            self.grid.place_agent(a, node)

        # Begin with some portion of the population in prison
        infected_nodes = self.random.sample(self.G.nodes(),
                                            self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.state = State.INCARCERATED

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        self.schedule.step()
        self.months += 1
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
コード例 #15
0
ファイル: model.py プロジェクト: bangtree/mesa
class VirusOnNetwork(Model):
    """A virus model with some number of agents"""

    def __init__(self, num_nodes=10, avg_node_degree=3, initial_outbreak_size=1, virus_spread_chance=0.4,
                virus_check_frequency=0.4, recovery_chance=0.3, gain_resistance_chance=0.5):

        self.num_nodes = num_nodes
        prob = avg_node_degree / self.num_nodes
        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.initial_outbreak_size = initial_outbreak_size if initial_outbreak_size <= num_nodes else num_nodes
        self.virus_spread_chance = virus_spread_chance
        self.virus_check_frequency = virus_check_frequency
        self.recovery_chance = recovery_chance
        self.gain_resistance_chance = gain_resistance_chance

        self.datacollector = DataCollector({"Infected": number_infected,
                                            "Susceptible": number_susceptible,
                                            "Resistant": number_resistant})

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            a = VirusAgent(i, self, State.SUSCEPTIBLE, self.virus_spread_chance, self.virus_check_frequency,
                           self.recovery_chance, self.gain_resistance_chance)
            self.schedule.add(a)
            # Add the agent to the node
            self.grid.place_agent(a, node)

        # Infect some nodes
        infected_nodes = self.random.sample(self.G.nodes(), self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.state = State.INFECTED

        self.running = True
        self.datacollector.collect(self)

    def resistant_susceptible_ratio(self):
        try:
            return number_state(self, State.RESISTANT) / number_state(self, State.SUSCEPTIBLE)
        except ZeroDivisionError:
            return math.inf

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
コード例 #16
0
class NormModel(Model):
    def __init__(self, size, type_no, subset_no):
        self.num_agents = size
        self.num_nodes = self.num_agents
        self.set = str(type_no)
        self.subset = subset_no
        self.I = networks_for_use[self.set][self.subset][0]
        # self.type = str(self.set)
        self.avg_deg = networks_for_use[self.set][self.subset][1][
            0]  # 1st parameter - average node degree
        self.big_nodes = networks_for_use[self.set][self.subset][1][
            1]  # 2nd parameter - degree of highest-degree node
        self.connectivity = networks_for_use[self.set][self.subset][1][
            2]  # 3rd parameter - mean network connectivity
        self.clustering = networks_for_use[self.set][self.subset][1][
            3]  # Network's clustering coeff.
        self.grid = NetworkGrid(self.I)
        self.schedule = SimultaneousActivation(self)
        self.running = True
        self.step_counter = 1

        for i, node in enumerate(self.I.nodes()):
            a = NormAgent(i, self)
            self.schedule.add(a)
            self.grid.place_agent(a, node)

        print(f"processing network number {self.subset+1}, type {self.set}")

        self.datacollector = DataCollector(
            model_reporters={
                "PerHate": percent_haters,
                "NetworkType": network_type,
                "AveSensitivity": average_sensitivity,
                "MeanDeg": net_avg_deg,
                "MaxDeg": net_max_deg,
                "NetConnect": net_conn,
                "NetClust": net_clust,
                "FinalStep": final_step,
            },
            # agent_reporters={"Hate": "behavior"}
        )

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
        self.step_counter += 1
        if average_sensitivity(self) < 0.1 or self.step_counter > 250:
            self.running = False
コード例 #17
0
class DiseaseModel(Model):
    def __init__(self, N, initInfected, percInfect, percRecover, intervention):
        self.running = True
        self.num_agents = N
        self.initInfected = initInfected
        self.percInfect = percInfect
        self.percRecover = percRecover
        self.intervention = intervention

        #self.grid = nx.ErdosRenyiGraph(self.num_agents,)
        self.G = nx.complete_graph(self.num_agents)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomSingleActivation(self)

        # create and initialise agents
        for i, node in enumerate(self.G.nodes):
            a = DiseaseAgent(i, self)
            self.schedule.add(a)
            self.grid.place_agent(a, node)
        # make some agents initially infected
        for a in filter(
                lambda a: a.unique_id in initInfected, self.schedule.agents
        ):  #random.sample(self.schedule.agents, self.initInfected):
            a.infect()

        # set up data collection
        self.datacollector = DataCollector(agent_reporters={
            "State": "state",
            "Event": "event",
            "Cause": "cause"
        })

    def reset_events(self):
        for a in self.schedule.agents:
            a.event = Event.NOTHING
            a.cause = -100

    def step(self):
        self.reset_events()
        # update model
        self.schedule.step()
        # perform intervention if necessary
        if self.intervention is not None:
            self.intervention.apply(self)
        # perform data collection
        self.datacollector.collect(self)
コード例 #18
0
class Population(Model):
    """Population"""
    def __init__(self, population_size, initial_outbreak_size, spread_chance):
        print("Beginning model setup...\n")
        self.population_size = population_size
        print("Creating graph...")
        self.graph = nx.powerlaw_cluster_graph(population_size, 100, 0.5)
        #self.graph = nx.complete_graph(population_size)
        print(len(self.graph.edges))
        print("Initializing grid...")
        self.grid = NetworkGrid(self.graph)
        self.schedule = SimultaneousActivation(self)
        self.initial_outbreak_size = initial_outbreak_size
        self.spread_chance = spread_chance

        print("Initializing data collector...")
        self.datacollector = DataCollector({
            "Infected:": count_infected,
            "Susceptible:": count_susceptible,
            "Removed:": count_removed
        })

        for i, node in enumerate(self.graph.nodes()):
            a = Person(i, self, State.SUSCEPTIBLE, spread_chance)
            self.schedule.add(a)
            self.grid.place_agent(a, i)
            if i % 100 == 0:
                print("Finished with agent ", i)

        infected_nodes = self.random.sample(self.graph.nodes(),
                                            self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.status = State.INFECTED

        self.datacollector.collect(self)
        print("Model initialized...\n")

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()

    def run(self, n):
        for i in range(n):
            print("Steps completed: ", i)
            self.step()
コード例 #19
0
class COVID_model(Model):
    
    def __init__(self):
        super().__init__(Model)
        
        self.susceptible = 0
        self.dead = 0
        self.recovered = 0
        self.infected = 0
        interactions = model_params.parameters['interactions']
        population = model_params.parameters['population']
        
        self.num_agents = population
        
        G = model_functions.build_network(interactions, population)
        self.grid = NetworkGrid(G)
        self.schedule = RandomActivation(self)
        
        self.running = True
    
        for node in range(population):
            new_agent = agent.human(self.next_id(), node, self)
            self.grid.place_agent(new_agent, node)
            self.schedule.add(new_agent)
    
        #self.meme = 0
        self.datacollector = DataCollector(model_reporters={"infected": model_functions.compute_infected, 
                                                            "recovered": model_functions.compute_recovered, 
                                                            "susceptible": model_functions.compute_susceptible, 
                                                            "dead": model_functions.compute_dead, 
                                                            "R0": model_functions.compute_R0, 
                                                            "severe_cases":model_functions.compute_severe})
        self.datacollector.collect(self)
    
    def step(self):
        self.schedule.step()
        
        self.datacollector.collect(self)
        
        if self.dead == self.schedule.get_agent_count():
            self.running = False
        else:
            self.running = True
コード例 #20
0
class Network(Model):
    def __init__(self, N):
        self.num_agents = N
        self.G = nx.watts_strogatz_graph(N, 2, 0, seed=None)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)

        node_list = self.random.sample(self.G.nodes(), self.num_agents)

        for i in range(self.num_agents):
            a = agent(i, self)
            self.grid.place_agent(a, node_list[i])
            self.schedule.add(a)

    def step(self):
        self.schedule.step()

    def run_model(self, n):
        for i in range(n):
            self.step()
コード例 #21
0
ファイル: model.py プロジェクト: LordMaciek/epi_net
class NormModel(Model):
    def __init__(self, size, net_type):
        self.num_agents = size
        self.num_nodes = self.num_agents
        self.type = net_type
        if self.type == 1:
            self.G, self.avg_degree, self.big_nodes, self.connectivity, self.clustering = netgen_ba(
                100, 4)
        if self.type == 2:
            self.G, self.avg_degree, self.big_nodes, self.connectivity, self.clustering = netgen_er(
                100, .078)
        if self.type == 3:
            self.G, self.avg_degree, self.big_nodes, self.connectivity, self.clustering = netgen_rr(
                100, 4)
        self.grid = NetworkGrid(self.G)
        self.schedule = SimultaneousActivation(self)
        self.running = True
        self.step_counter = 1
        for i, node in enumerate(self.G.nodes()):
            a = NormAgent(i, self)
            self.schedule.add(a)
            self.grid.place_agent(a, node)

        self.datacollector = DataCollector(
            model_reporters={
                "PerHate": percent_haters,
                "AverageSens": average_sensitivity,
            },
            agent_reporters={"Hate": "behavior"})

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
        self.step_counter += 1
        if percent_haters(
                self
        ) > 0.35 or self.step_counter > 250:  # When the percentage of haters in the model exceeds 80,
            self.running = False  # the simulation is stopped, data collected, and next one is started.
        # Alternatively:
        if average_sensitivity(self) < 0.1 or self.step_counter > 250:
            self.running = False
コード例 #22
0
class NormModel(Model):
    def __init__(self, size, set_no):
        self.num_agents = size
        self.num_nodes = self.num_agents
        self.set = set_no
        self.I = networks_for_use[self.set][0]
        self.net_deg = networks_for_use[self.set][
            1]  # 1st parameter - average node degree
        self.big_nodes = networks_for_use[self.set][
            2]  # 2nd parameter - huge networks allowed?
        self.culling = networks_for_use[self.set][
            3]  # 3rd parameter - maximum node degree allowed. only use if
        # big_nodes = True!
        self.grid = NetworkGrid(self.I)
        self.schedule = SimultaneousActivation(self)
        self.running = True

        for i, node in enumerate(self.I.nodes()):
            a = NormAgent(i, self)
            self.schedule.add(a)
            self.grid.place_agent(a, node)

        self.datacollector = DataCollector(
            model_reporters={
                "PerHate": percent_haters,
                "AveKnowing": percent_hate_knowing,
                "AveHate": average_hate,
                "MeanDeg": net_avg_deg,
                "Culling": net_culling,
                "MaxDeg": max_deg,
            },
            agent_reporters={"Hate": "behavior"})

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
        if percent_haters(
                self
        ) > 0.8:  # When the percentage of haters in the model exceeds 80,
            self.running = False  # the simulation is stopped, data collected, and next one is started.
コード例 #23
0
class MoneyModel(Model):
    """A model with some number of agents."""

    #One agent per node

    def __init__(self, num_agents):

        self.num_agents = num_agents
        # self.G = nx.erdos_renyi_graph(n=num_agents, p=0.5)
        self.G = nx.barabasi_albert_graph(n=num_agents, m=1)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.datacollector = DataCollector(
            # model_reporters={"Gini": compute_gini},
            agent_reporters={
                "Wealth": lambda _: _.wealth,
                "Degree": lambda _: _.degree
            })

        # Create agents
        for i in range(self.num_agents):
            a = MoneyAgent(i, self)
            self.schedule.add(a)
            # Assign the agent to a node
            self.grid.place_agent(a, i)

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
コード例 #24
0
class TrollModNetwork(Model):
    """A model with some number of trolls, mods, and regular users."""

    def __init__(self, num_agents=50, percent_trolls=.10, percent_mods=.20):

        self.num_agents = num_agents
        self.num_nodes = num_agents
        self.num_trolls = int(math.floor(float(num_agents) * percent_trolls))
        self.num_mods = int(math.floor(float(num_agents) * percent_mods))
        self.num_regular = self.num_agents - (self.num_trolls + self.num_mods)
        
        
#         self.G = nx.barabasi_albert_graph(self.num_nodes, int(round(float(self.num_nodes)*0.90)), seed=11)
#         self.G = nx.barabasi_albert_graph(self.num_nodes, int(round(float(self.num_nodes)*0.10)), seed=11)
        self.G = nx.powerlaw_cluster_graph(self.num_nodes, int(round(float(self.num_nodes)*0.1)), p=0.9, seed=11)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.running = True
        
        self.datacollector = DataCollector(
            model_reporters={"Average Delta Trolling": compute_troll_delta},
            agent_reporters={"Trolling Delta": lambda _: _.trolling_received_snapshot}
        )

        list_of_random_nodes = self.random.sample(self.G.nodes(), self.num_agents)

        # Create agents
        for i in range(self.num_trolls):
            a = TrollUser(i, self)
            self.schedule.add(a)
            # Add the agent to a random node
            self.grid.place_agent(a, list_of_random_nodes[i])
        
        for i in range(self.num_trolls, self.num_trolls + self.num_mods):
            a = ModUser(i, self)
            self.schedule.add(a)
            # Add the agent to a random node
            self.grid.place_agent(a, list_of_random_nodes[i])
        
        for i in range(self.num_trolls + self.num_mods, self.num_agents):
            a = RegularUser(i, self)
            self.schedule.add(a)
            # Add the agent to a random node
            self.grid.place_agent(a, list_of_random_nodes[i])

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
コード例 #25
0
class InfectModel(Model):
    """A model with some number of agents."""
    def __init__(self, N, limit_time, infected_init, neighbors):
        self.num_agents = N
        prob = neighbors / self.num_agents
        self.G = nx.erdos_renyi_graph(n=self.num_agents, p=prob)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)

        self.datacollector = DataCollector(
            {
                "Infected": number_infected,
                "Susceptible": number_susceptible,
                "Resistant": number_resistant,
            }
        )

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            a = PeopleAgent(i,limit_time, self)
            self.schedule.add(a)
            # Add the agent to the node
            self.grid.place_agent(a, node)

        # Infect some nodes
        infected_nodes = self.random.sample(self.G.nodes(), infected_init)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.status = State.ACTIVE
        
        self.datacollector.collect(self)

    def step(self):
        '''Advance the model by one step.'''
        self.schedule.step()
        #collecting data
        self.datacollector.collect(self)
コード例 #26
0
class SPQRisiko(Model):
    """A SPQRisiko model with some number of players"""
    def __init__(self, n_players, points_limit, strategy, goal):
        super().__init__()
        self.players_goals = ["BE", "LA", "PP"
                              ]  # Definition of acronyms on `strategies.py`
        self.current_turn = 0
        self.journal = []  # Keep track of main events
        self.reinforces_by_goal = {}
        self.tris_by_goal = {}
        # How many agent players wiil be
        self.n_players = n_players if n_players <= constants.MAX_PLAYERS else constants.MAX_PLAYERS
        # How many computer players will be
        self.n_computers = constants.MAX_PLAYERS - n_players
        # Creation of player, goals and computer agents
        goals = []
        if goal == "Random":
            for i, player in enumerate(range(n_players)):
                goals.append(self.players_goals[i % 3])
        else:
            goals = [goal for i in range(self.n_players)]

        self.players = [
            Player(i,
                   computer=False,
                   strategy=self.get_strategy_setup(strategy, i),
                   goal=goals[i],
                   model=self) for i in range(self.n_players)
        ]
        for player in self.players:
            self.log("{} follows {} goal with a {} strategy".format(
                player.color, player.goal, player.strategy))
        self.computers = [
            Player(i,
                   computer=True,
                   strategy="Neutral",
                   goal=self.random.choice(self.players_goals),
                   model=self)
            for i in range(self.n_players, self.n_players + self.n_computers)
        ]
        self.points_limit = points_limit  # limit at which one player wins
        self.deck = self.create_deck()
        self.random.shuffle(self.deck)
        self.trashed_cards = []
        self.precompute_tris_reinforces_by_goal()
        # Initialize map
        self.G, self.territories_dict = self.create_graph_map()
        self.grid = NetworkGrid(self.G)
        self.datacollector = DataCollector(
            model_reporters={
                "Winner": get_winner,
                "Turn": get_winner_turn,
                "Strategy": get_player_strategy,
                "Goal": get_player_goal
            })
        # Schedule
        self.schedule = RandomActivation(self)
        # Subgraphs
        self.ground_areas = []
        self.sea_areas = []

        path = os.path.abspath((os.path.join(__file__, '..', '..')))
        # Probabilities that the attacker wins on a ground combact
        with open(path + '/matrices/atta_wins_combact.pkl', 'rb') as f:
            self.atta_wins_combact = pickle.load(f)
        # Probabilities that the attacker wins on a combact by sea
        with open(path + '/matrices/atta_wins_combact_by_sea.pkl', 'rb') as f:
            self.atta_wins_combact_by_sea = pickle.load(f)

        territories = list(range(45))
        random.shuffle(territories)
        """
        If there're 4 players, Italia must be owned by the only computer player
        """
        if self.n_players == 4:
            territories.remove(15)  # Remove Italia from the territories
            t = GroundArea(*itemgetter("id", "name", "type", "coords")(
                self.territories_dict["territories"][15]),
                           model=self)
            t.armies = 3
            t.owner = self.computers[0]
            self.grid.place_agent(t, 15)
            self.ground_areas.append(self.grid.get_cell_list_contents([15])[0])
        """ 
        Connect nodes to territories and assign them to players
        """
        for i, node in enumerate(territories):
            t = GroundArea(*itemgetter("id", "name", "type", "coords")(
                self.territories_dict["territories"][node]),
                           model=self)
            if i < 9 * self.n_players:
                t.armies = 2
                t.owner = self.players[i % self.n_players]
            else:
                t.armies = 3
                t.owner = self.computers[i % self.n_computers]
            self.grid.place_agent(t, node)
            self.ground_areas.append(
                self.grid.get_cell_list_contents([node])[0])
        """
        Add sea area
        """
        for i, node in enumerate(range(45, 57)):
            t = SeaArea(*itemgetter("id", "name", "type", "coords")(
                self.territories_dict["sea_areas"][i]),
                        model=self)
            t.trireme = [0 for _ in range(self.n_players)]
            self.grid.place_agent(t, node)
            self.sea_areas.append(self.grid.get_cell_list_contents([node])[0])

        self.ground_areas.sort(key=lambda x: x.unique_id)
        self.sea_areas.sort(key=lambda x: x.unique_id)

        self.running = True
        # self.datacollector.collect(self)

    def get_strategy_setup(self, strategy, i):
        strats = ["Aggressive", "Passive", "Neutral"]
        if strategy == "Random":
            strategy = strats[i % 3]
        return strategy

    @staticmethod
    def get_movable_armies_by_strategy(strategy, minimum, maximum):
        return round((maximum - minimum) *
                     strategies.nomads_percentage[strategy] + minimum)

    @staticmethod
    def create_graph_map():
        # Read map configuration from file
        with open(
                os.path.join(os.path.dirname(__file__),
                             "config/territories.json"), "r") as f:
            territories_dict = json.load(f)

        graph_map = nx.Graph()

        for territory in territories_dict["territories"]:
            graph_map.add_node(territory["id"])
        for sea in territories_dict['sea_areas']:
            graph_map.add_node(sea['id'])
        for edges in territories_dict["edges"]:
            graph_map.add_edge(edges[0], edges[1])

        return graph_map, territories_dict

    @staticmethod
    def create_deck(custom_numbers=None):
        # Read deck from configuration file
        deck = []
        with open(os.path.join(os.path.dirname(__file__), "config/cards.json"),
                  "r") as f:
            cards = json.load(f)

        # custom cards' numbers
        if custom_numbers:
            # do something
            return deck
        for card in cards:
            c = {
                "type": card["type"],
                "adds_on_tris": card["adds_on_tris"],
                "image": card["image"]
            }
            for _ in range(card["number_in_deck"]):
                deck.append(c)

        return deck

    def draw_a_card(self):
        # if deck is empty, refill from trashed cards
        if len(self.deck) == 0:
            if len(self.trashed_cards) == 0:
                # We finished cards, players must do some tris to refill deck!
                return None
            self.deck.extend(self.trashed_cards)
            self.trashed_cards = []

        # return last card from deck
        return self.deck.pop()

    @staticmethod
    def reinforces_from_tris(cards):
        # assert len(cards) == 3, "Wrong number of cards given to 'tris' method"
        if len(cards) != 3:
            return None
        cards_in_tris = set([card["type"] for card in cards])
        # assert len(cards_in_tris) == 3 or len(cards_in_tris) == 1, \
        # Tris must be composed of three different cards or three of the same type
        if len(cards_in_tris) != 3 and len(cards_in_tris) != 1:
            return None
        reinforces = {
            "legionaries": 8 if len(cards_in_tris) == 1 else 10,
            "centers": 0,
            "triremes": 0
        }
        for card in cards:
            for key, value in card["adds_on_tris"].items():
                reinforces[key] += value
        return reinforces

    def precompute_tris_reinforces_by_goal(self):
        # precompute tris and assign points based on strategy
        all_possible_tris = [
            list(t) for t in itertools.combinations(self.deck, 3)
        ]
        all_reinforces = [
            SPQRisiko.reinforces_from_tris(tris) for tris in all_possible_tris
        ]
        # Remove None from list
        real_tris = [
            all_possible_tris[i] for i in range(len(all_reinforces))
            if all_reinforces[i]
        ]
        all_reinforces = [i for i in all_reinforces if i]
        named_tris = {}
        for i, tris in enumerate(real_tris):
            name = self.get_tris_name(tris)
            named_tris[name] = all_reinforces[i]
            self.reinforces_by_goal[name] = {}
            for goal, value in strategies.strategies.items():
                self.reinforces_by_goal[name][
                    goal] = self.get_reinforcements_score(
                        all_reinforces[i], value["tris"])

        # order tris name by score
        for goal, value in strategies.strategies.items():
            self.tris_by_goal[goal] = []
            for tris in real_tris:
                name = self.get_tris_name(tris)
                if name not in self.tris_by_goal[goal]:
                    self.tris_by_goal[goal].append(name)
            self.tris_by_goal[goal] = sorted(
                self.tris_by_goal[goal],
                key=cmp_to_key(lambda a, b: self.reinforces_by_goal[b][goal] -
                               self.reinforces_by_goal[a][goal]))

        self.reinforces_by_goal["average"] = {}
        for goal, value in strategies.strategies.items():
            points, count = 0, 0
            for tris in real_tris:
                count += 1
                points += self.reinforces_by_goal[self.get_tris_name(
                    tris)][goal]
            self.reinforces_by_goal["average"][goal] = float(points) / count

    def count_players_sea_areas(self):
        sea_areas = [0] * self.n_players

        for sea in self.sea_areas:
            m = max(sea.trireme)
            players_max_trireme = [
                player for player, n_trireme in enumerate(sea.trireme)
                if n_trireme == m
            ]
            if len(players_max_trireme) == 1:
                sea_areas[players_max_trireme[0]] += 1

        return sea_areas

    def count_players_territories_power_places(self):
        territories = [0] * self.n_players
        power_places = [0] * self.n_players

        for territory in self.ground_areas:
            if not territory.owner.computer:
                territories[territory.owner.unique_id] += 1
                if territory.power_place:
                    power_places[territory.owner.unique_id] += 1

        return territories, power_places

    def get_weakest_power_place(self, player):
        weakest = None
        for territory in self.ground_areas:
            if not territory.owner.computer and territory.owner.unique_id == player.unique_id:
                if territory.power_place:
                    if not weakest or territory.armies < weakest.armies:
                        weakest = territory
        return weakest

    def get_weakest_adversary_power_place(self, player):
        weakest = None
        for territory in self.ground_areas:
            if territory.owner.computer or territory.owner.unique_id != player.unique_id:
                if territory.power_place:
                    if not weakest or territory.armies < weakest.armies:
                        weakest = territory
        return weakest

    def find_nearest(self, territory, player):
        # It's a BFS visit to get the node whose distance from territory is the lesser than any other
        for ground_area in self.ground_areas:
            ground_area.found = 0
        for sea_area in self.sea_areas:
            sea_area.found = 0

        territory.found = 1
        visited = [territory]
        distances = [0] * 57

        while len(visited) > 0:
            t = visited.pop(0)
            if distances[t.unique_id] > 4:
                break
            for neighbor in self.grid.get_neighbors(t.unique_id):
                neighbor = self.grid.get_cell_list_contents([neighbor])[0]
                if neighbor.found == 0:
                    neighbor.found = 1
                    distances[neighbor.unique_id] = distances[t.unique_id] + 1
                    visited.append(neighbor)
                    if neighbor.type == "ground" and neighbor.owner.unique_id == player.unique_id:
                        return neighbor

        return None

    def get_largest_empire(self, player):
        # It's another DFS visit in which we account for the membership of a node to a connected component
        def __dfs_visit__(territory, ground_areas, cc_num):
            territory.found = 1
            ground_areas[territory.unique_id] = cc_num
            for neighbor in self.grid.get_neighbors(territory.unique_id):
                neighbor = self.grid.get_cell_list_contents([neighbor])[0]
                if neighbor.type == "ground" and \
                   neighbor.found == 0 and \
                   neighbor.owner.unique_id == player.unique_id:

                    __dfs_visit__(neighbor, ground_areas, cc_num)

        cc_num = 0
        ground_areas = [-1] * 45

        for territory in self.ground_areas:
            territory.found = 0

        for territory in self.ground_areas:
            if territory.type == "ground" and territory.found == 0 and territory.owner.unique_id == player.unique_id:
                __dfs_visit__(territory, ground_areas, cc_num)
                cc_num += 1

        stats = list(
            collections.Counter([t for t in ground_areas
                                 if t != -1]).most_common())
        if stats != []:
            return [
                self.ground_areas[idx] for idx, cc in enumerate(ground_areas)
                if cc == stats[0][0]
            ]
        return stats

    def maximum_empires(self):
        # It's a DFS visit in which we account for
        # the length of every connected components
        def __dfs_visit__(territory, d):
            territory.found = 1
            for neighbor in self.grid.get_neighbors(territory.unique_id):
                neighbor = self.grid.get_cell_list_contents([neighbor])[0]
                if neighbor.type == "ground" and \
                   neighbor.found == 0 and \
                   neighbor.owner.unique_id == territory.owner.unique_id:

                    d = __dfs_visit__(neighbor, d)
            return d + 1

        cc_lengths = [0] * self.n_players

        for territory in self.ground_areas:
            territory.found = 0

        for territory in self.ground_areas:
            if not territory.owner.computer and territory.found == 0:
                distance = __dfs_visit__(territory, 0)
                if distance > cc_lengths[territory.owner.unique_id]:
                    cc_lengths[territory.owner.unique_id] = distance

        return cc_lengths

    # Controlla se `player` ha vinto oppure se c'è un vincitore tra tutti
    def winner(self, player=None):
        if player is not None:
            if player.victory_points >= self.points_limit:
                return True
            return False

        max_points = -1
        max_player = None
        for p in self.players:
            if p.victory_points > max_points:
                max_points = p.victory_points
                max_player = p

        won = True if max_points > self.points_limit else False
        return max_player, won

    def get_territories_by_player(self, player: Player, ground_type="ground"):
        if ground_type == "ground":
            return [
                t for t in self.ground_areas
                if t.owner.unique_id == player.unique_id
            ]
        elif ground_type == "sea":
            return [
                t for t in self.sea_areas
                if t.trireme[self.players.index(player)] > 0
                or max(t.trireme) == 0
            ]

    def get_sea_area_near_ground_area(self, player):
        sea_areas = []
        for sea_area in self.sea_areas:
            for neighbor in self.grid.get_neighbors(sea_area.unique_id):
                neighbor = self.grid.get_cell_list_contents([neighbor])[0]
                if  isinstance(neighbor, GroundArea) and \
                    neighbor.owner.unique_id == player.unique_id:

                    sea_areas.append(sea_area)
        return sea_areas

    def n_power_places(self):
        n = 0
        for area in self.ground_areas:
            if area.power_place:
                n += 1
        return n

    def update_atta_wins_combact_matrix(self,
                                        attacker_armies,
                                        defender_armies,
                                        mat_type='combact'):
        print(attacker_armies, defender_armies, self.atta_wins_combact.shape,
              self.atta_wins_combact_by_sea.shape)
        if mat_type == 'combact':
            if attacker_armies > self.atta_wins_combact.shape[
                    0] and defender_armies > self.atta_wins_combact.shape[1]:
                self.atta_wins_combact = get_probabilities_ground_combact(
                    attacker_armies, defender_armies)
            elif attacker_armies > self.atta_wins_combact.shape[0]:
                self.atta_wins_combact = get_probabilities_ground_combact(
                    attacker_armies, self.atta_wins_combact.shape[1])
            elif defender_armies > self.atta_wins_combact.shape[1]:
                self.atta_wins_combact = get_probabilities_ground_combact(
                    self.atta_wins_combact.shape[0], defender_armies)
        elif mat_type == 'combact_by_sea':
            if attacker_armies > self.atta_wins_combact_by_sea.shape[
                    0] and defender_armies > self.atta_wins_combact_by_sea.shape[
                        1]:
                self.atta_wins_combact_by_sea = get_probabilities_combact_by_sea(
                    attacker_armies, defender_armies)
            elif attacker_armies > self.atta_wins_combact_by_sea.shape[0]:
                self.atta_wins_combact_by_sea = get_probabilities_combact_by_sea(
                    attacker_armies, self.atta_wins_combact_by_sea.shape[1])
            elif defender_armies > self.atta_wins_combact_by_sea.shape[1]:
                self.atta_wins_combact_by_sea = get_probabilities_combact_by_sea(
                    self.atta_wins_combact_by_sea.shape[0], defender_armies)

    def step(self):
        self.current_turn += 1
        for player in self.players:
            if not player.eliminated:
                can_draw = False
                territories, power_places = self.count_players_territories_power_places(
                )
                player_territories = self.get_territories_by_player(
                    player, "ground")
                sea_areas = self.count_players_sea_areas()
                empires = self.maximum_empires()

                # 1) Aggiornamento del punteggio
                player.update_victory_points(empires, territories, sea_areas,
                                             power_places)

                # 1.1) Controllo vittoria
                if self.winner(player):
                    self.running = False
                    print(player)
                    print(get_winner(self))
                    print(get_winner_turn(self))
                    self.datacollector.collect(self)
                    self.log("{} has won!".format(player.color))
                    return True

                # 2) Fase dei rinforzi
                print('\nREINFORCES')
                player.update_ground_reinforces_power_places()
                reinforces = Player.get_ground_reinforces(player_territories)
                self.log(
                    "{} earns {} legionaries (he owns {} territories)".format(
                        player.color, reinforces,
                        territories[player.unique_id]))
                player.put_reinforces(self, reinforces)
                # player.sacrifice_trireme(sea_area_from, ground_area_to)

                # use card combination
                # displace ground, naval and/or power places on the ground
                tris = player.get_best_tris(self)

                if tris:
                    reinforces = player.play_tris(self, tris)
                    self.log("{} play tris {}".format(
                        player.color, self.get_tris_name(tris)))
                    player.put_reinforces(self, reinforces)
                    # TODO: log where reinforces are put

                # 3) Movimento navale
                # player.naval_movement(sea_area_from, sea_area_to, n_trireme)

                # 4) Combattimento navale
                print('\nNAVAL COMBACT!!')
                # Get all sea_areas that the current player can attack
                attackable_sea_areas = []
                for sea_area in self.get_territories_by_player(
                        player, ground_type='sea'):
                    # Choose the adversary that has the lower probability of winning the combact
                    min_trireme = min(sea_area.trireme)
                    if min_trireme > 0:
                        adv_min_trireme = sea_area.trireme.index(min_trireme)
                        # Check if the atta_wins_combact probabilities matrix needs to be recomputed
                        # self.update_atta_wins_combact_matrix(sea_area.trireme[player.unique_id], sea_area.trireme[adv_min_trireme])
                        row = sea_area.trireme[player.unique_id]
                        col = sea_area.trireme[adv_min_trireme]
                        m = max(row, col)
                        ratio = 100 / m
                        if ratio < 1:
                            row = min(round(ratio * row), 100)
                            col = min(round(ratio * col), 100)
                        if  player.unique_id != adv_min_trireme and \
                            self.atta_wins_combact[row - 1, col - 1] >= strategies.probs_win[player.strategy]:

                            attackable_sea_areas.append(
                                [sea_area, adv_min_trireme])

                for sea_area, adv in attackable_sea_areas:
                    # Randomly select how many attack and defense trireme
                    attacker_trireme = sea_area.trireme[player.unique_id]
                    # The defender must always use the maximux number of armies to defend itself
                    # n_defense_trireme = sea_area.trireme[adversary.unique_id] if sea_area.trireme[adversary.unique_id] <= 3 else 3
                    # Let's combact biatch!!
                    print('Start battle!')
                    print('Trireme in ' + sea_area.name + ': ',
                          sea_area.trireme)
                    print('Player ' + str(player.unique_id) +
                          ' attacks Player ' + str(adv) + ' on ' +
                          sea_area.name)
                    player.naval_combact(sea_area, adv, attacker_trireme,
                                         strategies.probs_win[player.strategy],
                                         self.atta_wins_combact)

                # 5) Attacchi via mare
                print('\nCOMBACT BY SEA!!')

                for ground_area in self.ground_areas:
                    ground_area.already_attacked_by_sea = False

                attacks = self.get_attackable_ground_areas_by_sea(player)
                # attacks.sort(key=lambda x: x["prob_win"], reverse=True)

                while 0 < len(attacks):
                    attack = attacks[0]
                    # if not attack['defender'].already_attacked_by_sea:
                    attack['defender'].already_attacked_by_sea = True
                    attacker_armies = attack["attacker"].armies - attack[
                        "armies_to_leave"]
                    print(
                        'Battle: {} (player {}) with {} VS {} (player {}) with {}'
                        .format(attack["attacker"].name, player.unique_id,
                                attacker_armies, attack["defender"].name,
                                attack["defender"].owner.unique_id,
                                attack["defender"].armies))
                    conquered, min_moveable_armies = player.combact_by_sea(
                        attack["attacker"], attack["defender"],
                        attacker_armies)
                    if conquered:
                        # Move armies from attacker area to conquered
                        max_moveable_armies = attack[
                            "attacker"].armies - attack["armies_to_leave"]
                        nomads = SPQRisiko.get_movable_armies_by_strategy(
                            player.strategy, min_moveable_armies,
                            max_moveable_armies)
                        attack["attacker"].armies -= nomads
                        attack["defender"].armies = nomads
                        can_draw = True
                    # Remove from possible attacks all of those containing as defender the conquered territory
                    # and update the probability
                    attacks = self.update_attacks_by_sea(player, attacks)

                # 6) Attacchi terrestri
                print('\nGROUND COMBACT!!')

                attacks = []
                attacks = self.get_attackable_ground_areas(player)
                # attacks.sort(key=lambda x: x["prob_win"], reverse=True)

                while 0 < len(attacks):
                    attack = attacks[0]
                    attacker_armies = attack["attacker"].armies - 1
                    print(
                        'Battle: {} (player {}) with {} VS {} (player {}) with {}'
                        .format(attack["attacker"].name, player.unique_id,
                                attacker_armies, attack["defender"].name,
                                attack["defender"].owner.unique_id,
                                attack["defender"].armies))
                    conquered, min_moveable_armies = player.combact(
                        attack["attacker"], attack["defender"],
                        attacker_armies, strategies.probs_win[player.strategy],
                        self.atta_wins_combact)
                    if conquered:
                        # Move armies from attacker area to conquered
                        max_moveable_armies = attack["attacker"].armies - 1
                        nomads = SPQRisiko.get_movable_armies_by_strategy(
                            player.strategy, min_moveable_armies,
                            max_moveable_armies)
                        attack["attacker"].armies -= nomads
                        attack["defender"].armies = nomads
                        can_draw = True
                        self.log(
                            "{} conquered {} from {} and it moves {} armies there out of {}"
                            .format(player.color, attack["defender"].name,
                                    attack["attacker"].name, nomads,
                                    max_moveable_armies))
                    # Re-sort newly attackable areas with newer probabilities
                    attacks = self.get_attackable_ground_areas(player)
                    # attacks.sort(key=lambda x: x["prob_win"], reverse=True)

                # Controllo se qualche giocatore è stato eliminato
                for adv in self.players:
                    if adv.unique_id != player.unique_id and not adv.eliminated:
                        territories = self.get_territories_by_player(adv)
                        if len(territories) == 0:
                            self.log("{} has been eliminated by {}".format(
                                adv.color, player.color))
                            player.cards.extend(adv.cards)
                            adv.cards = []
                            adv.eliminated = True
                            for sea_area in self.get_territories_by_player(
                                    adv, ground_type="sea"):
                                sea_area.trireme[adv.unique_id] = 0

                # 7) Spostamento strategico di fine turno
                player.move_armies_by_goal(self)

                # 8) Presa della carta
                # Il giocatore può dimenticarsi di pescare la carta ahah sarebbe bello fare i giocatori smemorati
                if can_draw and random.random() <= 1:
                    card = self.draw_a_card()
                    if card:
                        player.cards.append(card)
        self.schedule.step()
        return False

    def update_attacks_by_sea(self, player, future_attacks):
        attack_num = 0
        last_attacker = future_attacks[0]['attacker']
        del future_attacks[0]
        while attack_num < len(future_attacks):
            attack = future_attacks[attack_num]
            if attack['defender'].owner.unique_id == player.unique_id:
                print('Since the defender has been conquered, I delete it')
                del future_attacks[attack_num]
            elif attack['defender'].already_attacked_by_sea:
                print(
                    'Since the defender has already been attacked by sea, I delete it'
                )
                del future_attacks[attack_num]
            elif attack['attacker'].unique_id == last_attacker.unique_id:
                print('The attacker may attack again')
                # Maybe it could change the armies to leave due to garrisons
                armies_to_leave = self.get_armies_to_leave(attack['attacker'])
                if attack['attacker'].armies - armies_to_leave >= min(
                        3, attack['defender'].armies):
                    prob_win = self.atta_wins_combact_by_sea[
                        attack['attacker'].armies - armies_to_leave - 1,
                        attack['defender'].armies - 1]
                    if prob_win >= strategies.probs_win[player.strategy]:
                        print('The attacker can attack again')
                        attack['prob_win'] = prob_win
                        attack_num += 1
                    else:
                        print(
                            'Since the attacker has a lower prob to win, I delete it'
                        )
                        del future_attacks[attack_num]
                else:
                    print(
                        'Since the attacker hasn\'t the min required armies, I delete it'
                    )
                    del future_attacks[attack_num]
            else:
                attack_num += 1
        if player.goal == "PP":
            future_attacks.sort(key=lambda x:
                                (x['defender'].power_place, x['prob_win']),
                                reverse=True)
        else:
            future_attacks.sort(key=lambda x: x['prob_win'], reverse=True)
        return future_attacks

    def get_attackable_ground_areas_by_sea(self, player):
        attacks = []
        for ground_area in self.get_territories_by_player(player):
            for neighbor in self.grid.get_neighbors(ground_area.unique_id):
                neighbor = self.grid.get_cell_list_contents([neighbor])[0]
                # A player can attack a ground area through sea, only if it posesses a number of
                # trireme greater than the possible adversary.
                if isinstance(
                        neighbor,
                        SeaArea) and neighbor.trireme[player.unique_id] > min(
                            neighbor.trireme):
                    for sea_area_neighbor in self.grid.get_neighbors(
                            neighbor.unique_id):
                        sea_area_neighbor = self.grid.get_cell_list_contents(
                            [sea_area_neighbor])[0]
                        if isinstance(sea_area_neighbor, GroundArea) and \
                           ground_area.unique_id != sea_area_neighbor.unique_id and \
                           sea_area_neighbor.owner.unique_id != player.unique_id and \
                           (sea_area_neighbor.owner.computer or neighbor.trireme[player.unique_id] > neighbor.trireme[sea_area_neighbor.owner.unique_id]):

                            armies_to_leave = self.get_armies_to_leave(
                                ground_area)
                            if ground_area.armies - armies_to_leave >= min(
                                    3, sea_area_neighbor.armies):
                                # self.update_atta_wins_combact_matrix(ground_area.armies - armies_to_leave, sea_area_neighbor.armies, mat_type='combact_by_sea')
                                row = ground_area.armies - armies_to_leave
                                col = sea_area_neighbor.armies
                                m = max(row, col)
                                ratio = 100 / m
                                if ratio < 1:
                                    row = min(round(ratio * row), 100)
                                    col = min(round(ratio * col), 100)
                                prob_win = self.atta_wins_combact_by_sea[row -
                                                                         1,
                                                                         col -
                                                                         1]
                                if prob_win >= strategies.probs_win[
                                        player.strategy]:
                                    attacks.append({
                                        "defender": sea_area_neighbor,
                                        "attacker": ground_area,
                                        "armies_to_leave": armies_to_leave,
                                        "prob_win": prob_win
                                    })
        if player.goal == "PP":
            attacks.sort(key=lambda x:
                         (x['defender'].power_place, x['prob_win']),
                         reverse=True)
        else:
            attacks.sort(key=lambda x: x['prob_win'], reverse=True)
        return attacks

    def get_armies_to_leave(self, ground_area):
        ground_area_neighbors = self.grid.get_neighbors(ground_area.unique_id)
        for ground_area_neighbor in ground_area_neighbors:
            ground_area_neighbor = self.grid.get_cell_list_contents(
                [ground_area_neighbor])[0]
            if isinstance(ground_area_neighbor, GroundArea) and \
               ground_area_neighbor.owner.unique_id != ground_area.owner.unique_id:

                return 2

        return 1

    def get_attackable_ground_areas_from(self, ground_area):
        attacks = []
        if ground_area.armies > 1:
            for neighbor in self.grid.get_neighbors(ground_area.unique_id):
                neighbor = self.grid.get_cell_list_contents([neighbor])[0]
                if neighbor.type == "ground" and \
                    neighbor.owner.unique_id != ground_area.owner.unique_id and \
                    ground_area.armies - 1 >= min(3, neighbor.armies):

                    # self.update_atta_wins_combact_matrix(ground_area.armies - 1, neighbor.armies)
                    row = ground_area.armies - 1
                    col = neighbor.armies
                    m = max(row, col)
                    ratio = 100 / m
                    if ratio < 1:
                        row = min(round(ratio * row), 100)
                        col = min(round(ratio * col), 100)
                    prob_win = self.atta_wins_combact[row - 1, col - 1]
                    if prob_win >= strategies.probs_win[
                            ground_area.owner.strategy]:
                        attacks.append({
                            "defender": neighbor,
                            "attacker": ground_area,
                            "prob_win": prob_win
                        })
        return attacks

    def get_attackable_ground_areas(self, player):
        attacks = []
        for ground_area in self.get_territories_by_player(player):
            attackables = self.get_attackable_ground_areas_from(ground_area)
            if attackables != []:
                for attackable in attackables:
                    attacks.append(attackable)
        if player.goal == "PP":
            attacks.sort(key=lambda x:
                         (x['defender'].power_place, x['prob_win']),
                         reverse=True)
        else:
            attacks.sort(key=lambda x: x['prob_win'], reverse=True)
        return attacks

    # Get non attackable areas wiht at least 2 armies and with an ally neighbor
    def non_attackable_areas(self, player, territories=None):
        non_attackables = []
        if not territories:
            territories = self.get_territories_by_player(player)
        for ground_area in territories:
            if ground_area.armies > 1:
                attackable, has_ally_neighbor = False, False
                for neighbor in self.grid.get_neighbors(ground_area.unique_id):
                    neighbor = self.grid.get_cell_list_contents([neighbor])[0]
                    if neighbor.type == "ground" and neighbor.owner.unique_id != player.unique_id:
                        attackable = True
                        break
                    has_ally_neighbor = True

                if not attackable and has_ally_neighbor:
                    non_attackables.append(ground_area)

        return non_attackables

    def is_not_attackable(self, area):
        for neighbor in self.grid.get_neighbors(area.unique_id):
            neighbor = self.grid.get_cell_list_contents([neighbor])[0]
            if isinstance(
                    neighbor, GroundArea
            ) and neighbor.owner.unique_id != area.owner.unique_id:
                return False
        return True

    def get_strongest_ally_neighbor(self, area):
        strongest = None
        for neighbor in self.grid.get_neighbors(area.unique_id):
            neighbor = self.grid.get_cell_list_contents([neighbor])[0]
            if isinstance(neighbor, GroundArea) and (
                    not strongest or strongest.armies < neighbor.armies):
                strongest = neighbor
        return strongest

    def is_neighbor_of(self, area1, area2):
        for neighbor in self.grid.get_neighbors(area1.unique_id):
            neighbor = self.grid.get_cell_list_contents([neighbor])[0]
            if neighbor.owner.unique_id == area2.unique_id:
                return True

        return False

    def log(self, log):
        self.journal.append("Turn {}: ".format(self.current_turn) + log)

    def run_model(self, n):
        for _ in range(n):
            self.step()

    # Tris name is the ordered initial letters of cards type
    def get_tris_name(self, tris):
        if len(tris) != 3:
            raise Exception("tris name parameter error")
        return "-".join(
            [card[0] for card in sorted(set([card["type"] for card in tris]))])

    def get_reinforcements_score(self, reinforces, multipliers):
        m, r = multipliers, reinforces
        return m[0] * r["legionaries"] + m[1] * r["triremes"] + m[2] * r[
            "centers"]

    def get_n_armies_by_player(self, player=None):
        if player is not None:
            return sum(
                [t.armies for t in self.get_territories_by_player(player)])
        else:
            sum_a = 0
            for player in self.players:
                sum_a += sum(
                    [t.armies for t in self.get_territories_by_player(player)])
            return sum_a / len(self.players)
コード例 #27
0
class Model(Model):

    initial_RefinedKitten = 100
    initial_ImperialKitten = 100
    initial_CharmingKitten = 100
    initial_HelixKitten = 100
    initial_StaticKitten = 100
    initial_RemixKitten = 100

    
    def __init__(self, nodes, initial_RefinedKitten = 100, 
                 initial_ImperialKitten = 100, initial_CharmingKitten = 100, 
                 initial_HelixKitten = 100, initial_StaticKitten = 100,
                 initial_RemixKitten = 100):
        super().__init__()
                
        self.initial_RefinedKitten = initial_RefinedKitten
        self.initial_ImperialKitten = initial_ImperialKitten
        self.initial_CharmingKitten = initial_CharmingKitten
        self.initial_HelixKitten = initial_HelixKitten
        self.initial_StaticKitten = initial_StaticKitten
        self.initial_RemixKitten = initial_RemixKitten

        
        self.grid = NetworkGrid(G)        
        self.schedule = RandomActivationByOrg(self)
                           
        for i in range(self.initial_RefinedKitten):
            refinedkitten = RefinedKitten(self.next_id(), 'RFK', self)
            self.grid.place_agent(refinedkitten, 'RFK')
            self.schedule.add(refinedkitten)

        for i in range(self.initial_ImperialKitten):
            imperialkitten = ImperialKitten(self.next_id(), 'IK', self)
            self.grid.place_agent(imperialkitten, 'IK')
            self.schedule.add(imperialkitten)

        for i in range(self.initial_CharmingKitten):
            charmingkitten = CharmingKitten(self.next_id(), 'CK', self)
            self.grid.place_agent(charmingkitten, 'CK')
            self.schedule.add(charmingkitten)

        for i in range(self.initial_HelixKitten):
            helixkitten = HelixKitten(self.next_id(), 'HK', self)
            self.grid.place_agent(helixkitten, 'HK')
            self.schedule.add(helixkitten)

        for i in range(self.initial_StaticKitten):
            statickitten = StaticKitten(self.next_id(), 'SK', self)
            self.grid.place_agent(statickitten, 'SK')
            self.schedule.add(statickitten)

        for i in range(self.initial_RemixKitten):
            remixkitten = RemixKitten(self.next_id(), 'RMK', self)
            self.grid.place_agent(remixkitten, 'RMK')
            self.schedule.add(remixkitten)
           
        self.running = True  
        
        self.datacollector = DataCollector(
            agent_reporters = {"Organization": "org", "Spear Phishing": "phish", "Zero Day": "zeroday",
            "Tool Sophistication": "tools", "Attribution Obfuscation": "attrib",
            "Stealth": "stealth", "Information Weaponization": "iwo","DDoS": "ddos", 
            "Data Destruction": "destruct", "Critical Infrastructure Disruption": "infra"})
        
    def step(self):       
        self.schedule.step()
        self.datacollector.collect(self)
コード例 #28
0
class InfoSpread(Model):
    """A virus model with some number of agents"""
    def __init__(self,
                 num_nodes=10,
                 avg_node_degree=3,
                 rewire_prob=.1,
                 initial_outbreak_size=1,
                 threshold_fake=2,
                 threshold_real=-2,
                 fake_p=1,
                 real_p=1):
        self.fake_p = fake_p
        self.real_p = real_p

        self.num_nodes = num_nodes
        self.G = nx.watts_strogatz_graph(
            n=self.num_nodes, k=avg_node_degree,
            p=rewire_prob)  #G generate graph structure
        self.grid = NetworkGrid(
            self.G
        )  #grid is the Masa native defintion of space: a coorindate with specified topology on which agents sits and interact
        self.schedule = SimultaneousActivation(self)
        self.initial_outbreak_size = (initial_outbreak_size
                                      if initial_outbreak_size <= num_nodes
                                      else num_nodes)

        self.datacollector = DataCollector({
            "Infected_fake":
            number_infected_fake,
            "Infected_real":
            number_infected_real,
        })

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            a = User(
                i,
                self,
                0,  #make the state a int
                threshold_fake,
                threshold_real)
            self.schedule.add(a)
            # Add the agent to the node
            self.grid.place_agent(a, node)

        # Infect some nodes, initial infection bug free
        infected_nodes_fake = self.random.sample(self.G.nodes(),
                                                 self.initial_outbreak_size)
        infected_nodes_real = self.random.sample(self.G.nodes(),
                                                 self.initial_outbreak_size)

        for a in self.grid.get_cell_list_contents(infected_nodes_fake):
            a.state = 1
            neighbors_nodes = self.grid.get_neighbors(a.pos)
            for n in self.grid.get_cell_list_contents(neighbors_nodes):
                n.state = 1

        for a in self.grid.get_cell_list_contents(infected_nodes_real):
            a.state = -1
            neighbors_nodes = self.grid.get_neighbors(a.pos)
            for n in self.grid.get_cell_list_contents(neighbors_nodes):
                n.state = -1
        """
        state measures fake score!! the more negative the less likely to spread fake news
        also this model assumes that 
        1
        one piece of real news can cancel out one piece of fake news
        This model can be modulated by changing the value of fake and real
        
        2
        the inital braeakout size of fake and real news are the same
        This can be chaged by introducing a different initial breaksize for real and fake news
        however this score is kepet the same intentionally because too uch complexity is not good for modeling
        """

        self.running = True
        self.datacollector.collect(self)

    def proportion_infected_fake(self):
        try:
            tot_fake = 0
            for i in self.grid.get_cell_list_contents(self.G):
                if i.state == 1:
                    tot_fake += 1
            return tot_fake / self.num_nodes
        except ZeroDivisionError:
            return math.inf

    def proportion_infected_real(self):
        try:
            tot_real = 0
            for i in self.grid.get_cell_list_contents(self.G):
                if i.state == -1:
                    tot_real += 1
            return tot_real / self.num_nodes
        except ZeroDivisionError:
            return math.inf

    def step(self):
        self.schedule.step(
        )  #this model updates with symoutanous schedule, meaning,
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        ''' could experiment terminating model here too'''
        for i in range(n):
            self.step()
コード例 #29
0
class BankSim(Model):
    simid = None  #Simulation ID for SQLITEDB primary key
    max_steps = 200
    conn = None  # Sqlite connector
    db_cursor = None  # Sqlite DB cursor
    lst_bank_ratio = list()
    lst_ibloan = list()

    def __init__(self, **params):
        super().__init__()
        config = configparser.ConfigParser()
        config.read('conf/config.ini')
        self.sqlite_db = config['SQLITEDB']['file']
        self.height = 20
        self.width = 20
        self.is_init_db = False if params.get(
            'write_db') is None else params.get('write_db')
        self.is_write_db = False if params.get(
            'write_db') is None else params.get('write_db')
        self.max_steps = params['max_steps']
        self.initial_saver = params['initial_saver']
        self.initial_loan = params['initial_loan']
        self.initial_bank = params['initial_bank']
        self.rfree = params['rfree']
        self.reserve_rates = params[
            'rfree'] / 2.0  # set reserve rates one half of risk free rate
        self.libor_rate = params['rfree']
        self.bankrupt_liquidation = 1  # 1: it is fire sale of assets, 0: bank liquidates loans at face value
        self.car = params['car']
        self.min_reserves_ratio = params['min_reserves_ratio']
        self.initial_equity = params['initial_equity']
        self.G = nx.empty_graph(self.initial_bank)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.datacollector = DataCollector({"BankAsset": get_sum_totasset})

    def step(self):
        if self.schedule.steps == 0:

            if self.is_init_db:
                init_database()
                logger.info('db initialization')

            if self.is_write_db:
                self.conn = sqlite3.connect(self.sqlite_db)
                self.db_cursor = self.conn.cursor()
                self.simid = int(
                    datetime.now().strftime('%y%m%d%H%M%S%f')[:-3])
                title = 'CAR {0:f}, Reserves Ratio {1:f}'.format(
                    self.car, self.min_reserves_ratio)
                task = (self.simid, title, datetime.now(timezone.utc))
                insert_simulation_table(self.db_cursor, task)

            for i in range(self.initial_bank):
                bank = Bank({
                    'unique_id': self.next_id(),
                    'model': self,
                    'equity': 100,
                    'rfree': self.rfree,
                    'car': self.car,
                    'buffer_reserves_ratio': 1.5
                })
                self.grid.place_agent(bank, i)
                self.schedule.add(bank)

            for i in range(self.initial_saver):
                saver = Saver({
                    'unique_id': self.next_id(),
                    'model': self,
                    'balance': 1,
                    'owns_account': False,
                    'saver_solvent': True,
                    'saver_exit': False,
                    'withdraw_upperbound': 0.2,
                    'exitprob_upperbound': 0.06
                })
                self.grid.place_agent(saver, random.choice(list(self.G.nodes)))
                self.schedule.add(saver)

            for i in range(self.initial_loan):
                loan = Loan({
                    "unique_id": self.next_id(),
                    "model": self,
                    "rfree": self.rfree,
                    "amount": 1,
                    "loan_solvent": True,
                    "loan_approved": False,
                    "loan_dumped": False,
                    "loan_liquidated": False,
                    "pdf_upper": 0.1,
                    "rcvry_rate": 0.4,
                    "firesale_upper": 0.1
                })
                bank_id = random.choice(list(self.G.nodes))
                loan.bank_id = bank_id
                self.grid.place_agent(loan, bank_id)  # Evenly distributed
                self.schedule.add(loan)

            initialize_deposit_base(self.schedule)
            initialize_loan_book(self.schedule, self.car,
                                 self.min_reserves_ratio)

            self.running = True
            self.datacollector.collect(self)

        if self.schedule.steps == self.max_steps:
            self.running = False

        # evaluate solvency of banks after loans experience default
        main_evaluate_solvency(self.schedule, self.reserve_rates,
                               self.bankrupt_liquidation, self.car)

        # evaluate second round effects owing to cross_bank linkages
        # only interbank loans to cover shortages in reserves requirements are included
        main_second_round_effects(self.schedule, self.bankrupt_liquidation,
                                  self.car, self.G)

        # Undercapitalized banks undertake risk_weight optimization
        main_risk_weight_optimization(self.schedule, self.car)

        # banks that are well capitalized pay dividends
        main_pay_dividends(self.schedule, self.car, self.min_reserves_ratio)

        # Reset insolvent loans, i.e. rebirth lending opportunity
        main_reset_insolvent_loans(self.schedule)

        # Build up loan book with loans available in bank neighborhood
        main_build_loan_book_locally(self.schedule, self.min_reserves_ratio,
                                     self.car)

        # Build up loan book with loans available in other neighborhoods
        main_build_loan_book_globally(self.schedule, self.car,
                                      self.min_reserves_ratio)

        # main_raise_deposits_build_loan_book
        # Evaluate liquidity needs related to reserves requirements
        main_evaluate_liquidity(self.schedule, self.car,
                                self.min_reserves_ratio,
                                self.bankrupt_liquidation)

        main_write_bank_ratios(self.schedule, self.lst_bank_ratio, self.car,
                               self.min_reserves_ratio)
        main_write_interbank_links(self.schedule, self.lst_ibloan)

        if self.is_write_db:
            # Insert agent variables of current step into SQLITEDB
            #insert_agtsaver_table(self.db_cursor, self.simid, self.schedule.steps,[x for x in self.schedule.agents if isinstance(x, Saver)])
            #insert_agtloan_table(self.db_cursor, self.simid, self.schedule.steps, [x for x in self.schedule.agents if isinstance(x, Loan)])
            # # It needs to log before the 2nd round effect begin because the function initializes
            insert_agtbank_table(
                self.db_cursor, self.simid, self.schedule.steps,
                [x for x in self.schedule.agents if isinstance(x, Bank)])
            # insert_agtibloan_table(self.db_cursor, self.simid, self.schedule.steps,
            #                        [x for x in self.schedule.agents if isinstance(x, Ibloan)])
            self.conn.commit()

        self.schedule.step()
        self.datacollector.collect(self)

    def run_model(self, step_count=20):
        """
        This method is only avail in the command mode
        :param step_count:
        :return:
        """
        for i in range(step_count):
            if i % 10 == 0 or (i + 1) == step_count:
                logger.info(
                    " STEP: %3d - # of sovent bank: %2d", i,
                    len([
                        x for x in self.schedule.agents
                        if isinstance(x, Bank) and x.bank_solvent
                    ]))
            try:
                self.step()
            except:
                error = traceback.format_exc()
                logger.error(error)
            if len([
                    x for x in self.schedule.agents
                    if isinstance(x, Bank) and x.bank_solvent
            ]) == 0:
                logger.info("All banks are bankrupt!")
                break
        #df_bank, df_ibloan = convert_result2dataframe(self.lst_bank_ratio, self.lst_ibloan)
        #return df_bank, df_ibloan
        return True
コード例 #30
0
class VirusModel(Model):
    """A virus model with some number of agents"""
    def __init__(self):
        # self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob)
        # self.G = nx.erdos_renyi_graph(n=3, p=0.5)
        self.G = nx.Graph()
        self.G.add_node(0)
        self.G.add_node(1)
        self.G.add_node(2)
        self.G.add_node(3)
        self.G.add_node(4)
        self.G.add_node(4)
        self.G.add_edge(0, 1)
        self.G.add_edge(0, 2)
        self.G.add_edge(0, 3)
        self.G.add_edge(0, 4)
        self.G.add_edge(0, 5)
        self.G.add_edge(1, 4)
        self.G.add_edge(4, 5)
        self.grid = NetworkGrid(self.G)

        self.rooms = {}
        self.rooms[0] = {"name": "Wejście", "rates": {}}
        self.rooms[1] = {"name": "Czytelnia", "rates": {"Nauka": 2}}
        self.rooms[2] = {"name": "Chillout", "rates": {"Relaks": 10}}
        self.rooms[3] = {"name": "Biuro", "rates": {"Praca": 1.5}}
        self.rooms[4] = {"name": "Toaleta", "rates": {"Toaleta": 30}}
        self.rooms[5] = {
            "name": "Kawiarnia",
            "rates": {
                "Jedzenie": 12,
                "Kultura": 0.5
            }
        }

        collector_dict = {}
        for i, room in enumerate(self.rooms):
            collector_dict[self.rooms[i]["name"]] = lambda model, i=i: len(
                model.grid.get_cell_list_contents([i])) - 1
        self.datacollector = DataCollector(collector_dict)

        self.schedule = RandomActivation(self)

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            r = RoomAgent(i, self, self.rooms[i]["name"],
                          self.rooms[i]["rates"])
            self.schedule.add(r)

            # Add the agent to the node
            self.grid.place_agent(r, node)

        self.prob_needs = {
            "Jedzenie": [4, 0.6],
            "Toaleta": [2, 0.6],
            "Relaks": [5, 1]
        }
        self.prob_studs = {
            "Nauka": [2, 1.5],
            "Praca": [0, 0.5],
            "Kultura": [0, 1.0]
        }
        self.prob_works = {
            "Nauka": [0, 0.3],
            "Praca": [6, 1.0],
            "Kultura": [0, 0.2]
        }
        self.prob_tours = {
            "Nauka": [0, 0.3],
            "Praca": [0, 0.5],
            "Kultura": [1, 1.0]
        }
        self.prob_local = {
            "Nauka": [1, 0.7],
            "Praca": [2, 0.9],
            "Kultura": [1, 1.0]
        }

        # godziny        0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
        self.rate_studs = [
            0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
            0, 0
        ]
        self.rate_works = [
            0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
            0, 0
        ]
        self.rate_tours = [
            0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, 3, 4, 4, 4, 6, 6, 4, 3, 2,
            0, 0
        ]
        self.rate_local = [
            0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 4, 4, 2, 2, 4, 5, 6, 6, 6, 3, 0,
            0, 0
        ]

        self.running = True
        self.datacollector.collect(self)

        self.tm = 0 * 60
        self.count = 0

    def get_sample(self, probs):
        ret = {}
        for k, [m, s] in probs.items():
            tm = int(np.clip(np.random.normal(m, s) * 60, 15, 600))
            ret[k] = tm
        return ret

    def step(self):
        # prepare list for the satisfied agents
        self.satisfied = []

        # add new agents
        hour = int(self.tm / 60)
        if (hour > 23):
            hour = 0

        for i in range(self.rate_studs[hour]):
            a = HumanAgent(100 + self.count, self,
                           self.get_sample(self.prob_needs),
                           self.get_sample(self.prob_studs))
            self.schedule.add(a)
            self.grid.place_agent(a, 0)
            self.count += 1

        for i in range(self.rate_works[hour]):
            a = HumanAgent(100 + self.count, self,
                           self.get_sample(self.prob_needs),
                           self.get_sample(self.prob_works))
            self.schedule.add(a)
            self.grid.place_agent(a, 0)
            self.count += 1

        # update system
        self.schedule.step()

        # collect data
        self.datacollector.collect(self)

        # make time step
        self.tm = self.tm + 1
        if (self.tm > 24 * 60):
            self.datacollector.get_model_vars_dataframe().to_csv("one_day.csv")
            self.tm = 0

        # remove satisfied agents from the system
        for a in self.satisfied:
            print(a.unique_id, a.goals, "is satisfied")
            self.grid.move_agent(a, 0)
            self.grid._remove_agent(a, 0)
            self.schedule.remove(a)

    def run_model(self, n):
        for i in range(n):
            self.step()

    def find_best_room(self, goal):
        #print("Looking for room for", goal)
        for i, room in enumerate(self.rooms):
            #print("Room", room, self.rooms[room]["rates"])
            if goal in self.rooms[room]["rates"]:
                return room
        return -1
コード例 #31
0
class IdeaSpread(Model):
    # creates a set number of agents and has them share beliefs
    def __init__(self,
                 num_nodes=50,
                 initial_anti=.18,
                 initial_pro=.71,
                 first_age=18,
                 last_age=22):
        self.num_nodes = num_nodes
        self.color_map = ['gray'] * self.num_nodes
        # mesa addition, creates knowledge of neighbors
        self.schedule = SimultaneousActivation(self)
        self.initial_anti = initial_anti
        self.initial_pro = initial_pro
        self.Vis = nx.Graph()
        self.Vis.add_nodes_from(range(num_nodes))
        self.ages = {}
        self.grid = NetworkGrid(self.Vis)
        self.population = {}
        groupsize = self.num_nodes / (last_age - first_age)

        # def setup_agents(self, age, num_nodes):
        # creates agents
        for i, node in enumerate(self.Vis.nodes()):
            a = Individual(i, self, Thought.NEUTRAL,
                           first_age + i * (last_age - first_age) / num_nodes)
            self.schedule.add(a)
            self.grid.place_agent(a, node)
            self.population[a.unique_id] = a
            # randomly assigns nodes to be +/-/0 within group
            if random.random() <= self.initial_anti:
                a.belief = Thought.ANTI
                self.color_map[a.unique_id] = ('red')
            elif random.random() <= self.initial_pro:
                a.belief = Thought.PRO
                self.color_map[a.unique_id] = 'green'
            else:
                self.color_map[a.unique_id] = 'gray'

        # adds age to dictionary with unique id
        for l in self.population:
            self.ages[l] = self.population[l].age

        # assigns edges (connections) between people
        for id1 in self.population:
            for id2 in self.population:
                if self.population[id1].prob_ref == 0 and id1 < id2:
                    if self.population[id2].prob_ref == 0 and random.random(
                    ) < (talk[0] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 1 and random.random(
                    ) < (talk[1] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 2 and random.random(
                    ) < (talk[2] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 3 and random.random(
                    ) < (talk[3] / groupsize):
                        self.Vis.add_edge(id1, id2)
                if self.population[id1].prob_ref == 1 and id1 < id2:
                    if self.population[id2].prob_ref == 0 and random.random(
                    ) < (talk[4] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 1 and random.random(
                    ) < (talk[5] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 2 and random.random(
                    ) < (talk[6] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 3 and random.random(
                    ) < (talk[7] / groupsize):
                        self.Vis.add_edge(id1, id2)
                if self.population[id1].prob_ref == 2 and id1 < id2:
                    if self.population[id2].prob_ref == 0 and random.random(
                    ) < (talk[8] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 1 and random.random(
                    ) < (talk[9] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 2 and random.random(
                    ) < (talk[10] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 3 and random.random(
                    ) < (talk[11] / groupsize):
                        self.Vis.add_edge(id1, id2)
                if self.population[id1].prob_ref == 3 and id1 < id2:
                    if self.population[id2].prob_ref == 0 and random.random(
                    ) < (talk[12] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 1 and random.random(
                    ) < (talk[13] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 2 and random.random(
                    ) < (talk[14] / groupsize):
                        self.Vis.add_edge(id1, id2)
                    if self.population[id2].prob_ref == 3 and random.random(
                    ) < (talk[15] / groupsize):
                        self.Vis.add_edge(id1, id2)


# TODO: figure out implementation of datacollector
        self.datacollector = DataCollector({
            "Anti Vaxxers": percent_anti,
            "Pro Vaxxine": percent_pro
        })
        self.running = True
        self.datacollector.collect(self)

    def step(self):
        self.schedule.step(self.population, self.Vis)
        self.datacollector.collect(self)

    def run(self, n):
        for i in range(n):
            print(percent_anti(self))
            portray(self, self.Vis)
            self.step()
            # reassigns color of people based on belief
            for a in self.population:
                if self.population[a].belief == Thought.ANTI:
                    self.color_map[a] = ('red')
                elif self.population[a].belief == Thought.PRO:
                    self.color_map[a] = 'green'
                else:
                    self.color_map[a] = 'gray'
コード例 #32
0
ファイル: model.py プロジェクト: fmcclean/mesacat
class EvacuationModel(Model):
    """A Mesa ABM model to simulate evacuation during a flood

    Args:
        hazard: Spatial table of flood hazard zones in WGS84
        output_path: Path to output files without extension
        domain: Polygon used to select OSM data, required if the graph, agents or targets are not specified
        target_types: List of OSM amenity values to use as targets, defaults to school
        network: Undirected network generated from OSM road network
        targets: Spatial table of OSM amenities
        target_capacity: The number of agents that can be evacuated to each target
        agents: Spatial table of agent starting locations
        seed: Seed value for random number generation

    Attributes:
        output_path (str): Path to output files without extension
        schedule (RandomActivation): Scheduler which activates each agent once per step,
            in random order, with the order reshuffled every step
        hazard (GeoDataFrame): Spatial table of flood hazard zones in WGS84
        G (Graph): Undirected network generated from OSM road network
        nodes (GeoDataFrame): Spatial table of nodes in G
        edges (GeoDataFrame): Spatial table edges in G
        grid (NetworkGrid): Network grid for agents to travel around based on G
        data_collector (DataCollector): Stores the model state at each time step
        target_nodes (Series): Series of nodes to evacuate to
        target_capacity (int): The number of agents that can be evacuated to each target
        igraph: Duplicate of G as an igraph object to speed up routing

    """
    def __init__(
            self,
            hazard: GeoDataFrame,
            output_path: str,
            domain: Optional[Polygon] = None,
            target_types: Iterable[str] = tuple(['school']),
            network: Optional[Graph] = None,
            targets: Optional[GeoDataFrame] = None,
            target_capacity: int = 100,
            agents: Optional[GeoDataFrame] = None,
            seed: Optional[int] = None):
        super().__init__()
        self._seed = seed
        self.output_path = output_path

        self.hazard = hazard
        self.schedule = RandomActivation(self)
        self.target_capacity = target_capacity

        if network is None:
            self.G = osmnx.graph_from_polygon(domain, simplify=False)
            self.G = self.G.to_undirected()
        else:
            self.G = network

        self.nodes: GeoDataFrame
        self.edges: GeoDataFrame
        self.nodes, self.edges = osmnx.save_load.graph_to_gdfs(self.G)

        if agents is None:
            agents = GeoDataFrame(geometry=create_footprints_gdf(domain).centroid)

        if targets is None:
            targets = osmnx.pois_from_polygon(domain, amenities=list(target_types))
            # Query can return polygons as well as points, only using the points
            targets = targets[targets.geometry.geom_type == 'Point']

        output_gpkg = output_path + '.gpkg'

        driver = 'GPKG'

        targets.crs, agents.crs = [self.nodes.crs] * 2

        nodes_tree = cKDTree(np.transpose([self.nodes.geometry.x, self.nodes.geometry.y]))

        # Prevents warning about CRS not being the same
        self.hazard.crs = self.nodes.crs
        self.hazard.to_file(output_gpkg, layer='hazard', driver=driver)

        agents_in_hazard_zone: GeoDataFrame = sjoin(agents, self.hazard)
        agents_in_hazard_zone = agents_in_hazard_zone.loc[~agents_in_hazard_zone.index.duplicated(keep='first')]
        agents_in_hazard_zone.geometry.to_file(output_gpkg, layer='agents', driver=driver)

        assert len(agents_in_hazard_zone) > 0, 'There are no agents within the hazard zone'

        targets_in_hazard_zone: GeoDataFrame = sjoin(targets, self.hazard)
        targets_in_hazard_zone = targets_in_hazard_zone.loc[~targets_in_hazard_zone.index.duplicated(keep='first')]

        targets_outside_hazard_zone = targets[~targets.index.isin(targets_in_hazard_zone.index.values)]
        targets_outside_hazard_zone.to_file(output_gpkg, layer='targets', driver=driver)

        assert len(targets_outside_hazard_zone) > 0, 'There are no targets outside the hazard zone'

        _, node_idx = nodes_tree.query(
            np.transpose([agents_in_hazard_zone.geometry.x, agents_in_hazard_zone.geometry.y]))

        _, target_node_idx = nodes_tree.query(
            np.transpose([targets_outside_hazard_zone.geometry.x, targets_outside_hazard_zone.geometry.y]))

        for (_, row), nearest_node in zip(targets_outside_hazard_zone.iterrows(), self.nodes.index[target_node_idx]):
            if not self.G.has_node(row.osmid):
                self.G.add_edge(nearest_node, row.osmid, length=0)
                self.G.nodes[row.osmid]['osmid'] = row.osmid
                self.G.nodes[row.osmid]['x'] = row.geometry.x
                self.G.nodes[row.osmid]['y'] = row.geometry.y

        self.nodes, self.edges = osmnx.save_load.graph_to_gdfs(self.G)

        self.nodes[['osmid', 'geometry']].to_file(output_gpkg, layer='nodes', driver=driver)
        self.edges[['osmid', 'geometry']].to_file(output_gpkg, layer='edges', driver=driver)

        output_gml = output_path + '.gml'
        osmnx.nx.write_gml(self.G, path=output_gml)
        self.igraph = igraph.read(output_gml)

        self.target_nodes = targets_outside_hazard_zone.osmid

        self.grid = NetworkGrid(self.G)

        # Create agents
        for i, idx in enumerate(node_idx):
            a = agent.EvacuationAgent(i, self)
            self.schedule.add(a)
            self.grid.place_agent(a, self.nodes.index[idx])
            a.update_route()
            a.update_location()

        self.data_collector = DataCollector(
            model_reporters={
                'evacuated': evacuated,
                'stranded': stranded
            },
            agent_reporters={'position': 'pos',
                             'reroute_count': 'reroute_count',
                             'lat': 'lat',
                             'lon': 'lon',
                             'highway': 'highway',
                             'status': status})

    def step(self):
        """Advances the model by one step and then stores the current state in data_collector"""
        self.schedule.step()
        self.data_collector.collect(self)

    def run(self, steps: int):
        """Runs the model for the given number of steps`

        Args:
            steps: number of steps to run the model for
        Returns:
            DataFrame: the agent vars dataframe
        """
        self.data_collector.collect(self)
        for _ in range(steps):
            self.step()
            if self.data_collector.model_vars['evacuated'][-1] + self.data_collector.model_vars['stranded'][-1] == len(
                    self.schedule.agents):
                # Continue for 5 steps after all agents evacuated or stranded
                for _ in range(5):
                    self.step()
                break
        self.data_collector.get_agent_vars_dataframe().astype({'highway': pd.Int64Dtype()}).to_csv(
            self.output_path + '.agent.csv')
        self.data_collector.get_model_vars_dataframe().to_csv(self.output_path + '.model.csv')
        return self.data_collector.get_agent_vars_dataframe()
コード例 #33
0
class Population(Model):
    """Population
    Adapted from https://www.medrxiv.org/content/10.1101/2020.03.18.20037994v1.full.pdf

    Model Parameters:
    spread_chance: probability of infection based on contact
    gamma: mean incubation period
    alpha: probability of become asymptomatic vs symptomatic
    gamma_AR: infectious period for asymptomatic people
    gamma_YR: infectious period for symptomatic people
    delta: death rate due to disease

    The social distancing func takes time passed -> new interaction multiplier
    """
    def __init__(self,
                 graph,
                 model_parameters,
                 social_distancing_func=lambda x: 1):

        # Model initialization
        self.population_size = model_parameters['population size']
        self.initial_outbreak_size = model_parameters['initial outbreak size']
        self.graph = graph
        self.grid = NetworkGrid(self.graph)
        self.schedule = SimultaneousActivation(self)
        self.social_distancing_func = social_distancing_func

        self.datacollector = DataCollector({  # "Exposed": count_exposed,
            "Susceptible": count_susceptible,
            "Recovered": count_recovered,
            # "Asymptomatic": count_asymptomatic,
            # "Symptomatic": count_symptomatic,
            "Diseased": count_diseased,
            "Removed": count_removed
        })
        self.model_parameters = model_parameters

        for i, node in enumerate(self.graph.nodes()):
            a = Person(i, self, State.SUSCEPTIBLE, model_parameters,
                       social_distancing_func)
            self.schedule.add(a)
            self.grid.place_agent(a, i)
            if i % 100 == 0:
                logger.info("Finished with agent " + str(i))

        infected_nodes = self.random.sample(self.graph.nodes(),
                                            self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.status = State.EXPOSED

        self.datacollector.collect(self)
        print("Model initialized...\n")

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()

    def run(self, n):
        for i in range(n):
            logger.info("Steps Completed: " + str(i))
            self.step()

    def run_until_stable(self):
        max_steps = 1e3
        steps = 0
        window_size = 50
        while steps < max_steps:
            self.step()
            logger.info("Steps Completed:" + str(steps))
            if steps > window_size:
                data = self.get_data()
                last_value = int(data.tail(1)['Diseased'])
                if last_value == 0:
                    break
                window_average = np.mean(
                    data.tail(window_size)
                    ['Diseased'])  # Window for determining stopping rule
                if abs(last_value - window_average) / window_average < 0.005:
                    break
            steps += 1

    def cross_influence(self, influence_coefficients, ratios):
        for inf_coeff, ratio in zip(influence_coefficients, ratios):
            susceptibles = list(
                filter(lambda x: x.status == State.SUSCEPTIBLE,
                       self.grid.get_all_cell_contents()))
            to_flip = self.random.sample(
                susceptibles, int(inf_coeff * ratio * len(susceptibles)))
            for agent in to_flip:
                agent.status = State.EXPOSED

    def clear_social_distancing_func(self):
        """
        Clears the social distancing function of the model and all its agents for pickling
        :return: None
        """
        self.social_distancing_func = None
        for agent in self.grid.get_all_cell_contents():
            agent.social_distancing_func = None

    def reinstate_social_distancing_func(self,
                                         social_distancing_func=lambda x: 1):
        """
        Re-adds the social distancing func to the model and all its agents
        :param social_distancing_func: social distancing func to be re-added
        :return: None
        """
        self.social_distancing_func = social_distancing_func
        for agent in self.grid.get_all_cell_contents():
            agent.social_distancing_func = social_distancing_func

    def save_model(self, filename):
        """
        Save the model to a pickle and dill file
        :param filename: filename (without extension) to save to
        :return: None
        """
        with open(filename + ".dil", 'wb') as f:
            dill.dump(self.social_distancing_func, f)
        self.clear_social_distancing_func()
        with open(filename + ".pkl", 'wb') as f:
            pickle.dump(self, f)

    def get_data(self):
        return self.datacollector.get_model_vars_dataframe()

    '''