diff --git a/examples/pd_grid/analysis.ipynb b/examples/pd_grid/analysis.ipynb index 1fe69759..e3f52170 100644 --- a/examples/pd_grid/analysis.ipynb +++ b/examples/pd_grid/analysis.ipynb @@ -72,7 +72,7 @@ " grid[y][x] = 0\n", " ax.pcolormesh(grid, cmap=bwr, vmin=0, vmax=1)\n", " ax.axis(\"off\")\n", - " ax.set_title(f\"Steps: {model.schedule.steps}\")" + " ax.set_title(f\"Steps: {model.steps}\")" ] }, { diff --git a/examples/pd_grid/pd_grid/agent.py b/examples/pd_grid/pd_grid/agent.py index 40e6ca52..85121327 100644 --- a/examples/pd_grid/pd_grid/agent.py +++ b/examples/pd_grid/pd_grid/agent.py @@ -33,7 +33,7 @@ def step(self): best_neighbor = max(neighbors, key=lambda a: a.score) self.next_move = best_neighbor.move - if self.model.schedule_type != "Simultaneous": + if self.model.activation_order != "Simultaneous": self.advance() def advance(self): @@ -42,7 +42,7 @@ def advance(self): def increment_score(self): neighbors = self.model.grid.get_neighbors(self.pos, True) - if self.model.schedule_type == "Simultaneous": + if self.model.activation_order == "Simultaneous": moves = [neighbor.next_move for neighbor in neighbors] else: moves = [neighbor.move for neighbor in neighbors] diff --git a/examples/pd_grid/pd_grid/model.py b/examples/pd_grid/pd_grid/model.py index cf3512ad..b1c2a05c 100644 --- a/examples/pd_grid/pd_grid/model.py +++ b/examples/pd_grid/pd_grid/model.py @@ -6,11 +6,7 @@ class PdGrid(mesa.Model): """Model class for iterated, spatial prisoner's dilemma model.""" - schedule_types = { - "Sequential": mesa.time.BaseScheduler, - "Random": mesa.time.RandomActivation, - "Simultaneous": mesa.time.SimultaneousActivation, - } + activation_regimes = ["Sequential", "Random", "Simultaneous"] # This dictionary holds the payoff for this agent, # keyed on: (my_move, other_move) @@ -18,33 +14,31 @@ class PdGrid(mesa.Model): payoff = {("C", "C"): 1, ("C", "D"): 0, ("D", "C"): 1.6, ("D", "D"): 0} def __init__( - self, width=50, height=50, schedule_type="Random", payoffs=None, seed=None + self, width=50, height=50, activation_order="Random", payoffs=None, seed=None ): """ Create a new Spatial Prisoners' Dilemma Model. Args: width, height: Grid size. There will be one agent per grid cell. - schedule_type: Can be "Sequential", "Random", or "Simultaneous". + activation_order: Can be "Sequential", "Random", or "Simultaneous". Determines the agent activation regime. payoffs: (optional) Dictionary of (move, neighbor_move) payoffs. """ super().__init__() + self.activation_order = activation_order self.grid = mesa.space.SingleGrid(width, height, torus=True) - self.schedule_type = schedule_type - self.schedule = self.schedule_types[self.schedule_type](self) # Create agents for x in range(width): for y in range(height): agent = PDAgent(self) self.grid.place_agent(agent, (x, y)) - self.schedule.add(agent) self.datacollector = mesa.DataCollector( { "Cooperating_Agents": lambda m: len( - [a for a in m.schedule.agents if a.move == "C"] + [a for a in m.agents if a.move == "C"] ) } ) @@ -53,8 +47,19 @@ def __init__( self.datacollector.collect(self) def step(self): - self.schedule.step() - # collect data + # Activate all agents, based on the activation regime + match self.activation_order: + case "Sequential": + self.agents.do("step") + case "Random": + self.agents.shuffle_do("step") + case "Simultaneous": + self.agents.do("step") + self.agents.do("advance") + case _: + raise ValueError(f"Unknown activation order: {self.activation_order}") + + # Collect data self.datacollector.collect(self) def run(self, n): diff --git a/examples/pd_grid/pd_grid/server.py b/examples/pd_grid/pd_grid/server.py index f2447da3..57785acc 100644 --- a/examples/pd_grid/pd_grid/server.py +++ b/examples/pd_grid/pd_grid/server.py @@ -9,10 +9,10 @@ model_params = { "height": 50, "width": 50, - "schedule_type": mesa.visualization.Choice( - "Scheduler type", + "activation_order": mesa.visualization.Choice( + "Activation regime", value="Random", - choices=list(PdGrid.schedule_types.keys()), + choices=PdGrid.activation_regimes, ), } diff --git a/examples/pd_grid/readme.md b/examples/pd_grid/readme.md index 8b4bc40c..51b91fd4 100644 --- a/examples/pd_grid/readme.md +++ b/examples/pd_grid/readme.md @@ -28,7 +28,7 @@ Launch the ``Demographic Prisoner's Dilemma Activation Schedule.ipynb`` notebook ## Files * ``run.py`` is the entry point for the font-end simulations. -* ``pd_grid/``: contains the model and agent classes; the model takes a ``schedule_type`` string as an argument, which determines what schedule type the model uses: Sequential, Random or Simultaneous. +* ``pd_grid/``: contains the model and agent classes; the model takes a ``activation_order`` string as an argument, which determines in which order agents are activated: Sequential, Random or Simultaneous. * ``Demographic Prisoner's Dilemma Activation Schedule.ipynb``: Jupyter Notebook for running the scheduling experiment. This runs the model three times, one for each activation type, and demonstrates how the activation regime drives the model to different outcomes. ## Further Reading diff --git a/examples/schelling/analysis.ipynb b/examples/schelling/analysis.ipynb index 50f382c6..71d925c1 100644 --- a/examples/schelling/analysis.ipynb +++ b/examples/schelling/analysis.ipynb @@ -65,9 +65,9 @@ } ], "source": [ - "while model.running and model.schedule.steps < 100:\n", + "while model.running and model.steps < 100:\n", " model.step()\n", - "print(model.schedule.steps) # Show how many steps have actually run" + "print(model.steps) # Show how many steps have actually run" ] }, { @@ -328,7 +328,7 @@ " Find the % of agents that only have neighbors of their same type.\n", " \"\"\"\n", " segregated_agents = 0\n", - " for agent in model.schedule.agents:\n", + " for agent in model.agents:\n", " segregated = True\n", " for neighbor in model.grid.iter_neighbors(agent.pos, True):\n", " if neighbor.type != agent.type:\n", @@ -336,7 +336,7 @@ " break\n", " if segregated:\n", " segregated_agents += 1\n", - " return segregated_agents / model.schedule.get_agent_count()" + " return segregated_agents / len(model.agents)" ] }, { diff --git a/examples/schelling_experimental/analysis.ipynb b/examples/schelling_experimental/analysis.ipynb index 50f382c6..71d925c1 100644 --- a/examples/schelling_experimental/analysis.ipynb +++ b/examples/schelling_experimental/analysis.ipynb @@ -65,9 +65,9 @@ } ], "source": [ - "while model.running and model.schedule.steps < 100:\n", + "while model.running and model.steps < 100:\n", " model.step()\n", - "print(model.schedule.steps) # Show how many steps have actually run" + "print(model.steps) # Show how many steps have actually run" ] }, { @@ -328,7 +328,7 @@ " Find the % of agents that only have neighbors of their same type.\n", " \"\"\"\n", " segregated_agents = 0\n", - " for agent in model.schedule.agents:\n", + " for agent in model.agents:\n", " segregated = True\n", " for neighbor in model.grid.iter_neighbors(agent.pos, True):\n", " if neighbor.type != agent.type:\n", @@ -336,7 +336,7 @@ " break\n", " if segregated:\n", " segregated_agents += 1\n", - " return segregated_agents / model.schedule.get_agent_count()" + " return segregated_agents / len(model.agents)" ] }, { diff --git a/examples/sugarscape_cg/Readme.md b/examples/sugarscape_cg/Readme.md index 948272b6..0334a628 100644 --- a/examples/sugarscape_cg/Readme.md +++ b/examples/sugarscape_cg/Readme.md @@ -21,7 +21,7 @@ The model is tests and demonstrates several Mesa concepts and features: - MultiGrid - Multiple agent types (ants, sugar patches) - Overlay arbitrary text (wolf's energy) on agent's shapes while drawing on CanvasGrid - - Dynamically removing agents from the grid and schedule when they die + - Dynamically removing agents from the grid and model when they die ## Installation @@ -44,7 +44,6 @@ Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and p ## Files * ``sugarscape/agents.py``: Defines the SsAgent, and Sugar agent classes. -* ``sugarscape/schedule.py``: This is exactly based on wolf_sheep/schedule.py. * ``sugarscape/model.py``: Defines the Sugarscape Constant Growback model itself * ``sugarscape/server.py``: Sets up the interactive visualization server * ``run.py``: Launches a model visualization server. diff --git a/examples/sugarscape_cg/sugarscape_cg/agents.py b/examples/sugarscape_cg/sugarscape_cg/agents.py index 05e56e78..a75f07c2 100644 --- a/examples/sugarscape_cg/sugarscape_cg/agents.py +++ b/examples/sugarscape_cg/sugarscape_cg/agents.py @@ -67,7 +67,7 @@ def step(self): self.eat() if self.sugar <= 0: self.model.grid.remove_agent(self) - self.model.schedule.remove(self) + self.remove() class Sugar(mesa.Agent): diff --git a/examples/sugarscape_cg/sugarscape_cg/model.py b/examples/sugarscape_cg/sugarscape_cg/model.py index 1436adb9..667e9b37 100644 --- a/examples/sugarscape_cg/sugarscape_cg/model.py +++ b/examples/sugarscape_cg/sugarscape_cg/model.py @@ -37,10 +37,9 @@ def __init__(self, width=50, height=50, initial_population=100): self.height = height self.initial_population = initial_population - self.schedule = mesa.time.RandomActivationByType(self) self.grid = mesa.space.MultiGrid(self.width, self.height, torus=False) self.datacollector = mesa.DataCollector( - {"SsAgent": lambda m: m.schedule.get_type_count(SsAgent)} + {"SsAgent": lambda m: len(m.agents_by_type[SsAgent])} ) # Create sugar @@ -51,7 +50,6 @@ def __init__(self, width=50, height=50, initial_population=100): max_sugar = sugar_distribution[x, y] sugar = Sugar(self, max_sugar) self.grid.place_agent(sugar, (x, y)) - self.schedule.add(sugar) # Create agent: for i in range(self.initial_population): @@ -62,31 +60,29 @@ def __init__(self, width=50, height=50, initial_population=100): vision = self.random.randrange(1, 6) ssa = SsAgent(self, False, sugar, metabolism, vision) self.grid.place_agent(ssa, (x, y)) - self.schedule.add(ssa) self.running = True self.datacollector.collect(self) def step(self): - self.schedule.step() + # Step suger and agents + self.agents_by_type[Sugar].do("step") + self.agents_by_type[SsAgent].shuffle_do("step") # collect data self.datacollector.collect(self) if self.verbose: - print([self.schedule.time, self.schedule.get_type_count(SsAgent)]) + print(f"Step: {self.steps}, SsAgents: {len(self.agents_by_type[SsAgent])}") def run_model(self, step_count=200): if self.verbose: print( - "Initial number Sugarscape Agent: ", - self.schedule.get_type_count(SsAgent), + f"Initial number Sugarscape Agents: {len(self.agents_by_type[SsAgent])}" ) for i in range(step_count): self.step() if self.verbose: - print("") print( - "Final number Sugarscape Agent: ", - self.schedule.get_type_count(SsAgent), + f"\nFinal number Sugarscape Agents: {len(self.agents_by_type[SsAgent])}" ) diff --git a/examples/sugarscape_g1mt/tests.py b/examples/sugarscape_g1mt/tests.py index bcfcf739..274afa6b 100644 --- a/examples/sugarscape_g1mt/tests.py +++ b/examples/sugarscape_g1mt/tests.py @@ -23,7 +23,7 @@ def test_decreasing_price_variance(): model.datacollector._new_model_reporter( "price_variance", lambda m: np.var( - flatten([a.prices for a in m.schedule.agents_by_type[Trader].values()]) + flatten([a.prices for a in m.agents_by_type[Trader].values()]) ), ) model.run_model(step_count=50) @@ -40,7 +40,7 @@ def calculate_carrying_capacities(enable_trade): for vision_max in visions: model = SugarscapeG1mt(vision_max=vision_max, enable_trade=enable_trade) model.run_model(step_count=50) - carrying_capacities.append(len(model.schedule.agents_by_type[Trader])) + carrying_capacities.append(len(model.agents_by_type[Trader])) return carrying_capacities # Carrying capacity should increase over mean vision (figure IV-6). diff --git a/examples/wolf_sheep/wolf_sheep/test_random_walk.py b/examples/wolf_sheep/wolf_sheep/test_random_walk.py index d2340fed..393a46b1 100644 --- a/examples/wolf_sheep/wolf_sheep/test_random_walk.py +++ b/examples/wolf_sheep/wolf_sheep/test_random_walk.py @@ -5,7 +5,6 @@ from mesa import Model from mesa.space import MultiGrid -from mesa.time import RandomActivation from mesa.visualization.TextVisualization import TextGrid, TextVisualization from wolf_sheep.random_walk import RandomWalker @@ -40,17 +39,15 @@ def __init__(self, width, height, agent_count): self.grid = MultiGrid(self.width, self.height, torus=True) self.agent_count = agent_count - self.schedule = RandomActivation(self) # Create agents for i in range(self.agent_count): x = self.random.randrange(self.width) y = self.random.randrange(self.height) a = WalkerAgent(i, (x, y), self, True) - self.schedule.add(a) self.grid.place_agent(a, (x, y)) def step(self): - self.schedule.step() + self.agents.shuffle_do("step") class WalkerWorldViz(TextVisualization):