Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace the remaining schedulers with AgentSet functionality #202

Merged
merged 7 commits into from
Sep 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/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/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/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/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/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
8 changes: 4 additions & 4 deletions examples/schelling/analysis.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
},
{
Expand Down Expand Up @@ -328,15 +328,15 @@
" 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",
" segregated = False\n",
" break\n",
" if segregated:\n",
" segregated_agents += 1\n",
" return segregated_agents / model.schedule.get_agent_count()"
" return segregated_agents / len(model.agents)"
]
},
{
Expand Down
8 changes: 4 additions & 4 deletions examples/schelling_experimental/analysis.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
},
{
Expand Down Expand Up @@ -328,15 +328,15 @@
" 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",
" segregated = False\n",
" break\n",
" if segregated:\n",
" segregated_agents += 1\n",
" return segregated_agents / model.schedule.get_agent_count()"
" return segregated_agents / len(model.agents)"
]
},
{
Expand Down
3 changes: 1 addition & 2 deletions examples/sugarscape_cg/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion examples/sugarscape_cg/sugarscape_cg/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
18 changes: 7 additions & 11 deletions examples/sugarscape_cg/sugarscape_cg/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand All @@ -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
EwoutH marked this conversation as resolved.
Show resolved Hide resolved
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])}"
)
4 changes: 2 additions & 2 deletions examples/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/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
Loading