From 9f27caff6bde6af77dc44443e1ce89443a22ef7e Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Thu, 22 Aug 2024 15:13:51 +0200 Subject: [PATCH] Revert PR #161: Replace schedulers with AgentSet functionality (#170) This commit reverts PR #161 https://github.com/projectmesa/mesa-examples/pull/161 That PR assumed that time advancement would be done automatically, like proposed in https://github.com/projectmesa/mesa/pull/2223 We encountered some underlying issues with time, which we couldn't resolve in time. --- examples/basic/boid_flockers/Flocker Test.ipynb | 2 +- .../boid_flockers/SimpleContinuousModule.py | 2 +- .../basic/boid_flockers/boid_flockers/model.py | 5 +++-- .../boltzmann_wealth_model/model.py | 8 ++++---- .../conways_game_of_life/cell.py | 4 ++-- .../conways_game_of_life/model.py | 17 ++++++++++++----- examples/basic/schelling/model.py | 6 ++++-- .../virus_on_network/virus_on_network/model.py | 6 +++--- 8 files changed, 30 insertions(+), 20 deletions(-) diff --git a/examples/basic/boid_flockers/Flocker Test.ipynb b/examples/basic/boid_flockers/Flocker Test.ipynb index c757f3a88ed..82ecc47b99f 100644 --- a/examples/basic/boid_flockers/Flocker Test.ipynb +++ b/examples/basic/boid_flockers/Flocker Test.ipynb @@ -25,7 +25,7 @@ "def draw_boids(model):\n", " x_vals = []\n", " y_vals = []\n", - " for boid in model.agents:\n", + " for boid in model.schedule.agents:\n", " x, y = boid.pos\n", " x_vals.append(x)\n", " y_vals.append(y)\n", diff --git a/examples/basic/boid_flockers/boid_flockers/SimpleContinuousModule.py b/examples/basic/boid_flockers/boid_flockers/SimpleContinuousModule.py index ec670d7af1c..42b3e9dd76f 100644 --- a/examples/basic/boid_flockers/boid_flockers/SimpleContinuousModule.py +++ b/examples/basic/boid_flockers/boid_flockers/SimpleContinuousModule.py @@ -18,7 +18,7 @@ def __init__(self, portrayal_method=None, canvas_height=500, canvas_width=500): def render(self, model): space_state = [] - for obj in model.agents: + for obj in model.schedule.agents: portrayal = self.portrayal_method(obj) x, y = obj.pos x = (x - model.space.x_min) / (model.space.x_max - model.space.x_min) diff --git a/examples/basic/boid_flockers/boid_flockers/model.py b/examples/basic/boid_flockers/boid_flockers/model.py index 6b032c33592..8ddfc11a2f4 100644 --- a/examples/basic/boid_flockers/boid_flockers/model.py +++ b/examples/basic/boid_flockers/boid_flockers/model.py @@ -120,7 +120,7 @@ def __init__( self.vision = vision self.speed = speed self.separation = separation - + self.schedule = mesa.time.RandomActivation(self) self.space = mesa.space.ContinuousSpace(width, height, True) self.factors = {"cohere": cohere, "separate": separate, "match": match} self.make_agents() @@ -144,6 +144,7 @@ def make_agents(self): **self.factors, ) self.space.place_agent(boid, pos) + self.schedule.add(boid) def step(self): - self.agents.shuffle().do("step") + self.schedule.step() diff --git a/examples/basic/boltzmann_wealth_model/boltzmann_wealth_model/model.py b/examples/basic/boltzmann_wealth_model/boltzmann_wealth_model/model.py index c34d0937dd3..11a3e95878a 100644 --- a/examples/basic/boltzmann_wealth_model/boltzmann_wealth_model/model.py +++ b/examples/basic/boltzmann_wealth_model/boltzmann_wealth_model/model.py @@ -2,7 +2,7 @@ def compute_gini(model): - agent_wealths = [agent.wealth for agent in model.agents] + agent_wealths = [agent.wealth for agent in model.schedule.agents] x = sorted(agent_wealths) N = model.num_agents B = sum(xi * (N - i) for i, xi in enumerate(x)) / (N * sum(x)) @@ -21,14 +21,14 @@ def __init__(self, N=100, width=10, height=10): super().__init__() self.num_agents = N self.grid = mesa.space.MultiGrid(width, height, True) - + self.schedule = mesa.time.RandomActivation(self) self.datacollector = mesa.DataCollector( model_reporters={"Gini": compute_gini}, agent_reporters={"Wealth": "wealth"} ) # Create agents for i in range(self.num_agents): a = MoneyAgent(i, self) - + self.schedule.add(a) # Add the agent to a random grid cell x = self.random.randrange(self.grid.width) y = self.random.randrange(self.grid.height) @@ -38,7 +38,7 @@ def __init__(self, N=100, width=10, height=10): self.datacollector.collect(self) def step(self): - self.agents.shuffle().do("step") + self.schedule.step() # collect data self.datacollector.collect(self) diff --git a/examples/basic/conways_game_of_life/conways_game_of_life/cell.py b/examples/basic/conways_game_of_life/conways_game_of_life/cell.py index d9e0e7ba076..8639288d4ca 100644 --- a/examples/basic/conways_game_of_life/conways_game_of_life/cell.py +++ b/examples/basic/conways_game_of_life/conways_game_of_life/cell.py @@ -24,7 +24,7 @@ def isAlive(self): def neighbors(self): return self.model.grid.iter_neighbors((self.x, self.y), True) - def determine_state(self): + def step(self): """ Compute if the cell will be dead or alive at the next tick. This is based on the number of alive or dead neighbors. The state is not @@ -46,7 +46,7 @@ def determine_state(self): if live_neighbors == 3: self._nextState = self.ALIVE - def assume_state(self): + def advance(self): """ Set the state to the new computed state -- computed in step(). """ diff --git a/examples/basic/conways_game_of_life/conways_game_of_life/model.py b/examples/basic/conways_game_of_life/conways_game_of_life/model.py index 76d9ca9fef4..f6c9637a67e 100644 --- a/examples/basic/conways_game_of_life/conways_game_of_life/model.py +++ b/examples/basic/conways_game_of_life/conways_game_of_life/model.py @@ -14,6 +14,15 @@ def __init__(self, width=50, height=50): Create a new playing area of (width, height) cells. """ super().__init__() + + # Set up the grid and schedule. + + # Use SimultaneousActivation which simulates all the cells + # computing their next state simultaneously. This needs to + # be done because each cell's next state depends on the current + # state of all its neighbors -- before they've changed. + self.schedule = mesa.time.SimultaneousActivation(self) + # Use a simple grid, where edges wrap around. self.grid = mesa.space.SingleGrid(width, height, torus=True) @@ -24,14 +33,12 @@ def __init__(self, width=50, height=50): if self.random.random() < 0.1: cell.state = cell.ALIVE self.grid.place_agent(cell, (x, y)) + self.schedule.add(cell) self.running = True def step(self): """ - Perform the model step in two stages: - - First, all cells assume their next state (whether they will be dead or alive) - - Then, all cells change state to their next state + Have the scheduler advance each cell by one step """ - self.agents.do("determine_state") - self.agents.do("assume_state") + self.schedule.step() diff --git a/examples/basic/schelling/model.py b/examples/basic/schelling/model.py index 5aa71415446..dfba4efb2b1 100644 --- a/examples/basic/schelling/model.py +++ b/examples/basic/schelling/model.py @@ -68,6 +68,7 @@ def __init__( self.homophily = homophily self.radius = radius + self.schedule = mesa.time.RandomActivation(self) self.grid = mesa.space.SingleGrid(width, height, torus=True) self.happy = 0 @@ -84,6 +85,7 @@ def __init__( agent_type = 1 if self.random.random() < self.minority_pc else 0 agent = SchellingAgent(self.next_id(), self, agent_type) self.grid.place_agent(agent, pos) + self.schedule.add(agent) self.datacollector.collect(self) @@ -92,9 +94,9 @@ def step(self): Run one step of the model. """ self.happy = 0 # Reset counter of happy agents - self.agents.shuffle().do("step") + self.schedule.step() self.datacollector.collect(self) - if self.happy == len(self.agents): + if self.happy == self.schedule.get_agent_count(): self.running = False diff --git a/examples/basic/virus_on_network/virus_on_network/model.py b/examples/basic/virus_on_network/virus_on_network/model.py index 7c69bdcd94e..a33e7545861 100644 --- a/examples/basic/virus_on_network/virus_on_network/model.py +++ b/examples/basic/virus_on_network/virus_on_network/model.py @@ -47,7 +47,7 @@ def __init__( prob = avg_node_degree / self.num_nodes self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob) self.grid = mesa.space.NetworkGrid(self.G) - + self.schedule = mesa.time.RandomActivation(self) self.initial_outbreak_size = ( initial_outbreak_size if initial_outbreak_size <= num_nodes else num_nodes ) @@ -75,7 +75,7 @@ def __init__( self.recovery_chance, self.gain_resistance_chance, ) - + self.schedule.add(a) # Add the agent to the node self.grid.place_agent(a, node) @@ -96,7 +96,7 @@ def resistant_susceptible_ratio(self): return math.inf def step(self): - self.agents.shuffle().do("step") + self.schedule.step() # collect data self.datacollector.collect(self)