Skip to content
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
- Add sugarcape_g1mt that is consistent with complexity tutorial
- Include interactive version with single run, batch run and server options
- Update .gitignore to ignore IDE environment files
  • Loading branch information
tpike3 committed Feb 2, 2023
commit ec4541a68a39cdd9942ee3153d4eb36e5f78faaf
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,24 @@ docs/_build/

# PyBuilder
target/

# Jupyter and iPython notebook checkpoints
*.ipynb_checkpoints

# Spyder app workspace config file
.spyderworkspace

# PyCharm environment files
.idea/

# VSCode environment files
.vscode/
*.code-workspace

# Apple OSX
*.DS_Store

# mypy
.mypy_cache/
.dmypy.json
dmypy.json
89 changes: 89 additions & 0 deletions examples/sugarscape_g1mt/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Sugarscape Constant Growback Model with Traders

## Summary

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.

### 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.
(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.

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).
- Considering only unoccupied sites find the nearest position that produces the most welfare using the Cobb-Douglas function.
- Move to the new position
- Collect all the resources (sugar and spice) at that location
(Epstein and Axtell, 1996, p. 99)

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
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
cross over one another otherwise *end*.
- This process then repeats until an *end* condition is met.
(Epstein and Axtell, 1996, p. 105)

The model demonstrates several Mesa concepts and features:
- MultiGrid
- Multiple agent types (traders, sugar, spice)
- Dynamically removing agents from the grid and schedule when they die
- Data Collection at the model and agent level
- Batchrunner (i.e. parameter sweeps)

## Installation

To install the dependencies use pip and the requirements.txt in this directory. e.g.

```
$ pip install -r requirements.txt
```

## How to Run

To run the model a single instance of the model:

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

To run the model with BatchRunner:

```
$ python run.py
```

To run the model interactively:

```
$ mesa runserver
```

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

## Files

* ``sugarscape_g1mt/trader_agents.py``: Defines the Trader agent class.
* ``sugarscape_g1mt/resource_agents.py``: Defines the Sugar and Spice agent classes.
* ``sugarscape_g1mt/model.py``: Manages the Sugarscape Constant Growback with Traders model.
* ``sugarscape_g1mt/sugar_map.txt``: Provides sugar and spice landscape in raster type format.
* ``server.py``: Sets up and launches and interactive visualization server.
* ``run.py``: Runs Server, Single Run or Batch Run with data collection and basic analysis.

## Additional Resources

- [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)
5 changes: 5 additions & 0 deletions examples/sugarscape_g1mt/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
jupyter
mesa
numpy
matplotlib
networkx
104 changes: 104 additions & 0 deletions examples/sugarscape_g1mt/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import sys
import pandas as pd
import matplotlib.pyplot as plt
import networkx as nx
import mesa
from sugarscape_g1mt.model import SugarscapeG1mt
from sugarscape_g1mt.server import server


# Analysis
def assess_results(results, single_agent):
# Make dataframe of results
results_df = pd.DataFrame(results)
# Plot and show mean price
plt.scatter(results_df["Step"], results_df["Price"], s=0.75)
plt.show()

if single_agent is not None:
plt.plot(results_df["Step"], results_df["Trader"])
plt.show()
else:
n = max(results_df["RunID"])
# Plot number of Traders
for i in range(n):
results_explore = results_df[results_df["RunId"] == i]
plt.plot(results_explore["Step"], results_explore["Trader"])
plt.show()

if single_agent is not None:
results_df = single_agent

# Show Trade Networks
# create graph object
print("Making Network")
G = nx.Graph()
trade = results_df.dropna(subset=["Trade Network"])
# add agent keys to make initial node set
G.add_nodes_from(list(trade["AgentID"].unique()))

# create edge list
for idx, row in trade.iterrows():
if len(row["Trade Network"]) > 0:
for agent in row["Trade Network"]:
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)))

# Plot histogram of degree distribution
degree_sequence = sorted((d for n, d in G.degree()), reverse=True)
degree_sequence = [d for n, d in G.degree()]
plt.hist(degree_sequence)
plt.show()

# Plot network
nx.draw(G)
plt.show()


# Run the model

args = sys.argv[1:]


if args[0] == "runserver":
server.launch()

elif "s" in args[0] or "Single" in args[0]:
print("Running Single Model")
# instantiate the model
model = SugarscapeG1mt()
# run the model
model.run_model()
# Get results
model_results = model.datacollector.get_model_vars_dataframe()
# Convert to make similar to batch_run_results
model_results["Step"] = model_results.index
agent_results = model.datacollector.get_agent_vars_dataframe()
agent_results = agent_results.reset_index()
# assess the results
assess_results(model_results, agent_results)

else:
print("Conducting a Batch Run")
# Batch Run
params = {
"width": 50,
"height": 50,
"vision_min": range(1, 3),
"metabolism_max": [3, 5],
}

results_batch = mesa.batch_run(
SugarscapeG1mt,
parameters=params,
iterations=1,
number_processes=1,
data_collection_period=1,
display_progress=True,
)

assess_results(results_batch, None)
Empty file.
Loading