Mesa 3.0.0a5__py3-none-any.whl → 3.0.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Mesa might be problematic. Click here for more details.

Files changed (91) hide show
  1. examples/README.md +37 -0
  2. examples/__init__.py +0 -0
  3. examples/advanced/__init__.py +0 -0
  4. examples/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb +116 -0
  5. examples/advanced/epstein_civil_violence/Readme.md +33 -0
  6. examples/advanced/epstein_civil_violence/epstein_civil_violence/__init__.py +0 -0
  7. examples/advanced/epstein_civil_violence/epstein_civil_violence/agent.py +158 -0
  8. examples/advanced/epstein_civil_violence/epstein_civil_violence/model.py +146 -0
  9. examples/advanced/epstein_civil_violence/epstein_civil_violence/portrayal.py +33 -0
  10. examples/advanced/epstein_civil_violence/epstein_civil_violence/server.py +81 -0
  11. examples/advanced/epstein_civil_violence/requirements.txt +3 -0
  12. examples/advanced/epstein_civil_violence/run.py +3 -0
  13. examples/advanced/pd_grid/analysis.ipynb +228 -0
  14. examples/advanced/pd_grid/pd_grid/__init__.py +0 -0
  15. examples/advanced/pd_grid/pd_grid/agent.py +50 -0
  16. examples/advanced/pd_grid/pd_grid/model.py +72 -0
  17. examples/advanced/pd_grid/pd_grid/portrayal.py +19 -0
  18. examples/advanced/pd_grid/pd_grid/server.py +21 -0
  19. examples/advanced/pd_grid/readme.md +42 -0
  20. examples/advanced/pd_grid/requirements.txt +3 -0
  21. examples/advanced/pd_grid/run.py +3 -0
  22. examples/advanced/sugarscape_g1mt/Readme.md +87 -0
  23. examples/advanced/sugarscape_g1mt/app.py +61 -0
  24. examples/advanced/sugarscape_g1mt/requirements.txt +6 -0
  25. examples/advanced/sugarscape_g1mt/run.py +105 -0
  26. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/__init__.py +0 -0
  27. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/model.py +180 -0
  28. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/resource_agents.py +26 -0
  29. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/server.py +61 -0
  30. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/sugar-map.txt +50 -0
  31. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/trader_agents.py +321 -0
  32. examples/advanced/sugarscape_g1mt/tests.py +72 -0
  33. examples/advanced/wolf_sheep/Readme.md +57 -0
  34. examples/advanced/wolf_sheep/__init__.py +0 -0
  35. examples/advanced/wolf_sheep/requirements.txt +1 -0
  36. examples/advanced/wolf_sheep/run.py +3 -0
  37. examples/advanced/wolf_sheep/wolf_sheep/__init__.py +0 -0
  38. examples/advanced/wolf_sheep/wolf_sheep/agents.py +102 -0
  39. examples/advanced/wolf_sheep/wolf_sheep/model.py +136 -0
  40. examples/advanced/wolf_sheep/wolf_sheep/resources/sheep.png +0 -0
  41. examples/advanced/wolf_sheep/wolf_sheep/resources/wolf.png +0 -0
  42. examples/advanced/wolf_sheep/wolf_sheep/server.py +78 -0
  43. examples/basic/__init__.py +13 -0
  44. examples/basic/boid_flockers/Readme.md +43 -0
  45. examples/basic/boid_flockers/agents.py +71 -0
  46. examples/basic/boid_flockers/app.py +59 -0
  47. examples/basic/boid_flockers/model.py +70 -0
  48. examples/basic/boltzmann_wealth_model/Readme.md +60 -0
  49. examples/basic/boltzmann_wealth_model/agents.py +31 -0
  50. examples/basic/boltzmann_wealth_model/app.py +66 -0
  51. examples/basic/boltzmann_wealth_model/model.py +44 -0
  52. examples/basic/boltzmann_wealth_model/st_app.py +115 -0
  53. examples/basic/conways_game_of_life/Readme.md +35 -0
  54. examples/basic/conways_game_of_life/agents.py +47 -0
  55. examples/basic/conways_game_of_life/model.py +32 -0
  56. examples/basic/conways_game_of_life/portrayal.py +18 -0
  57. examples/basic/conways_game_of_life/requirements.txt +1 -0
  58. examples/basic/conways_game_of_life/server.py +11 -0
  59. examples/basic/conways_game_of_life/st_app.py +71 -0
  60. examples/basic/schelling/README.md +47 -0
  61. examples/basic/schelling/agents.py +26 -0
  62. examples/basic/schelling/analysis.ipynb +205 -0
  63. examples/basic/schelling/app.py +43 -0
  64. examples/basic/schelling/model.py +60 -0
  65. examples/basic/virus_on_network/README.md +61 -0
  66. examples/basic/virus_on_network/agents.py +69 -0
  67. examples/basic/virus_on_network/app.py +133 -0
  68. examples/basic/virus_on_network/model.py +99 -0
  69. mesa/__init__.py +4 -1
  70. mesa/agent.py +24 -43
  71. mesa/batchrunner.py +7 -0
  72. mesa/examples.py +3 -0
  73. mesa/experimental/__init__.py +8 -2
  74. mesa/experimental/cell_space/__init__.py +7 -1
  75. mesa/experimental/cell_space/cell.py +35 -6
  76. mesa/experimental/cell_space/cell_agent.py +114 -23
  77. mesa/experimental/cell_space/discrete_space.py +70 -3
  78. mesa/experimental/cell_space/grid.py +13 -0
  79. mesa/experimental/cell_space/network.py +3 -0
  80. mesa/experimental/devs/examples/wolf_sheep.py +2 -1
  81. mesa/model.py +71 -21
  82. mesa/time.py +7 -5
  83. mesa/visualization/components/matplotlib.py +184 -90
  84. mesa/visualization/solara_viz.py +25 -61
  85. {mesa-3.0.0a5.dist-info → mesa-3.0.0b1.dist-info}/METADATA +55 -13
  86. mesa-3.0.0b1.dist-info/RECORD +114 -0
  87. mesa-3.0.0b1.dist-info/licenses/LICENSE +202 -0
  88. mesa-3.0.0a5.dist-info/licenses/LICENSE → mesa-3.0.0b1.dist-info/licenses/NOTICE +2 -2
  89. mesa-3.0.0a5.dist-info/RECORD +0 -44
  90. {mesa-3.0.0a5.dist-info → mesa-3.0.0b1.dist-info}/WHEEL +0 -0
  91. {mesa-3.0.0a5.dist-info → mesa-3.0.0b1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,87 @@
1
+ # Sugarscape Constant Growback Model with Traders
2
+
3
+ ## Summary
4
+
5
+ This is Epstein & Axtell's Sugarscape model with Traders, a detailed description is in Chapter four of
6
+ *Growing Artificial Societies: Social Science from the Bottom Up (1996)*. The model shows an emergent price equilibrium can happen via a decentralized dynamics.
7
+
8
+ This code generally matches the code in the Complexity Explorer Tutorial, but in `.py` instead of `.ipynb` format.
9
+
10
+ ### Agents:
11
+
12
+ - **Resource**: Resource agents grow back at one unit of sugar and spice per time step up to a specified max amount and can be harvested and traded by the trader agents.
13
+ (if you do the interactive run, the color will be green if the resource agent has a bigger amount of sugar, or yellow if it has a bigger amount of spice)
14
+ - **Traders**: Trader agents have the following attributes: (1) metabolism for sugar, (2) metabolism for spice, (3) vision,
15
+ (4) initial sugar endowment and (5) initial spice endowment. The traverse the landscape harvesting sugar and spice and
16
+ trading with other agents. If they run out of sugar or spice then they are removed from the model. (red circle if you do the interactive run)
17
+
18
+ The trader agents traverse the landscape according to rule **M**:
19
+ - Look out as far as vision permits in the four principal lattice directions and identify the unoccupied site(s).
20
+ - Considering only unoccupied sites find the nearest position that produces the most welfare using the Cobb-Douglas function.
21
+ - Move to the new position
22
+ - Collect all the resources (sugar and spice) at that location
23
+ (Epstein and Axtell, 1996, p. 99)
24
+
25
+ The traders trade according to rule **T**:
26
+ - Agents and potential trade partner compute their marginal rates of substitution (MRS), if they are equal *end*.
27
+ - Exchange resources, with spice flowing from the agent with the higher MRS to the agent with the lower MRS and sugar
28
+ flowing the opposite direction.
29
+ - The price (p) is calculated by taking the geometric mean of the agents' MRS.
30
+ - 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
31
+ - The trade occurs if it will (a) make both agent better off (increases MRS) and (b) does not cause the agents' MRS to
32
+ cross over one another otherwise *end*.
33
+ - This process then repeats until an *end* condition is met.
34
+ (Epstein and Axtell, 1996, p. 105)
35
+
36
+ The model demonstrates several Mesa concepts and features:
37
+ - MultiGrid
38
+ - Multiple agent types (traders, sugar, spice)
39
+ - Dynamically removing agents from the grid and schedule when they die
40
+ - Data Collection at the model and agent level
41
+ - Batchrunner (i.e. parameter sweeps)
42
+
43
+ ## Installation
44
+
45
+ To install the dependencies use pip and the requirements.txt in this directory. e.g.
46
+
47
+ ```
48
+ $ pip install -r requirements.txt
49
+ ```
50
+
51
+ ## How to Run
52
+
53
+ To run the model a single instance of the model:
54
+
55
+ ```
56
+ $ python run.py -s
57
+ ```
58
+
59
+ To run the model with BatchRunner:
60
+
61
+ ```
62
+ $ python run.py -b
63
+ ```
64
+
65
+ To run the model interactively:
66
+
67
+ ```
68
+ $ mesa runserver
69
+ ```
70
+
71
+ Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and press Reset, then Run.
72
+
73
+ ## Files
74
+
75
+ * `sugarscape_g1mt/trader_agents.py`: Defines the Trader agent class.
76
+ * `sugarscape_g1mt/resource_agents.py`: Defines the Resource agent class which contains an amount of sugar and spice.
77
+ * `sugarscape_g1mt/model.py`: Manages the Sugarscape Constant Growback with Traders model.
78
+ * `sugarscape_g1mt/sugar_map.txt`: Provides sugar and spice landscape in raster type format.
79
+ * `server.py`: Sets up an interactive visualization server.
80
+ * `run.py`: Runs Server, Single Run or Batch Run with data collection and basic analysis.
81
+ * `app.py`: Runs a visualization server via Solara (`solara run app.py`).
82
+ * `tests.py`: Has tests to ensure that the model reproduces the results in shown in Growing Artificial Societies.
83
+
84
+ ## Additional Resources
85
+
86
+ - [Growing Artificial Societies](https://mitpress.mit.edu/9780262550253/growing-artificial-societies/)
87
+ - [Complexity Explorer Sugarscape with Traders Tutorial](https://www.complexityexplorer.org/courses/172-agent-based-models-with-python-an-introduction-to-mesa)
@@ -0,0 +1,61 @@
1
+ import numpy as np
2
+ import solara
3
+ from matplotlib.figure import Figure
4
+ from mesa.visualization import SolaraViz, make_plot_measure
5
+ from sugarscape_g1mt.model import SugarscapeG1mt
6
+ from sugarscape_g1mt.trader_agents import Trader
7
+
8
+
9
+ def SpaceDrawer(model):
10
+ def portray(g):
11
+ layers = {
12
+ "sugar": [[np.nan for j in range(g.height)] for i in range(g.width)],
13
+ "spice": [[np.nan for j in range(g.height)] for i in range(g.width)],
14
+ "trader": {"x": [], "y": [], "c": "tab:red", "marker": "o", "s": 10},
15
+ }
16
+
17
+ for content, (i, j) in g.coord_iter():
18
+ for agent in content:
19
+ if isinstance(agent, Trader):
20
+ layers["trader"]["x"].append(i)
21
+ layers["trader"]["y"].append(j)
22
+ else:
23
+ # Don't visualize resource with value <= 1.
24
+ layers["sugar"][i][j] = (
25
+ agent.sugar_amount if agent.sugar_amount > 1 else np.nan
26
+ )
27
+ layers["spice"][i][j] = (
28
+ agent.spice_amount if agent.spice_amount > 1 else np.nan
29
+ )
30
+ return layers
31
+
32
+ fig = Figure()
33
+ ax = fig.subplots()
34
+ out = portray(model.grid)
35
+ # Sugar
36
+ # Important note: imshow by default draws from upper left. You have to
37
+ # always explicitly specify origin="lower".
38
+ im = ax.imshow(out["sugar"], cmap="spring", origin="lower")
39
+ fig.colorbar(im, orientation="vertical")
40
+ # Spice
41
+ ax.imshow(out["spice"], cmap="winter", origin="lower")
42
+ # Trader
43
+ ax.scatter(**out["trader"])
44
+ ax.set_axis_off()
45
+ return solara.FigureMatplotlib(fig)
46
+
47
+
48
+ model_params = {
49
+ "width": 50,
50
+ "height": 50,
51
+ }
52
+
53
+ model1 = SugarscapeG1mt(50, 50)
54
+
55
+ page = SolaraViz(
56
+ model1,
57
+ components=[SpaceDrawer, make_plot_measure(["Trader", "Price"])],
58
+ name="Sugarscape {G1, M, T}",
59
+ play_interval=1500,
60
+ )
61
+ page # noqa
@@ -0,0 +1,6 @@
1
+ jupyter
2
+ mesa~=2.0
3
+ numpy
4
+ matplotlib
5
+ networkx
6
+ pandas
@@ -0,0 +1,105 @@
1
+ import sys
2
+
3
+ import matplotlib.pyplot as plt
4
+ import mesa
5
+ import networkx as nx
6
+ import pandas as pd
7
+ from sugarscape_g1mt.model import SugarscapeG1mt
8
+ from sugarscape_g1mt.server import server
9
+
10
+
11
+ # Analysis
12
+ def assess_results(results, single_agent):
13
+ # Make dataframe of results
14
+ results_df = pd.DataFrame(results)
15
+ # Plot and show mean price
16
+ plt.scatter(results_df["Step"], results_df["Price"], s=0.75)
17
+ plt.show()
18
+
19
+ if single_agent is not None:
20
+ plt.plot(results_df["Step"], results_df["Trader"])
21
+ plt.show()
22
+ else:
23
+ n = max(results_df["RunId"])
24
+ # Plot number of Traders
25
+ for i in range(n):
26
+ results_explore = results_df[results_df["RunId"] == i]
27
+ plt.plot(results_explore["Step"], results_explore["Trader"])
28
+ plt.show()
29
+
30
+ if single_agent is not None:
31
+ results_df = single_agent
32
+
33
+ # Show Trade Networks
34
+ # create graph object
35
+ print("Making Network")
36
+ G = nx.Graph()
37
+ trade = results_df.dropna(subset=["Trade Network"])
38
+ # add agent keys to make initial node set
39
+ G.add_nodes_from(list(trade["AgentID"].unique()))
40
+
41
+ # create edge list
42
+ for idx, row in trade.iterrows():
43
+ if len(row["Trade Network"]) > 0:
44
+ for agent in row["Trade Network"]:
45
+ G.add_edge(row["AgentID"], agent)
46
+
47
+ # Get Basic Network Statistics
48
+ print(f"Node Connectivity {nx.node_connectivity(G)}")
49
+ print(f"Average Clustering {nx.average_clustering(G)}")
50
+ print(f"Global Efficiency {nx.global_efficiency(G)}")
51
+
52
+ # Plot histogram of degree distribution
53
+ degree_sequence = sorted((d for n, d in G.degree()), reverse=True)
54
+ degree_sequence = [d for n, d in G.degree()]
55
+ plt.hist(degree_sequence)
56
+ plt.show()
57
+
58
+ # Plot network
59
+ nx.draw(G)
60
+ plt.show()
61
+
62
+
63
+ # Run the model
64
+ def main():
65
+ args = sys.argv[1:]
66
+
67
+ if len(args) == 0:
68
+ server.launch()
69
+
70
+ elif args[0] == "-s":
71
+ print("Running Single Model")
72
+ model = SugarscapeG1mt()
73
+ model.run_model()
74
+ model_results = model.datacollector.get_model_vars_dataframe()
75
+ model_results["Step"] = model_results.index
76
+ agent_results = model.datacollector.get_agent_vars_dataframe()
77
+ agent_results = agent_results.reset_index()
78
+ assess_results(model_results, agent_results)
79
+
80
+ elif args[0] == "-b":
81
+ print("Conducting a Batch Run")
82
+ params = {
83
+ "width": 50,
84
+ "height": 50,
85
+ "vision_min": range(1, 4),
86
+ "metabolism_max": [2, 3, 4, 5],
87
+ }
88
+
89
+ results_batch = mesa.batch_run(
90
+ SugarscapeG1mt,
91
+ parameters=params,
92
+ iterations=1,
93
+ number_processes=1,
94
+ data_collection_period=1,
95
+ display_progress=True,
96
+ )
97
+
98
+ assess_results(results_batch, None)
99
+
100
+ else:
101
+ raise Exception("Option not found")
102
+
103
+
104
+ if __name__ == "__main__":
105
+ main()
@@ -0,0 +1,180 @@
1
+ from pathlib import Path
2
+
3
+ import mesa
4
+ import numpy as np
5
+ from mesa.experimental.cell_space import OrthogonalVonNeumannGrid
6
+
7
+ from .resource_agents import Resource
8
+ from .trader_agents import Trader
9
+
10
+
11
+ # Helper Functions
12
+ def flatten(list_of_lists):
13
+ """
14
+ helper function for model datacollector for trade price
15
+ collapses agent price list into one list
16
+ """
17
+ return [item for sublist in list_of_lists for item in sublist]
18
+
19
+
20
+ def geometric_mean(list_of_prices):
21
+ """
22
+ find the geometric mean of a list of prices
23
+ """
24
+ return np.exp(np.log(list_of_prices).mean())
25
+
26
+
27
+ def get_trade(agent):
28
+ """
29
+ For agent reporters in data collector
30
+
31
+ return list of trade partners and None for other agents
32
+ """
33
+ if isinstance(agent, Trader):
34
+ return agent.trade_partners
35
+ else:
36
+ return None
37
+
38
+
39
+ class SugarscapeG1mt(mesa.Model):
40
+ """
41
+ Manager class to run Sugarscape with Traders
42
+ """
43
+
44
+ def __init__(
45
+ self,
46
+ width=50,
47
+ height=50,
48
+ initial_population=200,
49
+ endowment_min=25,
50
+ endowment_max=50,
51
+ metabolism_min=1,
52
+ metabolism_max=5,
53
+ vision_min=1,
54
+ vision_max=5,
55
+ enable_trade=True,
56
+ ):
57
+ super().__init__()
58
+ # Initiate width and height of sugarscape
59
+ self.width = width
60
+ self.height = height
61
+ # Initiate population attributes
62
+ self.initial_population = initial_population
63
+ self.endowment_min = endowment_min
64
+ self.endowment_max = endowment_max
65
+ self.metabolism_min = metabolism_min
66
+ self.metabolism_max = metabolism_max
67
+ self.vision_min = vision_min
68
+ self.vision_max = vision_max
69
+ self.enable_trade = enable_trade
70
+ self.running = True
71
+
72
+ # initiate mesa grid class
73
+ self.grid = OrthogonalVonNeumannGrid((self.width, self.height), torus=False)
74
+ # initiate datacollector
75
+ self.datacollector = mesa.DataCollector(
76
+ model_reporters={
77
+ "Trader": lambda m: len(m.agents_by_type[Trader]),
78
+ "Trade Volume": lambda m: sum(
79
+ len(a.trade_partners) for a in m.agents_by_type[Trader]
80
+ ),
81
+ "Price": lambda m: geometric_mean(
82
+ flatten([a.prices for a in m.agents_by_type[Trader]])
83
+ ),
84
+ },
85
+ agent_reporters={"Trade Network": lambda a: get_trade(a)},
86
+ )
87
+
88
+ # read in landscape file from supplmentary material
89
+ sugar_distribution = np.genfromtxt(Path(__file__).parent / "sugar-map.txt")
90
+ spice_distribution = np.flip(sugar_distribution, 1)
91
+
92
+ for cell in self.grid.all_cells:
93
+ max_sugar = sugar_distribution[cell.coordinate]
94
+ max_spice = spice_distribution[cell.coordinate]
95
+ Resource(self, max_sugar, max_spice, cell)
96
+
97
+ for _ in range(self.initial_population):
98
+ # get agent position
99
+ x = self.random.randrange(self.width)
100
+ y = self.random.randrange(self.height)
101
+ # see Growing Artificial Societies p. 108 for initialization
102
+ # give agents initial endowment
103
+ sugar = int(self.random.uniform(self.endowment_min, self.endowment_max + 1))
104
+ spice = int(self.random.uniform(self.endowment_min, self.endowment_max + 1))
105
+ # give agents initial metabolism
106
+ metabolism_sugar = int(
107
+ self.random.uniform(self.metabolism_min, self.metabolism_max + 1)
108
+ )
109
+ metabolism_spice = int(
110
+ self.random.uniform(self.metabolism_min, self.metabolism_max + 1)
111
+ )
112
+ # give agents vision
113
+ vision = int(self.random.uniform(self.vision_min, self.vision_max + 1))
114
+
115
+ cell = self.grid[(x, y)]
116
+ # create Trader object
117
+ Trader(
118
+ self,
119
+ cell,
120
+ sugar=sugar,
121
+ spice=spice,
122
+ metabolism_sugar=metabolism_sugar,
123
+ metabolism_spice=metabolism_spice,
124
+ vision=vision,
125
+ )
126
+
127
+ def step(self):
128
+ """
129
+ Unique step function that does staged activation of sugar and spice
130
+ and then randomly activates traders
131
+ """
132
+ # step Resource agents
133
+ self.agents_by_type[Resource].do("step")
134
+
135
+ # step trader agents
136
+ # to account for agent death and removal we need a separate data structure to
137
+ # iterate
138
+ trader_shuffle = self.agents_by_type[Trader].shuffle()
139
+
140
+ for agent in trader_shuffle:
141
+ agent.prices = []
142
+ agent.trade_partners = []
143
+ agent.move()
144
+ agent.eat()
145
+ agent.maybe_die()
146
+
147
+ if not self.enable_trade:
148
+ # If trade is not enabled, return early
149
+ self.datacollector.collect(self)
150
+ return
151
+
152
+ trader_shuffle = self.agents_by_type[Trader].shuffle()
153
+
154
+ for agent in trader_shuffle:
155
+ agent.trade_with_neighbors()
156
+
157
+ # collect model level data
158
+ self.datacollector.collect(self)
159
+ """
160
+ Mesa is working on updating datacollector agent reporter
161
+ so it can collect information on specific agents from
162
+ mesa.time.RandomActivationByType.
163
+
164
+ Please see issue #1419 at
165
+ https://github.com/projectmesa/mesa/issues/1419
166
+ (contributions welcome)
167
+
168
+ Below is one way to update agent_records to get specific Trader agent data
169
+ """
170
+ # Need to remove excess data
171
+ # Create local variable to store trade data
172
+ agent_trades = self.datacollector._agent_records[self.steps]
173
+ # Get rid of all None to reduce data storage needs
174
+ agent_trades = [agent for agent in agent_trades if agent[2] is not None]
175
+ # Reassign the dictionary value with lean trade data
176
+ self.datacollector._agent_records[self.steps] = agent_trades
177
+
178
+ def run_model(self, step_count=1000):
179
+ for i in range(step_count):
180
+ self.step()
@@ -0,0 +1,26 @@
1
+ from mesa.experimental.cell_space import FixedAgent
2
+
3
+
4
+ class Resource(FixedAgent):
5
+ """
6
+ Resource:
7
+ - contains an amount of sugar and spice
8
+ - grows 1 amount of sugar at each turn
9
+ - grows 1 amount of spice at each turn
10
+ """
11
+
12
+ def __init__(self, model, max_sugar, max_spice, cell):
13
+ super().__init__(model)
14
+ self.sugar_amount = max_sugar
15
+ self.max_sugar = max_sugar
16
+ self.spice_amount = max_spice
17
+ self.max_spice = max_spice
18
+ self.cell = cell
19
+
20
+ def step(self):
21
+ """
22
+ Growth function, adds one unit of sugar and spice each step up to
23
+ max amount
24
+ """
25
+ self.sugar_amount = min([self.max_sugar, self.sugar_amount + 1])
26
+ self.spice_amount = min([self.max_spice, self.spice_amount + 1])
@@ -0,0 +1,61 @@
1
+ import mesa
2
+
3
+ from .model import SugarscapeG1mt
4
+ from .resource_agents import Resource
5
+ from .trader_agents import Trader
6
+
7
+ sugar_dic = {4: "#005C00", 3: "#008300", 2: "#00AA00", 1: "#00F800"}
8
+ spice_dic = {4: "#acac00", 3: "#c5c500", 2: "#dfdf00", 1: "#f8f800"}
9
+
10
+
11
+ def Agent_portrayal(agent):
12
+ if agent is None:
13
+ return
14
+
15
+ if isinstance(agent, Trader):
16
+ return {
17
+ "Shape": "circle",
18
+ "Filled": "true",
19
+ "r": 0.5,
20
+ "Layer": 0,
21
+ "Color": "#FF0A01",
22
+ }
23
+
24
+ elif isinstance(agent, Resource):
25
+ resource_type = "sugar" if agent.max_sugar > agent.max_spice else "spice"
26
+ if resource_type == "sugar":
27
+ color = (
28
+ sugar_dic[agent.sugar_amount] if agent.sugar_amount != 0 else "#D6F5D6"
29
+ )
30
+ layer = 1 if agent.sugar_amount > 2 else 0
31
+ else:
32
+ color = (
33
+ spice_dic[agent.spice_amount] if agent.spice_amount != 0 else "#D6F5D6"
34
+ )
35
+ layer = 1 if agent.spice_amount > 2 else 0
36
+ return {
37
+ "Color": color,
38
+ "Shape": "rect",
39
+ "Filled": "true",
40
+ "Layer": layer,
41
+ "w": 1,
42
+ "h": 1,
43
+ }
44
+
45
+ return {}
46
+
47
+
48
+ canvas_element = mesa.visualization.CanvasGrid(Agent_portrayal, 50, 50, 500, 500)
49
+ chart_element = mesa.visualization.ChartModule(
50
+ [{"Label": "Trader", "Color": "#AA0000"}]
51
+ )
52
+ chart_element2 = mesa.visualization.ChartModule(
53
+ [{"Label": "Price", "Color": "#000000"}]
54
+ )
55
+
56
+ server = mesa.visualization.ModularServer(
57
+ SugarscapeG1mt,
58
+ [canvas_element, chart_element, chart_element2],
59
+ "Sugarscape with Traders",
60
+ )
61
+ # server.launch()
@@ -0,0 +1,50 @@
1
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 2 2 2 2 2 2 2 2
2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2
3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2
4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2
5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2
6
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 3 3 3 3 3 3 3 2 2
7
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 3 3 3 3 3 3 2
8
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 2
9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3
10
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3
11
+ 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3
12
+ 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3
13
+ 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3
14
+ 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3
15
+ 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 2
16
+ 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 3 3 3 3 3 3 2
17
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 4 4 4 4 3 3 3 3 3 3 3 2 2
18
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2
19
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2
20
+ 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2
21
+ 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2
22
+ 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2
23
+ 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1
24
+ 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1
25
+ 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1
26
+ 1 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1
27
+ 1 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1
28
+ 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1
29
+ 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1
30
+ 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1
31
+ 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 0 0 0
32
+ 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
33
+ 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
34
+ 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0
35
+ 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0
36
+ 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0
37
+ 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 2 2 2 2 2 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
38
+ 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 2 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0
39
+ 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0
40
+ 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 3 3 3 3 3 3 2 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
41
+ 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 3 3 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
42
+ 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
43
+ 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
44
+ 1 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
45
+ 1 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
46
+ 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
47
+ 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
48
+ 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
49
+ 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
50
+ 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0