-
-
Notifications
You must be signed in to change notification settings - Fork 188
add the example 'caching_and_replay' which uses Mesa-Replay #14
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
Merged
Merged
Changes from 2 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
04f0973
add the example 'caching_and_replay' which uses Mesa-Replay
Logende bfc96c2
incorporate review findings
Logende 4e1f2ea
remove "decorator" from description to avoid misunderstanding, as it …
Logende 623bfe3
update ReadMe of Schelling Model with Caching and Replay
Logende 4d967c4
update README and add cache status information to web view
Logende 8ca554a
reformat using black
Logende fcdddc0
incorporate feedback
Logende File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Caching and Replaying Schelling | ||
|
||
## Summary | ||
|
||
This example applies caching on the Mesa [Schelling example](https://github.com/projectmesa/mesa-examples/tree/main/examples/Schelling). | ||
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. | ||
|
||
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`. | ||
From the user's perspective, the new model behaves the same way as the original Schelling model, but additionally supports caching. | ||
|
||
## Installation | ||
|
||
To install the dependencies use pip and the requirements.txt in this directory. e.g. | ||
|
||
``` | ||
$ pip install -r requirements.txt | ||
Logende marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
## How to Run | ||
|
||
To run the model interactively, run ``mesa runserver`` in this directory. e.g. | ||
|
||
``` | ||
$ mesa runserver | ||
``` | ||
|
||
Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and press Reset, then Run. | ||
|
||
After running a regular simulation, you can **replay** your latest simulation run by first enabling the Replay switch and then pressing Reset. | ||
Logende marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
Note that this **requires the previous simulation run to have finished** (e.g. all agents are happy, no more new steps are simulated). | ||
|
||
## Files | ||
|
||
* ``run.py``: Launches a model visualization server and uses `CacheableModelSchelling` as simulation model | ||
* ``cacheablemodel.py``: Implements `CacheableModelSchelling` to make the original Schelling model cacheable | ||
* ``model.py``: Taken from the original Mesa Schelling example | ||
* ``server.py``: Taken from the original Mesa Schelling example | ||
|
||
## Further Reading | ||
|
||
* [Mesa-Replay library](https://github.com/Logende/mesa-replay) | ||
* [More caching and replay examples](https://github.com/Logende/mesa-replay/tree/main/examples) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
from model import Schelling | ||
from mesa_replay import CacheableModel, CacheState | ||
|
||
|
||
class CacheableSchelling(CacheableModel): | ||
"""A wrapper around the original Schelling model to make the simulation cacheable and replay-able. | ||
Uses CacheableModel from the Mesa-Replay library, which is a decorator that can be put around any regular mesa model | ||
Logende marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
to make it "cacheable". From outside, a CacheableSchelling instance can be treated like any regular Mesa model. | ||
The only difference is that the model will write the state of every simulation step to a cache file or when in | ||
replay mode use a given cache file to replay that cached simulation run.""" | ||
|
||
def __init__( | ||
self, | ||
width=20, | ||
height=20, | ||
density=0.8, | ||
minority_pc=0.2, | ||
homophily=3, | ||
# Note that this is an additional parameter we add to our model, which decides whether to simulate or replay | ||
replay=False, | ||
): | ||
actual_model = Schelling(width, height, density, minority_pc, homophily) | ||
cache_state = CacheState.REPLAY if replay else CacheState.RECORD | ||
super().__init__( | ||
actual_model, | ||
cache_file_path="my_cache_file_path.cache", | ||
cache_state=cache_state, | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
"""This file was copied over from the original Schelling mesa example.""" | ||
|
||
import mesa | ||
|
||
|
||
class SchellingAgent(mesa.Agent): | ||
""" | ||
Schelling segregation agent | ||
""" | ||
|
||
def __init__(self, pos, model, agent_type): | ||
""" | ||
Create a new Schelling agent. | ||
|
||
Args: | ||
unique_id: Unique identifier for the agent. | ||
x, y: Agent initial location. | ||
agent_type: Indicator for the agent's type (minority=1, majority=0) | ||
""" | ||
super().__init__(pos, model) | ||
self.pos = pos | ||
self.type = agent_type | ||
|
||
def step(self): | ||
similar = 0 | ||
for neighbor in self.model.grid.iter_neighbors(self.pos, True): | ||
if neighbor.type == self.type: | ||
similar += 1 | ||
|
||
# If unhappy, move: | ||
if similar < self.model.homophily: | ||
self.model.grid.move_to_empty(self) | ||
else: | ||
self.model.happy += 1 | ||
|
||
|
||
class Schelling(mesa.Model): | ||
""" | ||
Model class for the Schelling segregation model. | ||
""" | ||
|
||
def __init__(self, width=20, height=20, density=0.8, minority_pc=0.2, homophily=3): | ||
""" """ | ||
|
||
self.width = width | ||
self.height = height | ||
self.density = density | ||
self.minority_pc = minority_pc | ||
self.homophily = homophily | ||
|
||
self.schedule = mesa.time.RandomActivation(self) | ||
self.grid = mesa.space.SingleGrid(width, height, torus=True) | ||
|
||
self.happy = 0 | ||
self.datacollector = mesa.DataCollector( | ||
{"happy": "happy"}, # Model-level count of happy agents | ||
# For testing purposes, agent's individual x and y | ||
{"x": lambda a: a.pos[0], "y": lambda a: a.pos[1]}, | ||
) | ||
|
||
# Set up agents | ||
# We use a grid iterator that returns | ||
# the coordinates of a cell as well as | ||
# its contents. (coord_iter) | ||
for cell in self.grid.coord_iter(): | ||
x = cell[1] | ||
y = cell[2] | ||
if self.random.random() < self.density: | ||
if self.random.random() < self.minority_pc: | ||
agent_type = 1 | ||
else: | ||
agent_type = 0 | ||
|
||
agent = SchellingAgent((x, y), self, agent_type) | ||
self.grid.place_agent(agent, (x, y)) | ||
self.schedule.add(agent) | ||
|
||
self.running = True | ||
self.datacollector.collect(self) | ||
|
||
def step(self): | ||
""" | ||
Run one step of the model. If All agents are happy, halt the model. | ||
""" | ||
self.happy = 0 # Reset counter of happy agents | ||
self.schedule.step() | ||
# collect data | ||
self.datacollector.collect(self) | ||
|
||
if self.happy == self.schedule.get_agent_count(): | ||
self.running = False |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
mesa | ||
git+https://github.com/Logende/mesa-replay@main#egg=Mesa-Replay |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import mesa | ||
|
||
from server import ( | ||
canvas_element, | ||
get_happy_agents, | ||
happy_chart, | ||
model_params, | ||
) | ||
from cacheablemodel import CacheableSchelling | ||
|
||
# As 'replay' is a simulation model parameter in this example, we need to make it available as such | ||
model_params["replay"] = mesa.visualization.Checkbox("Replay last run?", False) | ||
|
||
server = mesa.visualization.ModularServer( | ||
# Note that Schelling was replaced by CacheableSchelling here | ||
CacheableSchelling, | ||
[canvas_element, get_happy_agents, happy_chart], | ||
"Schelling", | ||
model_params, | ||
) | ||
|
||
server.launch() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
"""This file was copied over from the original Schelling mesa example.""" | ||
|
||
import mesa | ||
|
||
from model import Schelling | ||
|
||
|
||
def get_happy_agents(model): | ||
""" | ||
Display a text count of how many happy agents there are. | ||
""" | ||
return f"Happy agents: {model.happy}" | ||
|
||
|
||
def schelling_draw(agent): | ||
""" | ||
Portrayal Method for canvas | ||
""" | ||
if agent is None: | ||
return | ||
portrayal = {"Shape": "circle", "r": 0.5, "Filled": "true", "Layer": 0} | ||
|
||
if agent.type == 0: | ||
portrayal["Color"] = ["#FF0000", "#FF9999"] | ||
portrayal["stroke_color"] = "#00FF00" | ||
else: | ||
portrayal["Color"] = ["#0000FF", "#9999FF"] | ||
portrayal["stroke_color"] = "#000000" | ||
return portrayal | ||
|
||
|
||
canvas_element = mesa.visualization.CanvasGrid(schelling_draw, 20, 20, 500, 500) | ||
happy_chart = mesa.visualization.ChartModule([{"Label": "happy", "Color": "Black"}]) | ||
|
||
model_params = { | ||
"height": 20, | ||
"width": 20, | ||
"density": mesa.visualization.Slider("Agent density", 0.6, 0.1, 1.0, 0.1), | ||
"minority_pc": mesa.visualization.Slider("Fraction minority", 0.2, 0.00, 1.0, 0.05), | ||
"homophily": mesa.visualization.Slider("Homophily", 2, 0, 8, 1), | ||
} | ||
|
||
server = mesa.visualization.ModularServer( | ||
Schelling, | ||
[canvas_element, get_happy_agents, happy_chart], | ||
"Schelling", | ||
model_params, | ||
) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.