Mesa 3.0.0b1__py3-none-any.whl → 3.0.0b2__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 (102) hide show
  1. mesa/__init__.py +1 -3
  2. mesa/agent.py +23 -8
  3. mesa/examples/__init__.py +21 -0
  4. {examples → mesa/examples}/advanced/epstein_civil_violence/Readme.md +3 -2
  5. mesa/examples/advanced/epstein_civil_violence/app.py +72 -0
  6. {examples/advanced/epstein_civil_violence → mesa/examples/advanced}/epstein_civil_violence/model.py +4 -4
  7. examples/advanced/pd_grid/readme.md → mesa/examples/advanced/pd_grid/Readme.md +4 -3
  8. mesa/examples/advanced/pd_grid/app.py +50 -0
  9. {examples/advanced/pd_grid → mesa/examples/advanced}/pd_grid/model.py +1 -2
  10. {examples → mesa/examples}/advanced/sugarscape_g1mt/Readme.md +6 -29
  11. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/trader_agents.py → mesa/examples/advanced/sugarscape_g1mt/agents.py +26 -3
  12. {examples → mesa/examples}/advanced/sugarscape_g1mt/app.py +23 -14
  13. {examples/advanced/sugarscape_g1mt → mesa/examples/advanced}/sugarscape_g1mt/model.py +6 -6
  14. {examples → mesa/examples}/advanced/sugarscape_g1mt/tests.py +3 -6
  15. mesa/examples/advanced/wolf_sheep/app.py +77 -0
  16. {examples/advanced/wolf_sheep → mesa/examples/advanced}/wolf_sheep/model.py +9 -8
  17. mesa/examples/basic/boid_flockers/Readme.md +22 -0
  18. {examples → mesa/examples}/basic/boid_flockers/app.py +1 -2
  19. {examples → mesa/examples}/basic/boid_flockers/model.py +1 -2
  20. {examples → mesa/examples}/basic/boltzmann_wealth_model/Readme.md +1 -5
  21. mesa/examples/basic/boltzmann_wealth_model/__init__.py +0 -0
  22. {examples → mesa/examples}/basic/boltzmann_wealth_model/app.py +1 -2
  23. {examples → mesa/examples}/basic/boltzmann_wealth_model/model.py +3 -4
  24. {examples → mesa/examples}/basic/conways_game_of_life/Readme.md +11 -7
  25. mesa/examples/basic/conways_game_of_life/__init__.py +0 -0
  26. {examples → mesa/examples}/basic/conways_game_of_life/agents.py +8 -8
  27. mesa/examples/basic/conways_game_of_life/app.py +39 -0
  28. {examples → mesa/examples}/basic/conways_game_of_life/model.py +3 -4
  29. {examples → mesa/examples}/basic/conways_game_of_life/st_app.py +2 -1
  30. examples/basic/schelling/README.md → mesa/examples/basic/schelling/Readme.md +2 -9
  31. mesa/examples/basic/schelling/__init__.py +0 -0
  32. {examples → mesa/examples}/basic/schelling/app.py +1 -2
  33. {examples → mesa/examples}/basic/schelling/model.py +1 -2
  34. mesa/examples/basic/virus_on_network/__init__.py +0 -0
  35. {examples → mesa/examples}/basic/virus_on_network/app.py +5 -2
  36. {examples → mesa/examples}/basic/virus_on_network/model.py +4 -7
  37. mesa/experimental/cell_space/discrete_space.py +6 -0
  38. mesa/experimental/devs/eventlist.py +6 -0
  39. mesa/model.py +13 -0
  40. mesa/space.py +70 -5
  41. mesa/visualization/components/altair.py +87 -19
  42. mesa/visualization/components/matplotlib.py +55 -11
  43. {mesa-3.0.0b1.dist-info → mesa-3.0.0b2.dist-info}/METADATA +1 -3
  44. mesa-3.0.0b2.dist-info/RECORD +93 -0
  45. examples/advanced/epstein_civil_violence/epstein_civil_violence/portrayal.py +0 -33
  46. examples/advanced/epstein_civil_violence/epstein_civil_violence/server.py +0 -81
  47. examples/advanced/epstein_civil_violence/requirements.txt +0 -3
  48. examples/advanced/epstein_civil_violence/run.py +0 -3
  49. examples/advanced/pd_grid/pd_grid/portrayal.py +0 -19
  50. examples/advanced/pd_grid/pd_grid/server.py +0 -21
  51. examples/advanced/pd_grid/requirements.txt +0 -3
  52. examples/advanced/pd_grid/run.py +0 -3
  53. examples/advanced/sugarscape_g1mt/requirements.txt +0 -6
  54. examples/advanced/sugarscape_g1mt/run.py +0 -105
  55. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/resource_agents.py +0 -26
  56. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/server.py +0 -61
  57. examples/advanced/wolf_sheep/requirements.txt +0 -1
  58. examples/advanced/wolf_sheep/run.py +0 -3
  59. examples/advanced/wolf_sheep/wolf_sheep/resources/sheep.png +0 -0
  60. examples/advanced/wolf_sheep/wolf_sheep/resources/wolf.png +0 -0
  61. examples/advanced/wolf_sheep/wolf_sheep/server.py +0 -78
  62. examples/basic/__init__.py +0 -13
  63. examples/basic/boid_flockers/Readme.md +0 -43
  64. examples/basic/conways_game_of_life/portrayal.py +0 -18
  65. examples/basic/conways_game_of_life/requirements.txt +0 -1
  66. examples/basic/conways_game_of_life/server.py +0 -11
  67. mesa/cookiecutter-mesa/cookiecutter.json +0 -8
  68. mesa/cookiecutter-mesa/hooks/post_gen_project.py +0 -13
  69. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/README.md +0 -4
  70. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/app.pytemplate +0 -27
  71. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/setup.pytemplate +0 -11
  72. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/__init__.py +0 -1
  73. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/model.pytemplate +0 -60
  74. mesa/examples.py +0 -3
  75. mesa/main.py +0 -65
  76. mesa-3.0.0b1.dist-info/RECORD +0 -114
  77. {examples → mesa/examples}/README.md +0 -0
  78. {examples → mesa/examples/advanced}/__init__.py +0 -0
  79. {examples → mesa/examples}/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb +0 -0
  80. {examples/advanced → mesa/examples/advanced/epstein_civil_violence}/__init__.py +0 -0
  81. /examples/advanced/epstein_civil_violence/epstein_civil_violence/agent.py → /mesa/examples/advanced/epstein_civil_violence/agents.py +0 -0
  82. {examples/advanced/epstein_civil_violence/epstein_civil_violence → mesa/examples/advanced/pd_grid}/__init__.py +0 -0
  83. /examples/advanced/pd_grid/pd_grid/agent.py → /mesa/examples/advanced/pd_grid/agents.py +0 -0
  84. {examples → mesa/examples}/advanced/pd_grid/analysis.ipynb +0 -0
  85. {examples/advanced/pd_grid/pd_grid → mesa/examples/advanced/sugarscape_g1mt}/__init__.py +0 -0
  86. {examples/advanced/sugarscape_g1mt → mesa/examples/advanced}/sugarscape_g1mt/sugar-map.txt +0 -0
  87. {examples → mesa/examples}/advanced/wolf_sheep/Readme.md +0 -0
  88. {examples/advanced/sugarscape_g1mt/sugarscape_g1mt → mesa/examples/advanced/wolf_sheep}/__init__.py +0 -0
  89. {examples/advanced/wolf_sheep → mesa/examples/advanced}/wolf_sheep/agents.py +0 -0
  90. {examples/advanced/wolf_sheep → mesa/examples/basic}/__init__.py +0 -0
  91. {examples/advanced/wolf_sheep/wolf_sheep → mesa/examples/basic/boid_flockers}/__init__.py +0 -0
  92. {examples → mesa/examples}/basic/boid_flockers/agents.py +0 -0
  93. {examples → mesa/examples}/basic/boltzmann_wealth_model/agents.py +0 -0
  94. {examples → mesa/examples}/basic/boltzmann_wealth_model/st_app.py +0 -0
  95. {examples → mesa/examples}/basic/schelling/agents.py +0 -0
  96. {examples → mesa/examples}/basic/schelling/analysis.ipynb +0 -0
  97. /examples/basic/virus_on_network/README.md → /mesa/examples/basic/virus_on_network/Readme.md +0 -0
  98. {examples → mesa/examples}/basic/virus_on_network/agents.py +0 -0
  99. {mesa-3.0.0b1.dist-info → mesa-3.0.0b2.dist-info}/WHEEL +0 -0
  100. {mesa-3.0.0b1.dist-info → mesa-3.0.0b2.dist-info}/entry_points.txt +0 -0
  101. {mesa-3.0.0b1.dist-info → mesa-3.0.0b2.dist-info}/licenses/LICENSE +0 -0
  102. {mesa-3.0.0b1.dist-info → mesa-3.0.0b2.dist-info}/licenses/NOTICE +0 -0
mesa/__init__.py CHANGED
@@ -5,7 +5,6 @@ Core Objects: Model, and Agent.
5
5
 
6
6
  import datetime
7
7
 
8
- import mesa.examples as examples
9
8
  import mesa.experimental as experimental
10
9
  import mesa.space as space
11
10
  import mesa.time as time
@@ -22,11 +21,10 @@ __all__ = [
22
21
  "DataCollector",
23
22
  "batch_run",
24
23
  "experimental",
25
- "examples",
26
24
  ]
27
25
 
28
26
  __title__ = "mesa"
29
- __version__ = "3.0.0b1"
27
+ __version__ = "3.0.0b2"
30
28
  __license__ = "Apache 2.0"
31
29
  _this_year = datetime.datetime.now(tz=datetime.timezone.utc).date().year
32
30
  __copyright__ = f"Copyright {_this_year} Project Mesa Team"
mesa/agent.py CHANGED
@@ -21,6 +21,8 @@ from random import Random
21
21
  # mypy
22
22
  from typing import TYPE_CHECKING, Any, Literal, overload
23
23
 
24
+ import numpy as np
25
+
24
26
  if TYPE_CHECKING:
25
27
  # We ensure that these are not imported during runtime to prevent cyclic
26
28
  # dependency.
@@ -67,7 +69,13 @@ class Agent:
67
69
  self.model.register_agent(self)
68
70
 
69
71
  def remove(self) -> None:
70
- """Remove and delete the agent from the model."""
72
+ """Remove and delete the agent from the model.
73
+
74
+ Notes:
75
+ If you need to do additional cleanup when removing an agent by for example removing
76
+ it from a space, consider extending this method in your own agent class.
77
+
78
+ """
71
79
  with contextlib.suppress(KeyError):
72
80
  self.model.deregister_agent(self)
73
81
 
@@ -79,9 +87,14 @@ class Agent:
79
87
 
80
88
  @property
81
89
  def random(self) -> Random:
82
- """Return a seeded rng."""
90
+ """Return a seeded stdlib rng."""
83
91
  return self.model.random
84
92
 
93
+ @property
94
+ def rng(self) -> np.random.Generator:
95
+ """Return a seeded np.random rng."""
96
+ return self.model.rng
97
+
85
98
 
86
99
  class AgentSet(MutableSet, Sequence):
87
100
  """A collection class that represents an ordered set of agents within an agent-based model (ABM).
@@ -288,15 +301,17 @@ class AgentSet(MutableSet, Sequence):
288
301
 
289
302
  It's a fast, optimized version of calling shuffle() followed by do().
290
303
  """
291
- agents = list(self._agents.keys())
292
- self.random.shuffle(agents)
304
+ weakrefs = list(self._agents.keyrefs())
305
+ self.random.shuffle(weakrefs)
293
306
 
294
307
  if isinstance(method, str):
295
- for agent in agents:
296
- getattr(agent, method)(*args, **kwargs)
308
+ for ref in weakrefs:
309
+ if (agent := ref()) is not None:
310
+ getattr(agent, method)(*args, **kwargs)
297
311
  else:
298
- for agent in agents:
299
- method(agent, *args, **kwargs)
312
+ for ref in weakrefs:
313
+ if (agent := ref()) is not None:
314
+ method(agent, *args, **kwargs)
300
315
 
301
316
  return self
302
317
 
@@ -0,0 +1,21 @@
1
+ from mesa.examples.advanced.epstein_civil_violence.model import EpsteinCivilViolence
2
+ from mesa.examples.advanced.pd_grid.model import PdGrid
3
+ from mesa.examples.advanced.sugarscape_g1mt.model import SugarscapeG1mt
4
+ from mesa.examples.advanced.wolf_sheep.model import WolfSheep
5
+ from mesa.examples.basic.boid_flockers.model import BoidFlockers
6
+ from mesa.examples.basic.boltzmann_wealth_model.model import BoltzmannWealthModel
7
+ from mesa.examples.basic.conways_game_of_life.model import ConwaysGameOfLife
8
+ from mesa.examples.basic.schelling.model import Schelling
9
+ from mesa.examples.basic.virus_on_network.model import VirusOnNetwork
10
+
11
+ __all__ = [
12
+ "BoidFlockers",
13
+ "BoltzmannWealthModel",
14
+ "ConwaysGameOfLife",
15
+ "Schelling",
16
+ "VirusOnNetwork",
17
+ "EpsteinCivilViolence",
18
+ "PdGrid",
19
+ "SugarscapeG1mt",
20
+ "WolfSheep",
21
+ ]
@@ -18,8 +18,9 @@ Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and p
18
18
 
19
19
  ## Files
20
20
 
21
- * ``EpsteinCivilViolence.py``: Core model and agent code.
22
- * ``EpsteinCivilViolenceServer.py``: Sets up the interactive visualization.
21
+ * ``model.py``: Core model code.
22
+ * ``agent.py``: Agent classes.
23
+ * ``app.py``: Sets up the interactive visualization.
23
24
  * ``Epstein Civil Violence.ipynb``: Jupyter notebook conducting some preliminary analysis of the model.
24
25
 
25
26
  ## Further Reading
@@ -0,0 +1,72 @@
1
+ from mesa.examples.advanced.epstein_civil_violence.agents import Citizen, Cop
2
+ from mesa.examples.advanced.epstein_civil_violence.model import EpsteinCivilViolence
3
+ from mesa.visualization import (
4
+ Slider,
5
+ SolaraViz,
6
+ make_plot_measure,
7
+ make_space_matplotlib,
8
+ )
9
+
10
+ COP_COLOR = "#000000"
11
+ AGENT_QUIET_COLOR = "#648FFF"
12
+ AGENT_REBEL_COLOR = "#FE6100"
13
+ JAIL_COLOR = "#808080"
14
+ JAIL_SHAPE = "rect"
15
+
16
+
17
+ def citizen_cop_portrayal(agent):
18
+ if agent is None:
19
+ return
20
+
21
+ portrayal = {
22
+ "size": 25,
23
+ "shape": "s", # square marker
24
+ }
25
+
26
+ if isinstance(agent, Citizen):
27
+ color = (
28
+ AGENT_QUIET_COLOR if agent.condition == "Quiescent" else AGENT_REBEL_COLOR
29
+ )
30
+ color = JAIL_COLOR if agent.jail_sentence else color
31
+ shape = JAIL_SHAPE if agent.jail_sentence else "circle"
32
+ portrayal["color"] = color
33
+ portrayal["shape"] = shape
34
+ if shape == "s":
35
+ portrayal["w"] = 0.9
36
+ portrayal["h"] = 0.9
37
+ else:
38
+ portrayal["r"] = 0.5
39
+ portrayal["filled"] = False
40
+ portrayal["layer"] = 0
41
+
42
+ elif isinstance(agent, Cop):
43
+ portrayal["color"] = COP_COLOR
44
+ portrayal["r"] = 0.9
45
+ portrayal["layer"] = 1
46
+
47
+ return portrayal
48
+
49
+
50
+ model_params = {
51
+ "height": 40,
52
+ "width": 40,
53
+ "citizen_density": Slider("Initial Agent Density", 0.7, 0.0, 0.9, 0.1),
54
+ "cop_density": Slider("Initial Cop Density", 0.04, 0.0, 0.1, 0.01),
55
+ "citizen_vision": Slider("Citizen Vision", 7, 1, 10, 1),
56
+ "cop_vision": Slider("Cop Vision", 7, 1, 10, 1),
57
+ "legitimacy": Slider("Government Legitimacy", 0.82, 0.0, 1, 0.01),
58
+ "max_jail_term": Slider("Max Jail Term", 30, 0, 50, 1),
59
+ }
60
+
61
+ space_component = make_space_matplotlib(citizen_cop_portrayal)
62
+ chart_component = make_plot_measure(["Quiescent", "Active", "Jailed"])
63
+
64
+ epstein_model = EpsteinCivilViolence()
65
+
66
+ page = SolaraViz(
67
+ epstein_model,
68
+ components=[space_component, chart_component],
69
+ model_params=model_params,
70
+ name="Epstein Civil Violence",
71
+ )
72
+ page # noqa
@@ -1,6 +1,5 @@
1
1
  import mesa
2
-
3
- from .agent import Citizen, Cop
2
+ from mesa.examples.advanced.epstein_civil_violence.agents import Citizen, Cop
4
3
 
5
4
 
6
5
  class EpsteinCivilViolence(mesa.Model):
@@ -43,8 +42,9 @@ class EpsteinCivilViolence(mesa.Model):
43
42
  arrest_prob_constant=2.3,
44
43
  movement=True,
45
44
  max_iters=1000,
45
+ seed=None,
46
46
  ):
47
- super().__init__()
47
+ super().__init__(seed=seed)
48
48
  self.width = width
49
49
  self.height = height
50
50
  self.citizen_density = citizen_density
@@ -60,7 +60,7 @@ class EpsteinCivilViolence(mesa.Model):
60
60
  self.iteration = 0
61
61
 
62
62
  self.grid = mesa.experimental.cell_space.OrthogonalMooreGrid(
63
- (width, height), capacity=1, torus=True
63
+ (width, height), capacity=1, torus=True, random=self.random
64
64
  )
65
65
 
66
66
  model_reporters = {
@@ -19,7 +19,7 @@ The Demographic Prisoner's Dilemma demonstrates how simple rules can lead to the
19
19
 
20
20
  ##### Web based model simulation
21
21
 
22
- To run the model interactively, run ``mesa runserver`` in this directory.
22
+ To run the model interactively, run ``solara run app.py`` in this directory.
23
23
 
24
24
  ##### Jupyter Notebook
25
25
 
@@ -27,8 +27,9 @@ Launch the ``Demographic Prisoner's Dilemma Activation Schedule.ipynb`` notebook
27
27
 
28
28
  ## Files
29
29
 
30
- * ``run.py`` is the entry point for the font-end simulations.
31
- * ``pd_grid/``: contains the model and agent classes; the model takes a ``activation_order`` string as an argument, which determines in which order agents are activated: Sequential, Random or Simultaneous.
30
+ * ``agents.py``: contains the agent class.
31
+ * ``model.py``: contains the model class; the model takes a ``activation_order`` string as an argument, which determines in which order agents are activated: Sequential, Random or Simultaneous.
32
+ * ``app.py``: contains the interactive visualization server.
32
33
  * ``Demographic Prisoner's Dilemma Activation Schedule.ipynb``: Jupyter Notebook for running the scheduling experiment. This runs the model three times, one for each activation type, and demonstrates how the activation regime drives the model to different outcomes.
33
34
 
34
35
  ## Further Reading
@@ -0,0 +1,50 @@
1
+ """
2
+ Solara-based visualization for the Spatial Prisoner's Dilemma Model.
3
+ """
4
+
5
+ from mesa.examples.advanced.pd_grid.model import PdGrid
6
+ from mesa.visualization import SolaraViz, make_plot_measure, make_space_matplotlib
7
+ from mesa.visualization.UserParam import Slider
8
+
9
+
10
+ def pd_agent_portrayal(agent):
11
+ """
12
+ Portrayal function for rendering PD agents in the visualization.
13
+ """
14
+ return {
15
+ "color": "blue" if agent.move == "C" else "red",
16
+ "shape": "s", # square marker
17
+ "size": 25,
18
+ }
19
+
20
+
21
+ # Model parameters
22
+ model_params = {
23
+ "width": Slider("Grid Width", value=50, min=10, max=100, step=1),
24
+ "height": Slider("Grid Height", value=50, min=10, max=100, step=1),
25
+ "activation_order": {
26
+ "type": "Select",
27
+ "value": "Random",
28
+ "values": PdGrid.activation_regimes,
29
+ "label": "Activation Regime",
30
+ },
31
+ }
32
+
33
+
34
+ # Create grid visualization component using Altair
35
+ grid_viz = make_space_matplotlib(agent_portrayal=pd_agent_portrayal)
36
+
37
+ # Create plot for tracking cooperating agents over time
38
+ plot_component = make_plot_measure("Cooperating_Agents")
39
+
40
+ # Initialize model
41
+ initial_model = PdGrid()
42
+
43
+ # Create visualization with all components
44
+ page = SolaraViz(
45
+ model=initial_model,
46
+ components=[grid_viz, plot_component],
47
+ model_params=model_params,
48
+ name="Spatial Prisoner's Dilemma",
49
+ )
50
+ page # noqa B018
@@ -1,8 +1,7 @@
1
1
  import mesa
2
+ from mesa.examples.advanced.pd_grid.agents import PDAgent
2
3
  from mesa.experimental.cell_space import OrthogonalMooreGrid
3
4
 
4
- from .agent import PDAgent
5
-
6
5
 
7
6
  class PdGrid(mesa.Model):
8
7
  """Model class for iterated, spatial prisoner's dilemma model."""
@@ -34,51 +34,28 @@ cross over one another otherwise *end*.
34
34
  (Epstein and Axtell, 1996, p. 105)
35
35
 
36
36
  The model demonstrates several Mesa concepts and features:
37
- - MultiGrid
37
+ - OrthogonalMooreGrid
38
38
  - Multiple agent types (traders, sugar, spice)
39
39
  - Dynamically removing agents from the grid and schedule when they die
40
40
  - Data Collection at the model and agent level
41
- - Batchrunner (i.e. parameter sweeps)
41
+ - custom solara matplotlib space visualization
42
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
43
 
51
44
  ## 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
45
  To run the model interactively:
66
46
 
67
47
  ```
68
- $ mesa runserver
48
+ $ solara run app.py
69
49
  ```
70
50
 
71
51
  Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and press Reset, then Run.
72
52
 
73
53
  ## Files
74
54
 
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.
55
+ * `model.py`: The Sugarscape Constant Growback with Traders model.
56
+ * `agents.py`: Defines the Trader agent class and the Resource agent class which contains an amount of sugar and spice.
81
57
  * `app.py`: Runs a visualization server via Solara (`solara run app.py`).
58
+ * `sugar_map.txt`: Provides sugar and spice landscape in raster type format.
82
59
  * `tests.py`: Has tests to ensure that the model reproduces the results in shown in Growing Artificial Societies.
83
60
 
84
61
  ## Additional Resources
@@ -1,8 +1,6 @@
1
1
  import math
2
2
 
3
- from mesa.experimental.cell_space import CellAgent
4
-
5
- from .resource_agents import Resource
3
+ from mesa.experimental.cell_space import CellAgent, FixedAgent
6
4
 
7
5
 
8
6
  # Helper function
@@ -20,6 +18,31 @@ def get_distance(cell_1, cell_2):
20
18
  return math.sqrt(dx**2 + dy**2)
21
19
 
22
20
 
21
+ class Resource(FixedAgent):
22
+ """
23
+ Resource:
24
+ - contains an amount of sugar and spice
25
+ - grows 1 amount of sugar at each turn
26
+ - grows 1 amount of spice at each turn
27
+ """
28
+
29
+ def __init__(self, model, max_sugar, max_spice, cell):
30
+ super().__init__(model)
31
+ self.sugar_amount = max_sugar
32
+ self.max_sugar = max_sugar
33
+ self.spice_amount = max_spice
34
+ self.max_spice = max_spice
35
+ self.cell = cell
36
+
37
+ def step(self):
38
+ """
39
+ Growth function, adds one unit of sugar and spice each step up to
40
+ max amount
41
+ """
42
+ self.sugar_amount = min([self.max_sugar, self.sugar_amount + 1])
43
+ self.spice_amount = min([self.max_spice, self.spice_amount + 1])
44
+
45
+
23
46
  class Trader(CellAgent):
24
47
  """
25
48
  Trader:
@@ -1,10 +1,19 @@
1
+ import os.path
2
+ import sys
3
+
4
+ sys.path.insert(
5
+ 0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../../"))
6
+ )
7
+
8
+
1
9
  import numpy as np
2
10
  import solara
3
11
  from matplotlib.figure import Figure
4
- from mesa.visualization import SolaraViz, make_plot_measure
5
12
  from sugarscape_g1mt.model import SugarscapeG1mt
6
13
  from sugarscape_g1mt.trader_agents import Trader
7
14
 
15
+ from mesa.visualization import SolaraViz, make_plot_measure
16
+
8
17
 
9
18
  def SpaceDrawer(model):
10
19
  def portray(g):
@@ -14,19 +23,19 @@ def SpaceDrawer(model):
14
23
  "trader": {"x": [], "y": [], "c": "tab:red", "marker": "o", "s": 10},
15
24
  }
16
25
 
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
- )
26
+ for agent in g.all_cells.agents:
27
+ i, j = agent.cell.coordinate
28
+ if isinstance(agent, Trader):
29
+ layers["trader"]["x"].append(i)
30
+ layers["trader"]["y"].append(j)
31
+ else:
32
+ # Don't visualize resource with value <= 1.
33
+ layers["sugar"][i][j] = (
34
+ agent.sugar_amount if agent.sugar_amount > 1 else np.nan
35
+ )
36
+ layers["spice"][i][j] = (
37
+ agent.spice_amount if agent.spice_amount > 1 else np.nan
38
+ )
30
39
  return layers
31
40
 
32
41
  fig = Figure()
@@ -1,11 +1,10 @@
1
1
  from pathlib import Path
2
2
 
3
- import mesa
4
3
  import numpy as np
5
- from mesa.experimental.cell_space import OrthogonalVonNeumannGrid
6
4
 
7
- from .resource_agents import Resource
8
- from .trader_agents import Trader
5
+ import mesa
6
+ from mesa.examples.advanced.sugarscape_g1mt.agents import Resource, Trader
7
+ from mesa.experimental.cell_space import OrthogonalVonNeumannGrid
9
8
 
10
9
 
11
10
  # Helper Functions
@@ -53,8 +52,9 @@ class SugarscapeG1mt(mesa.Model):
53
52
  vision_min=1,
54
53
  vision_max=5,
55
54
  enable_trade=True,
55
+ seed=None,
56
56
  ):
57
- super().__init__()
57
+ super().__init__(seed=seed)
58
58
  # Initiate width and height of sugarscape
59
59
  self.width = width
60
60
  self.height = height
@@ -176,5 +176,5 @@ class SugarscapeG1mt(mesa.Model):
176
176
  self.datacollector._agent_records[self.steps] = agent_trades
177
177
 
178
178
  def run_model(self, step_count=1000):
179
- for i in range(step_count):
179
+ for _ in range(step_count):
180
180
  self.step()
@@ -1,11 +1,8 @@
1
- import random
2
-
3
1
  import numpy as np
4
2
  from scipy import stats
5
- from sugarscape_g1mt.model import SugarscapeG1mt, flatten
6
- from sugarscape_g1mt.trader_agents import Trader
7
3
 
8
- random.seed(1)
4
+ from .agents import Trader
5
+ from .model import SugarscapeG1mt, flatten
9
6
 
10
7
 
11
8
  def check_slope(y, increasing):
@@ -19,7 +16,7 @@ def check_slope(y, increasing):
19
16
  def test_decreasing_price_variance():
20
17
  # The variance of the average trade price should decrease over time (figure IV-3)
21
18
  # See Growing Artificial Societies p. 109.
22
- model = SugarscapeG1mt()
19
+ model = SugarscapeG1mt(42)
23
20
  model.datacollector._new_model_reporter(
24
21
  "price_variance",
25
22
  lambda m: np.var(
@@ -0,0 +1,77 @@
1
+ from mesa.examples.advanced.wolf_sheep.agents import GrassPatch, Sheep, Wolf
2
+ from mesa.examples.advanced.wolf_sheep.model import WolfSheep
3
+ from mesa.visualization import (
4
+ Slider,
5
+ SolaraViz,
6
+ make_plot_measure,
7
+ make_space_matplotlib,
8
+ )
9
+
10
+ WOLF_COLOR = "#000000"
11
+ SHEEP_COLOR = "#648FFF"
12
+
13
+
14
+ def wolf_sheep_portrayal(agent):
15
+ if agent is None:
16
+ return
17
+
18
+ portrayal = {
19
+ "size": 25,
20
+ "shape": "s", # square marker
21
+ }
22
+
23
+ if isinstance(agent, Wolf):
24
+ portrayal["color"] = WOLF_COLOR
25
+ portrayal["Layer"] = 3
26
+ elif isinstance(agent, Sheep):
27
+ portrayal["color"] = SHEEP_COLOR
28
+ portrayal["Layer"] = 2
29
+ elif isinstance(agent, GrassPatch):
30
+ if agent.fully_grown:
31
+ portrayal["color"] = "#00FF00"
32
+ else:
33
+ portrayal["color"] = "#84e184"
34
+ # portrayal["shape"] = "rect"
35
+ # portrayal["Filled"] = "true"
36
+ portrayal["Layer"] = 1
37
+
38
+ return portrayal
39
+
40
+
41
+ model_params = {
42
+ # The following line is an example to showcase StaticText.
43
+ "grass": {
44
+ "type": "Select",
45
+ "value": True,
46
+ "values": [True, False],
47
+ "label": "grass regrowth enabled?",
48
+ },
49
+ "grass_regrowth_time": Slider("Grass Regrowth Time", 20, 1, 50),
50
+ "initial_sheep": Slider("Initial Sheep Population", 100, 10, 300),
51
+ "sheep_reproduce": Slider("Sheep Reproduction Rate", 0.04, 0.01, 1.0, 0.01),
52
+ "initial_wolves": Slider("Initial Wolf Population", 10, 5, 100),
53
+ "wolf_reproduce": Slider(
54
+ "Wolf Reproduction Rate",
55
+ 0.05,
56
+ 0.01,
57
+ 1.0,
58
+ 0.01,
59
+ ),
60
+ "wolf_gain_from_food": Slider("Wolf Gain From Food Rate", 20, 1, 50),
61
+ "sheep_gain_from_food": Slider("Sheep Gain From Food", 4, 1, 10),
62
+ }
63
+
64
+
65
+ space_component = make_space_matplotlib(wolf_sheep_portrayal)
66
+ lineplot_component = make_plot_measure(["Wolves", "Sheep", "Grass"])
67
+
68
+ model = WolfSheep()
69
+
70
+
71
+ page = SolaraViz(
72
+ model,
73
+ components=[space_component, lineplot_component],
74
+ model_params=model_params,
75
+ name="Wolf Sheep",
76
+ )
77
+ page # noqa
@@ -10,10 +10,9 @@ Replication of the model found in NetLogo:
10
10
  """
11
11
 
12
12
  import mesa
13
+ from mesa.examples.advanced.wolf_sheep.agents import GrassPatch, Sheep, Wolf
13
14
  from mesa.experimental.cell_space import OrthogonalMooreGrid
14
15
 
15
- from .agents import GrassPatch, Sheep, Wolf
16
-
17
16
 
18
17
  class WolfSheep(mesa.Model):
19
18
  """
@@ -67,7 +66,7 @@ class WolfSheep(mesa.Model):
67
66
  once it is eaten
68
67
  sheep_gain_from_food: Energy sheep gain from grass, if enabled.
69
68
  """
70
- super().__init__(seed=None)
69
+ super().__init__(seed=seed)
71
70
  # Set parameters
72
71
  self.width = width
73
72
  self.height = height
@@ -81,15 +80,17 @@ class WolfSheep(mesa.Model):
81
80
  collectors = {
82
81
  "Wolves": lambda m: len(m.agents_by_type[Wolf]),
83
82
  "Sheep": lambda m: len(m.agents_by_type[Sheep]),
83
+ "Grass": lambda m: len(
84
+ m.agents_by_type[GrassPatch].select(lambda a: a.fully_grown)
85
+ )
86
+ if m.grass
87
+ else -1,
84
88
  }
85
89
 
86
- if grass:
87
- collectors["Grass"] = lambda m: len(m.agents_by_type[GrassPatch])
88
-
89
90
  self.datacollector = mesa.DataCollector(collectors)
90
91
 
91
92
  # Create sheep:
92
- for i in range(self.initial_sheep):
93
+ for _ in range(self.initial_sheep):
93
94
  x = self.random.randrange(self.width)
94
95
  y = self.random.randrange(self.height)
95
96
  energy = self.random.randrange(2 * self.sheep_gain_from_food)
@@ -132,5 +133,5 @@ class WolfSheep(mesa.Model):
132
133
  self.datacollector.collect(self)
133
134
 
134
135
  def run_model(self, step_count=200):
135
- for i in range(step_count):
136
+ for _ in range(step_count):
136
137
  self.step()
@@ -0,0 +1,22 @@
1
+ # Boids Flockers
2
+
3
+ ## Summary
4
+
5
+ An implementation of Craig Reynolds's Boids flocker model. Agents (simulated birds) try to fly towards the average position of their neighbors and in the same direction as them, while maintaining a minimum distance. This produces flocking behavior.
6
+
7
+ This model tests Mesa's continuous space feature, and uses numpy arrays to represent vectors.
8
+
9
+ ## How to Run
10
+
11
+ * To launch the visualization interactively, run ``solara run app.py`` in this directory.It will automatically open a browser page.
12
+
13
+ ## Files
14
+
15
+ * [model.py](model.py): Ccntains the Boid Model
16
+ * [agents.py](agents.py): Contains the Boid agent
17
+ * [app.py](app.py): Solara based Visualization code.
18
+
19
+ ## Further Reading
20
+
21
+ The following link can be visited for more information on the boid flockers model:
22
+ https://cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/modeling-natural-systems/boids.html
@@ -1,7 +1,6 @@
1
+ from mesa.examples.basic.boid_flockers.model import BoidFlockers
1
2
  from mesa.visualization import Slider, SolaraViz, make_space_matplotlib
2
3
 
3
- from .model import BoidFlockers
4
-
5
4
 
6
5
  def boid_draw(agent):
7
6
  if not agent.neighbors: # Only for the first Frame