Skip to content

Commit

Permalink
Replace the remaining schedulers with AgentSet functionality (project…
Browse files Browse the repository at this point in the history
…mesa#202)

This PR completes the migration from schedulers to AgentSet functionality across the mesa-examples repository for all regular (non-`gis`/-`rl`) examples. Key changes include:

- Replaced `RandomActivation`, `SimultaneousActivation`, and `RandomActivationByType` schedulers with appropriate AgentSet methods
- Updated `Model.step()` implementations to use AgentSet activation
- Removed references to `schedule.steps`, `schedule.agents`, and `schedule.agents_by_type`
- Updated agent addition/removal logic to work with AgentSets
- Adjusted data collection and visualization code to use `Model.steps` and `Model.agents`

For more details on migrating from schedulers to AgentSets, see the migration guide: https://mesa.readthedocs.io/en/latest/migration_guide.html#time-and-schedulers
  • Loading branch information
EwoutH authored Sep 21, 2024
1 parent 0f4b939 commit e23b804
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 26 deletions.
2 changes: 1 addition & 1 deletion examples/advanced/pd_grid/analysis.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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}\")"
]
},
{
Expand Down
4 changes: 2 additions & 2 deletions examples/advanced/pd_grid/pd_grid/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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]
Expand Down
31 changes: 18 additions & 13 deletions examples/advanced/pd_grid/pd_grid/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,39 @@
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)

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"]
)
}
)
Expand All @@ -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):
Expand Down
6 changes: 3 additions & 3 deletions examples/advanced/pd_grid/pd_grid/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
),
}

Expand Down
2 changes: 1 addition & 1 deletion examples/advanced/pd_grid/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions examples/advanced/sugarscape_g1mt/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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).
Expand Down
5 changes: 1 addition & 4 deletions examples/advanced/wolf_sheep/wolf_sheep/test_random_walk.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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):
Expand Down

0 comments on commit e23b804

Please sign in to comment.