Skip to content

Commit c5dccc1

Browse files
Improve Caching and Replay Example (#102)
* Improve Caching and Replay * Update to benchmark * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update model.py * Update run.py * Update cacheablemodel.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 64b43d2 commit c5dccc1

File tree

5 files changed

+95
-39
lines changed

5 files changed

+95
-39
lines changed

examples/caching_and_replay/README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Summary
44

5-
This example applies caching on the Mesa [Schelling example](https://github.com/projectmesa/mesa-examples/tree/main/examples/Schelling).
5+
This example applies caching on the Mesa [Schelling example](https://github.com/projectmesa/mesa-examples/tree/main/examples/schelling).
66
It enables a simulation run to be "cached" or in other words recorded. The recorded simulation run is persisted on the local file system and can be replayed at any later point.
77

88
It uses the [Mesa-Replay](https://github.com/Logende/mesa-replay) library and puts the Schelling model inside a so-called `CacheableModel` wrapper that we name `CacheableSchelling`.
@@ -29,6 +29,14 @@ To run the model interactively, run ``mesa runserver`` in this directory. e.g.
2929
$ mesa runserver
3030
```
3131

32+
or
33+
34+
Directly run the file ``run.py`` in the terminal. e.g.
35+
36+
```
37+
$ python run.py
38+
```
39+
3240
Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and press Reset, then Run.
3341

3442
First, run the **simulation** with the 'Replay' switch disabled.

examples/caching_and_replay/cacheablemodel.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@
33

44

55
class CacheableSchelling(CacheableModel):
6-
"""A wrapper around the original Schelling model to make the simulation cacheable
6+
"""
7+
A wrapper around the original Schelling model to make the simulation cacheable
78
and replay-able. Uses CacheableModel from the Mesa-Replay library,
89
which is a wrapper that can be put around any regular mesa model to make it
910
"cacheable".
1011
From outside, a CacheableSchelling instance can be treated like any
1112
regular Mesa model.
1213
The only difference is that the model will write the state of every simulation step
1314
to a cache file or when in replay mode use a given cache file to replay that cached
14-
simulation run."""
15+
simulation run.
16+
"""
1517

1618
def __init__(
1719
self,
@@ -20,14 +22,23 @@ def __init__(
2022
density=0.8,
2123
minority_pc=0.2,
2224
homophily=3,
25+
radius=1,
26+
cache_file_path="./my_cache_file_path.cache",
2327
# Note that this is an additional parameter we add to our model,
2428
# which decides whether to simulate or replay
2529
replay=False,
2630
):
27-
actual_model = Schelling(width, height, density, minority_pc, homophily)
31+
actual_model = Schelling(
32+
width=width,
33+
height=height,
34+
density=density,
35+
minority_pc=minority_pc,
36+
homophily=homophily,
37+
radius=radius,
38+
)
2839
cache_state = CacheState.REPLAY if replay else CacheState.RECORD
2940
super().__init__(
30-
actual_model,
31-
cache_file_path="my_cache_file_path.cache",
41+
model=actual_model,
42+
cache_file_path=cache_file_path,
3243
cache_state=cache_state,
3344
)

examples/caching_and_replay/model.py

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class SchellingAgent(mesa.Agent):
88
Schelling segregation agent
99
"""
1010

11-
def __init__(self, pos, model, agent_type):
11+
def __init__(self, unique_id, model, agent_type):
1212
"""
1313
Create a new Schelling agent.
1414
@@ -17,13 +17,14 @@ def __init__(self, pos, model, agent_type):
1717
x, y: Agent initial location.
1818
agent_type: Indicator for the agent's type (minority=1, majority=0)
1919
"""
20-
super().__init__(pos, model)
21-
self.pos = pos
20+
super().__init__(unique_id, model)
2221
self.type = agent_type
2322

2423
def step(self):
2524
similar = 0
26-
for neighbor in self.model.grid.iter_neighbors(self.pos, True):
25+
for neighbor in self.model.grid.iter_neighbors(
26+
self.pos, moore=True, radius=self.model.radius
27+
):
2728
if neighbor.type == self.type:
2829
similar += 1
2930

@@ -39,48 +40,64 @@ class Schelling(mesa.Model):
3940
Model class for the Schelling segregation model.
4041
"""
4142

42-
def __init__(self, width=20, height=20, density=0.8, minority_pc=0.2, homophily=3):
43-
""" """
44-
super().__init__()
45-
self.width = width
43+
def __init__(
44+
self,
45+
height=20,
46+
width=20,
47+
homophily=3,
48+
radius=1,
49+
density=0.8,
50+
minority_pc=0.3,
51+
seed=None,
52+
):
53+
"""
54+
Create a new Schelling model.
55+
56+
Args:
57+
width, height: Size of the space.
58+
density: Initial Chance for a cell to populated
59+
minority_pc: Chances for an agent to be in minority class
60+
homophily: Minimum number of agents of same class needed to be happy
61+
radius: Search radius for checking similarity
62+
seed: Seed for Reproducibility
63+
"""
64+
65+
super().__init__(seed=seed)
4666
self.height = height
67+
self.width = width
4768
self.density = density
4869
self.minority_pc = minority_pc
4970
self.homophily = homophily
71+
self.radius = radius
5072

5173
self.schedule = mesa.time.RandomActivation(self)
5274
self.grid = mesa.space.SingleGrid(width, height, torus=True)
5375

5476
self.happy = 0
5577
self.datacollector = mesa.DataCollector(
56-
{"happy": "happy"}, # Model-level count of happy agents
57-
# For testing purposes, agent's individual x and y
58-
{"x": lambda a: a.pos[0], "y": lambda a: a.pos[1]},
78+
model_reporters={"happy": "happy"}, # Model-level count of happy agents
5979
)
6080

6181
# Set up agents
6282
# We use a grid iterator that returns
6383
# the coordinates of a cell as well as
6484
# its contents. (coord_iter)
65-
for cell in self.grid.coord_iter():
66-
x, y = cell[1]
85+
for _, pos in self.grid.coord_iter():
6786
if self.random.random() < self.density:
6887
agent_type = 1 if self.random.random() < self.minority_pc else 0
69-
70-
agent = SchellingAgent((x, y), self, agent_type)
71-
self.grid.place_agent(agent, (x, y))
88+
agent = SchellingAgent(self.next_id(), self, agent_type)
89+
self.grid.place_agent(agent, pos)
7290
self.schedule.add(agent)
7391

74-
self.running = True
7592
self.datacollector.collect(self)
7693

7794
def step(self):
7895
"""
79-
Run one step of the model. If All agents are happy, halt the model.
96+
Run one step of the model.
8097
"""
8198
self.happy = 0 # Reset counter of happy agents
8299
self.schedule.step()
83-
# collect data
100+
84101
self.datacollector.collect(self)
85102

86103
if self.happy == self.schedule.get_agent_count():

examples/caching_and_replay/run.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,30 @@
66

77
# As 'replay' is a simulation model parameter in this example, we need to make it available as such
88
model_params["replay"] = mesa.visualization.Checkbox("Replay cached run?", False)
9+
model_params["cache_file_path"] = "./my_cache_file_path.cache"
910

1011

1112
def get_cache_file_status(_):
1213
"""
1314
Display an informational text about caching and the status of the cache file (existing versus not existing)
1415
"""
15-
cache_file = Path("./my_cache_file_path.cache")
16+
cache_file = Path(model_params["cache_file_path"])
1617
return (
1718
f"Only activate the 'Replay cached run?' switch when a cache file already exists, otherwise it will fail. "
1819
f"Cache file existing: '{cache_file.exists()}'."
1920
)
2021

2122

2223
server = mesa.visualization.ModularServer(
23-
# Note that Schelling was replaced by CacheableSchelling here
24-
CacheableSchelling,
25-
[get_cache_file_status, canvas_element, get_happy_agents, happy_chart],
26-
"Schelling",
27-
model_params,
24+
model_cls=CacheableSchelling, # Note that Schelling was replaced by CacheableSchelling here
25+
visualization_elements=[
26+
get_cache_file_status,
27+
canvas_element,
28+
get_happy_agents,
29+
happy_chart,
30+
],
31+
name="Schelling Segregation Model",
32+
model_params=model_params,
2833
)
2934

3035
server.launch()

examples/caching_and_replay/server.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,35 @@ def schelling_draw(agent):
2828
return portrayal
2929

3030

31-
canvas_element = mesa.visualization.CanvasGrid(schelling_draw, 20, 20, 500, 500)
31+
canvas_element = mesa.visualization.CanvasGrid(
32+
portrayal_method=schelling_draw,
33+
grid_width=20,
34+
grid_height=20,
35+
canvas_width=500,
36+
canvas_height=500,
37+
)
3238
happy_chart = mesa.visualization.ChartModule([{"Label": "happy", "Color": "Black"}])
3339

3440
model_params = {
3541
"height": 20,
3642
"width": 20,
37-
"density": mesa.visualization.Slider("Agent density", 0.6, 0.1, 1.0, 0.1),
38-
"minority_pc": mesa.visualization.Slider("Fraction minority", 0.2, 0.00, 1.0, 0.05),
39-
"homophily": mesa.visualization.Slider("Homophily", 2, 0, 8, 1),
43+
"density": mesa.visualization.Slider(
44+
name="Agent density", value=0.8, min_value=0.1, max_value=1.0, step=0.1
45+
),
46+
"minority_pc": mesa.visualization.Slider(
47+
name="Fraction minority", value=0.2, min_value=0.00, max_value=1.0, step=0.05
48+
),
49+
"homophily": mesa.visualization.Slider(
50+
name="Homophily", value=3, min_value=0, max_value=8, step=1
51+
),
52+
"radius": mesa.visualization.Slider(
53+
name="Search Radius", value=1, min_value=1, max_value=5, step=1
54+
),
4055
}
4156

4257
server = mesa.visualization.ModularServer(
43-
Schelling,
44-
[canvas_element, get_happy_agents, happy_chart],
45-
"Schelling",
46-
model_params,
58+
model_cls=Schelling,
59+
visualization_elements=[canvas_element, get_happy_agents, happy_chart],
60+
name="Schelling Segregation Model",
61+
model_params=model_params,
4762
)

0 commit comments

Comments
 (0)