Skip to content

Commit

Permalink
Use pre-commit (#27)
Browse files Browse the repository at this point in the history
* Use Pathlib

Code by Phil Robare (versilimidude2)

* Use pre-commit

* Dropped unused imports

* used pre-commit to run pyupgrade, trim whitespace

* Remove pathlib changes

These belong in a separate PR.

* remove redundant black, move comment

as per rht's suggestions

---------

Co-authored-by: Catherine Devlin <[email protected]>
  • Loading branch information
2 people authored and rht committed May 18, 2023
1 parent 50b422b commit e83c64e
Show file tree
Hide file tree
Showing 36 changed files with 127 additions and 85 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,5 @@ dmypy.json

# Virtual environment
venv/

examples/caching_and_replay/my_cache_file_path.cache
20 changes: 20 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
ci:
autoupdate_schedule: 'monthly'
autofix_prs: false

repos:
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black-jupyter
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
hooks:
- id: pyupgrade
args: [--py38-plus]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0 # Use the ref you want to point at
hooks:
- id: trailing-whitespace
- id: check-toml
- id: check-yaml
4 changes: 2 additions & 2 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
Contributing
=========================

As an open source project, Mesa welcomes contributions of many forms, and from beginners to experts.
As an open source project, Mesa welcomes contributions of many forms, and from beginners to experts.

Contributions can a full model or it could one of the following to an existing model:
Contributions can a full model or it could one of the following to an existing model:

- Code patches
- Bug reports and patch reviews
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# mesa-examples

This repository contains examples that work with Mesa and illustrate different features of Mesa.
This repository contains examples that work with Mesa and illustrate different features of Mesa.

To contribute to this repository, see `CONTRIBUTING.rst`_

Expand Down
9 changes: 6 additions & 3 deletions examples/bank_reserves/bank_reserves/agents.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
The following code was adapted from the Bank Reserves model included in Netlogo
Model information can be found at: http://ccl.northwestern.edu/netlogo/models/BankReserves
Model information can be found at:
http://ccl.northwestern.edu/netlogo/models/BankReserves
Accessed on: November 2, 2017
Author of NetLogo code:
Wilensky, U. (1998). NetLogo Bank Reserves model.
Expand Down Expand Up @@ -76,12 +77,14 @@ def do_business(self):
if self.random.randint(0, 1) == 0:
# 50% chance of trading $5
if self.random.randint(0, 1) == 0:
# give customer $5 from my wallet (may result in negative wallet)
# give customer $5 from my wallet
# (may result in negative wallet)
customer.wallet += 5
self.wallet -= 5
# 50% chance of trading $2
else:
# give customer $2 from my wallet (may result in negative wallet)
# give customer $2 from my wallet
# (may result in negative wallet)
customer.wallet += 2
self.wallet -= 2

Expand Down
3 changes: 2 additions & 1 deletion examples/bank_reserves/bank_reserves/model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
The following code was adapted from the Bank Reserves model included in Netlogo
Model information can be found at: http://ccl.northwestern.edu/netlogo/models/BankReserves
Model information can be found at:
http://ccl.northwestern.edu/netlogo/models/BankReserves
Accessed on: November 2, 2017
Author of NetLogo code:
Wilensky, U. (1998). NetLogo Bank Reserves model.
Expand Down
3 changes: 2 additions & 1 deletion examples/bank_reserves/batch_run.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
The following code was adapted from the Bank Reserves model included in Netlogo
Model information can be found at: http://ccl.northwestern.edu/netlogo/models/BankReserves
Model information can be found at:
http://ccl.northwestern.edu/netlogo/models/BankReserves
Accessed on: November 2, 2017
Author of NetLogo code:
Wilensky, U. (1998). NetLogo Bank Reserves model.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ class BoltzmannWealthModelNetwork(mesa.Model):
"""A model with some number of agents."""

def __init__(self, num_agents=7, num_nodes=10):

self.num_agents = num_agents
self.num_nodes = num_nodes if num_nodes >= self.num_agents else self.num_agents
self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=0.5)
Expand Down Expand Up @@ -65,7 +64,6 @@ def move(self):
self.model.grid.move_agent(self, new_position)

def give_money(self):

neighbors_nodes = self.model.grid.get_neighbors(self.pos, include_center=False)
neighbors = self.model.grid.get_cell_list_contents(neighbors_nodes)
if len(neighbors) > 0:
Expand Down
4 changes: 2 additions & 2 deletions examples/caching_and_replay/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ It uses the [Mesa-Replay](https://github.com/Logende/mesa-replay) library and pu
From the user's perspective, the new model behaves the same way as the original Schelling model, but additionally supports caching.

Note that the main purpose of this example is to demonstrate that caching and replaying simulation runs is possible.
The example is designed to be accessible.
The example is designed to be accessible.
In practice, someone who wants to replay their simulation might not necessarily embed a replay button into the web view, but instead have a dedicated script to run a simulation that is being cached, separate from a script to replay a simulation run from a given cache file.
More examples of caching and replay can be found in the [Mesa-Replay Repository](https://github.com/Logende/mesa-replay/tree/main/examples).

Expand All @@ -31,7 +31,7 @@ To run the model interactively, run ``mesa runserver`` in this directory. e.g.

Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and press Reset, then Run.

First, run the **simulation** with the 'Replay' switch disabled.
First, run the **simulation** with the 'Replay' switch disabled.
When the simulation run is finished (e.g. all agents are happy, no more new steps are simulated), the run will automatically be stored in a cache file.

Next, **replay** your latest cached simulation run by enabling the Replay switch and then pressing Reset.
Expand Down
17 changes: 11 additions & 6 deletions examples/caching_and_replay/cacheablemodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@


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 wrapper that can be put around any regular mesa model
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."""
"""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 wrapper that can be put around any regular mesa model 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,
Expand All @@ -16,7 +20,8 @@ def __init__(
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
# 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)
Expand Down
9 changes: 6 additions & 3 deletions examples/charts/charts/agents.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
The following code was adapted from the Bank Reserves model included in Netlogo
Model information can be found at: http://ccl.northwestern.edu/netlogo/models/BankReserves
Model information can be found at:
http://ccl.northwestern.edu/netlogo/models/BankReserves
Accessed on: November 2, 2017
Author of NetLogo code:
Wilensky, U. (1998). NetLogo Bank Reserves model.
Expand Down Expand Up @@ -76,12 +77,14 @@ def do_business(self):
if self.random.randint(0, 1) == 0:
# 50% chance of trading $5
if self.random.randint(0, 1) == 0:
# give customer $5 from my wallet (may result in negative wallet)
# give customer $5 from my wallet
# (may result in negative wallet)
customer.wallet += 5
self.wallet -= 5
# 50% chance of trading $2
else:
# give customer $2 from my wallet (may result in negative wallet)
# give customer $2 from my wallet
# (may result in negative wallet)
customer.wallet += 2
self.wallet -= 2

Expand Down
4 changes: 2 additions & 2 deletions examples/charts/charts/model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
The following code was adapted from the Bank Reserves model included in Netlogo
Model information can be found at: http://ccl.northwestern.edu/netlogo/models/BankReserves
Model information can be found at:
http://ccl.northwestern.edu/netlogo/models/BankReserves
Accessed on: November 2, 2017
Author of NetLogo code:
Wilensky, U. (1998). NetLogo Bank Reserves model.
Expand Down Expand Up @@ -80,7 +81,6 @@ def get_total_loans(model):


class Charts(mesa.Model):

# grid height
grid_h = 20
# grid width
Expand Down
4 changes: 2 additions & 2 deletions examples/color_patches/color_patches/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def __init__(self, width=20, height=20):
# -->but only col & row
# for (contents, col, row) in self._grid.coord_iter():
# replaced content with _ to appease linter
for (_, row, col) in self._grid.coord_iter():
for _, row, col in self._grid.coord_iter():
cell = ColorCell(
(row, col), self, ColorCell.OPINIONS[self.random.randrange(0, 16)]
)
Expand Down Expand Up @@ -115,7 +115,7 @@ def grid(self):
80 cell_objects = model.grid.get_cell_list_contents([(x, y)])
AttributeError: 'ColorPatches' object has no attribute 'grid'
"""
""" # noqa: E501
return self._grid

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(self, width=50, height=50):

# Place a cell at each location, with some initialized to
# ALIVE and some to DEAD.
for (contents, x, y) in self.grid.coord_iter():
for contents, x, y in self.grid.coord_iter():
cell = Cell((x, y), self)
if self.random.random() < 0.1:
cell.state = cell.ALIVE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def __init__(
unique_id = 0
if self.cop_density + self.citizen_density > 1:
raise ValueError("Cop density + citizen density must be less than 1")
for (contents, x, y) in self.grid.coord_iter():
for contents, x, y in self.grid.coord_iter():
if self.random.random() < self.cop_density:
cop = Cop(unique_id, self, (x, y), vision=self.cop_vision)
unique_id += 1
Expand Down
2 changes: 1 addition & 1 deletion examples/forest_fire/forest_fire/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(self, width=100, height=100, density=0.65):
)

# Place a tree in each cell with Prob = density
for (contents, x, y) in self.grid.coord_iter():
for contents, x, y in self.grid.coord_iter():
if self.random.random() < density:
# Create a tree
new_tree = TreeCell((x, y), self)
Expand Down
4 changes: 3 additions & 1 deletion examples/hex_snowflake/hex_snowflake/cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ def step(self):
changed here, but is just computed and stored in self._nextState,
because our current state may still be necessary for our neighbors
to calculate their next state.
When a cell is made alive, its neighbors are able to be considered in the next step. Only cells that are considered check their neighbors for performance reasons.
When a cell is made alive, its neighbors are able to be considered
in the next step. Only cells that are considered check their neighbors
for performance reasons.
"""
# assume no state change
self._nextState = self.state
Expand Down
5 changes: 3 additions & 2 deletions examples/hex_snowflake/hex_snowflake/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

class HexSnowflake(mesa.Model):
"""
Represents the hex grid of cells. The grid is represented by a 2-dimensional array of cells with adjacency rules specific to hexagons.
Represents the hex grid of cells. The grid is represented by a 2-dimensional array
of cells with adjacency rules specific to hexagons.
"""

def __init__(self, width=50, height=50):
Expand All @@ -25,7 +26,7 @@ def __init__(self, width=50, height=50):
self.grid = mesa.space.HexGrid(width, height, torus=True)

# Place a dead cell at each location.
for (contents, x, y) in self.grid.coord_iter():
for contents, x, y in self.grid.coord_iter():
cell = Cell((x, y), self)
self.grid.place_agent(cell, (x, y))
self.schedule.add(cell)
Expand Down
4 changes: 3 additions & 1 deletion examples/pd_grid/pd_grid/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ def isCooroperating(self):
return self.move == "C"

def step(self):
"""Get the best neighbor's move, and change own move accordingly if better than own score."""
"""Get the best neighbor's move, and change own move accordingly
if better than own score."""

neighbors = self.model.grid.get_neighbors(self.pos, True, include_center=True)
best_neighbor = max(neighbors, key=lambda a: a.score)
self.next_move = best_neighbor.move
Expand Down
1 change: 0 additions & 1 deletion examples/shape_example/shape_example/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ def agent_draw(agent):
"Layer": 2,
"Color": ["#00FF00", "#99FF99"],
"stroke_color": "#666666",
"Filled": "true",
"heading_x": agent.heading[0],
"heading_y": agent.heading[1],
"text": agent.unique_id,
Expand Down
1 change: 0 additions & 1 deletion examples/sugarscape_cg/sugarscape_cg/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ def step(self):
print([self.schedule.time, self.schedule.get_type_count(SsAgent)])

def run_model(self, step_count=200):

if self.verbose:
print(
"Initial number Sugarscape Agent: ",
Expand Down
24 changes: 12 additions & 12 deletions examples/sugarscape_g1mt/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
This is Epstein & Axtell's Sugarscape model with Traders, a detailed description is in Chapter four of
*Growing Artificial Societies: Social Science from the Bottom Up.* (1996)

This code generally matches the code in the Complexity Explorer Tutorial, but in `.py` instead of `.ipynb` format.
This code generally matches the code in the Complexity Explorer Tutorial, but in `.py` instead of `.ipynb` format.

### Agents:
### Agents:

- **Sugar**: Sugar agents grow back at one unit per time step and can be harvested and traded by the trader agents. Sugar
is unequally distributed across the landscape with sugar hills in the upper left and lower right of the space.
(green if you do the interactive run)
- **Spice**: Spice agents grow back at one unit per time step and can be harvested and traded by the trader agents. Spice
is unequally distributed across the landscape with spice hills in the upper right and lower left of the space.
is unequally distributed across the landscape with spice hills in the upper right and lower left of the space.
(yellow if you do the interactive run)
- **Traders**: Trader agents have the following attributes: (1) metabolism for sugar, (2) metabolism for spice, (3) vision,
(4) initial sugar endowment and (5) initial spice endowment. The traverse the landscape harvesting sugar and spice and
trading with other agents. If they run out of sugar or spice then they are removed from the model.
(4) initial sugar endowment and (5) initial spice endowment. The traverse the landscape harvesting sugar and spice and
trading with other agents. If they run out of sugar or spice then they are removed from the model.

The trader agents traverse the landscape according to rule **M**:
- Look out as far as vision permits in the four principal lattice directions and identify the unoccupied site(s).
Expand All @@ -26,15 +26,15 @@ The trader agents traverse the landscape according to rule **M**:
- Collect all the resources (sugar and spice) at that location
(Epstein and Axtell, 1996, p. 99)

The traders trade according to rule **T**:
The traders trade according to rule **T**:
- Agents and potential trade partner compute their marginal rates of substitution (MRS), if they are equal *end*.
- Exchange resources, with spice flowing from the agent with the higher MRS to the agent with the lower MRS and sugar
- Exchange resources, with spice flowing from the agent with the higher MRS to the agent with the lower MRS and sugar
flowing the opposite direction.
- The price (p) is calculated by taking the geometric mean of the agents' MRS.
- If p > 1 then p units of spice are traded for 1 unit of sugar; if p < 1 then 1/p units of sugar for 1 unit of spice
- The trade occurs if it will (a) make both agent better off (increases MRS) and (b) does not cause the agents' MRS to
- The trade occurs if it will (a) make both agent better off (increases MRS) and (b) does not cause the agents' MRS to
cross over one another otherwise *end*.
- This process then repeats until an *end* condition is met.
- This process then repeats until an *end* condition is met.
(Epstein and Axtell, 1996, p. 105)

The model demonstrates several Mesa concepts and features:
Expand All @@ -54,13 +54,13 @@ To install the dependencies use pip and the requirements.txt in this directory.

## How to Run

To run the model a single instance of the model:
To run the model a single instance of the model:

```
$ python run.py -s
```

To run the model with BatchRunner:
To run the model with BatchRunner:

```
$ python run.py -b
Expand All @@ -85,5 +85,5 @@ Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and p

## Additional Resources

- [Growing Artificial Societies](https://mitpress.mit.edu/9780262550253/growing-artificial-societies/)
- [Growing Artificial Societies](https://mitpress.mit.edu/9780262550253/growing-artificial-societies/)
- [Complexity Explorer Sugarscape with Traders Tutorial](https://www.complexityexplorer.org/courses/172-agent-based-models-with-python-an-introduction-to-mesa)
6 changes: 3 additions & 3 deletions examples/sugarscape_g1mt/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ def assess_results(results, single_agent):
G.add_edge(row["AgentID"], agent)

# Get Basic Network Statistics
print("Node Connectivity {}".format(nx.node_connectivity(G)))
print("Average Clustering {}".format(nx.average_clustering(G)))
print("Global Efficiency {}".format(nx.global_efficiency(G)))
print(f"Node Connectivity {nx.node_connectivity(G)}")
print(f"Average Clustering {nx.average_clustering(G)}")
print(f"Global Efficiency {nx.global_efficiency(G)}")

# Plot histogram of degree distribution
degree_sequence = sorted((d for n, d in G.degree()), reverse=True)
Expand Down
Loading

0 comments on commit e83c64e

Please sign in to comment.