Mesa 2.4.0__py3-none-any.whl → 3.0.0__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 (110) hide show
  1. mesa/__init__.py +3 -5
  2. mesa/agent.py +105 -92
  3. mesa/batchrunner.py +55 -31
  4. mesa/datacollection.py +10 -14
  5. mesa/examples/README.md +37 -0
  6. mesa/examples/__init__.py +21 -0
  7. mesa/examples/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb +116 -0
  8. mesa/examples/advanced/epstein_civil_violence/Readme.md +34 -0
  9. mesa/examples/advanced/epstein_civil_violence/__init__.py +0 -0
  10. mesa/examples/advanced/epstein_civil_violence/agents.py +164 -0
  11. mesa/examples/advanced/epstein_civil_violence/app.py +73 -0
  12. mesa/examples/advanced/epstein_civil_violence/model.py +114 -0
  13. mesa/examples/advanced/pd_grid/Readme.md +43 -0
  14. mesa/examples/advanced/pd_grid/__init__.py +0 -0
  15. mesa/examples/advanced/pd_grid/agents.py +50 -0
  16. mesa/examples/advanced/pd_grid/analysis.ipynb +228 -0
  17. mesa/examples/advanced/pd_grid/app.py +54 -0
  18. mesa/examples/advanced/pd_grid/model.py +71 -0
  19. mesa/examples/advanced/sugarscape_g1mt/Readme.md +64 -0
  20. mesa/examples/advanced/sugarscape_g1mt/__init__.py +0 -0
  21. mesa/examples/advanced/sugarscape_g1mt/agents.py +344 -0
  22. mesa/examples/advanced/sugarscape_g1mt/app.py +62 -0
  23. mesa/examples/advanced/sugarscape_g1mt/model.py +180 -0
  24. mesa/examples/advanced/sugarscape_g1mt/sugar-map.txt +50 -0
  25. mesa/examples/advanced/sugarscape_g1mt/tests.py +69 -0
  26. mesa/examples/advanced/wolf_sheep/Readme.md +57 -0
  27. mesa/examples/advanced/wolf_sheep/__init__.py +0 -0
  28. mesa/examples/advanced/wolf_sheep/agents.py +102 -0
  29. mesa/examples/advanced/wolf_sheep/app.py +84 -0
  30. mesa/examples/advanced/wolf_sheep/model.py +137 -0
  31. mesa/examples/basic/__init__.py +0 -0
  32. mesa/examples/basic/boid_flockers/Readme.md +22 -0
  33. mesa/examples/basic/boid_flockers/__init__.py +0 -0
  34. mesa/examples/basic/boid_flockers/agents.py +71 -0
  35. mesa/examples/basic/boid_flockers/app.py +58 -0
  36. mesa/examples/basic/boid_flockers/model.py +69 -0
  37. mesa/examples/basic/boltzmann_wealth_model/Readme.md +56 -0
  38. mesa/examples/basic/boltzmann_wealth_model/__init__.py +0 -0
  39. mesa/examples/basic/boltzmann_wealth_model/agents.py +31 -0
  40. mesa/examples/basic/boltzmann_wealth_model/app.py +74 -0
  41. mesa/examples/basic/boltzmann_wealth_model/model.py +43 -0
  42. mesa/examples/basic/boltzmann_wealth_model/st_app.py +115 -0
  43. mesa/examples/basic/conways_game_of_life/Readme.md +39 -0
  44. mesa/examples/basic/conways_game_of_life/__init__.py +0 -0
  45. mesa/examples/basic/conways_game_of_life/agents.py +47 -0
  46. mesa/examples/basic/conways_game_of_life/app.py +51 -0
  47. mesa/examples/basic/conways_game_of_life/model.py +31 -0
  48. mesa/examples/basic/conways_game_of_life/st_app.py +72 -0
  49. mesa/examples/basic/schelling/Readme.md +40 -0
  50. mesa/examples/basic/schelling/__init__.py +0 -0
  51. mesa/examples/basic/schelling/agents.py +26 -0
  52. mesa/examples/basic/schelling/analysis.ipynb +205 -0
  53. mesa/examples/basic/schelling/app.py +42 -0
  54. mesa/examples/basic/schelling/model.py +59 -0
  55. mesa/examples/basic/virus_on_network/Readme.md +61 -0
  56. mesa/examples/basic/virus_on_network/__init__.py +0 -0
  57. mesa/examples/basic/virus_on_network/agents.py +69 -0
  58. mesa/examples/basic/virus_on_network/app.py +114 -0
  59. mesa/examples/basic/virus_on_network/model.py +96 -0
  60. mesa/experimental/UserParam.py +18 -7
  61. mesa/experimental/__init__.py +10 -2
  62. mesa/experimental/cell_space/__init__.py +16 -1
  63. mesa/experimental/cell_space/cell.py +93 -23
  64. mesa/experimental/cell_space/cell_agent.py +117 -21
  65. mesa/experimental/cell_space/cell_collection.py +56 -19
  66. mesa/experimental/cell_space/discrete_space.py +92 -8
  67. mesa/experimental/cell_space/grid.py +33 -9
  68. mesa/experimental/cell_space/network.py +15 -10
  69. mesa/experimental/cell_space/voronoi.py +257 -0
  70. mesa/experimental/components/altair.py +11 -2
  71. mesa/experimental/components/matplotlib.py +132 -26
  72. mesa/experimental/devs/__init__.py +2 -0
  73. mesa/experimental/devs/eventlist.py +54 -15
  74. mesa/experimental/devs/examples/epstein_civil_violence.py +69 -38
  75. mesa/experimental/devs/examples/wolf_sheep.py +42 -43
  76. mesa/experimental/devs/simulator.py +57 -16
  77. mesa/experimental/{jupyter_viz.py → solara_viz.py} +151 -99
  78. mesa/model.py +136 -78
  79. mesa/space.py +208 -148
  80. mesa/time.py +63 -80
  81. mesa/visualization/__init__.py +25 -6
  82. mesa/visualization/components/__init__.py +83 -0
  83. mesa/visualization/components/altair_components.py +188 -0
  84. mesa/visualization/components/matplotlib_components.py +175 -0
  85. mesa/visualization/mpl_space_drawing.py +593 -0
  86. mesa/visualization/solara_viz.py +458 -0
  87. mesa/visualization/user_param.py +69 -0
  88. mesa/visualization/utils.py +9 -0
  89. {mesa-2.4.0.dist-info → mesa-3.0.0.dist-info}/METADATA +62 -17
  90. mesa-3.0.0.dist-info/RECORD +95 -0
  91. mesa-3.0.0.dist-info/licenses/LICENSE +202 -0
  92. mesa-2.4.0.dist-info/licenses/LICENSE → mesa-3.0.0.dist-info/licenses/NOTICE +2 -2
  93. mesa/cookiecutter-mesa/cookiecutter.json +0 -8
  94. mesa/cookiecutter-mesa/hooks/post_gen_project.py +0 -11
  95. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/README.md +0 -4
  96. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/run.pytemplate +0 -3
  97. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/setup.pytemplate +0 -11
  98. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/model.pytemplate +0 -60
  99. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/server.pytemplate +0 -36
  100. mesa/flat/__init__.py +0 -6
  101. mesa/flat/visualization.py +0 -5
  102. mesa/main.py +0 -63
  103. mesa/visualization/ModularVisualization.py +0 -1
  104. mesa/visualization/TextVisualization.py +0 -1
  105. mesa/visualization/UserParam.py +0 -1
  106. mesa/visualization/modules.py +0 -1
  107. mesa-2.4.0.dist-info/RECORD +0 -45
  108. /mesa/{cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}} → examples/advanced}/__init__.py +0 -0
  109. {mesa-2.4.0.dist-info → mesa-3.0.0.dist-info}/WHEEL +0 -0
  110. {mesa-2.4.0.dist-info → mesa-3.0.0.dist-info}/entry_points.txt +0 -0
@@ -1,36 +1,40 @@
1
- """
2
- Wolf-Sheep Predation Model
3
- ================================
4
-
5
- Replication of the model found in NetLogo:
6
- Wilensky, U. (1997). NetLogo Wolf Sheep Predation model.
7
- http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation.
8
- Center for Connected Learning and Computer-Based Modeling,
9
- Northwestern University, Evanston, IL.
10
- """
1
+ """Example of using ABM simulator for Wolf-Sheep Predation Model."""
11
2
 
12
3
  import mesa
4
+ from mesa.experimental.cell_space import FixedAgent
13
5
  from mesa.experimental.devs.simulator import ABMSimulator
14
6
 
15
7
 
16
8
  class Animal(mesa.Agent):
17
- def __init__(self, unique_id, model, moore, energy, p_reproduce, energy_from_food):
18
- super().__init__(unique_id, model)
9
+ """Base Animal class."""
10
+
11
+ def __init__(self, model, moore, energy, p_reproduce, energy_from_food):
12
+ """Initialize Animal instance.
13
+
14
+ Args:
15
+ model: a model instance
16
+ moore: using moore grid or not
17
+ energy: initial energy
18
+ p_reproduce: probability of reproduction
19
+ energy_from_food: energy gained from 1 unit of food
20
+ """
21
+ super().__init__(model)
19
22
  self.energy = energy
20
23
  self.p_reproduce = p_reproduce
21
24
  self.energy_from_food = energy_from_food
22
25
  self.moore = moore
23
26
 
24
27
  def random_move(self):
28
+ """Move to random neighboring cell."""
25
29
  next_moves = self.model.grid.get_neighborhood(self.pos, self.moore, True)
26
30
  next_move = self.random.choice(next_moves)
27
31
  # Now move:
28
32
  self.model.grid.move_agent(self, next_move)
29
33
 
30
34
  def spawn_offspring(self):
35
+ """Create offspring."""
31
36
  self.energy /= 2
32
37
  offspring = self.__class__(
33
- self.model.next_id(),
34
38
  self.model,
35
39
  self.moore,
36
40
  self.energy,
@@ -39,13 +43,15 @@ class Animal(mesa.Agent):
39
43
  )
40
44
  self.model.grid.place_agent(offspring, self.pos)
41
45
 
42
- def feed(self): ...
46
+ def feed(self): ... # noqa: D102
43
47
 
44
48
  def die(self):
49
+ """Die."""
45
50
  self.model.grid.remove_agent(self)
46
51
  self.remove()
47
52
 
48
53
  def step(self):
54
+ """Execute one step of the agent."""
49
55
  self.random_move()
50
56
  self.energy -= 1
51
57
 
@@ -58,13 +64,10 @@ class Animal(mesa.Agent):
58
64
 
59
65
 
60
66
  class Sheep(Animal):
61
- """
62
- A sheep that walks around, reproduces (asexually) and gets eaten.
63
-
64
- The init is the same as the RandomWalker.
65
- """
67
+ """A sheep that walks around, reproduces (asexually) and gets eaten."""
66
68
 
67
69
  def feed(self):
70
+ """Eat grass and gain energy."""
68
71
  # If there is grass available, eat it
69
72
  agents = self.model.grid.get_cell_list_contents(self.pos)
70
73
  grass_patch = next(obj for obj in agents if isinstance(obj, GrassPatch))
@@ -74,11 +77,10 @@ class Sheep(Animal):
74
77
 
75
78
 
76
79
  class Wolf(Animal):
77
- """
78
- A wolf that walks around, reproduces (asexually) and eats sheep.
79
- """
80
+ """A wolf that walks around, reproduces (asexually) and eats sheep."""
80
81
 
81
82
  def feed(self):
83
+ """Eat wolf and gain energy."""
82
84
  agents = self.model.grid.get_cell_list_contents(self.pos)
83
85
  sheep = [obj for obj in agents if isinstance(obj, Sheep)]
84
86
  if len(sheep) > 0:
@@ -89,13 +91,11 @@ class Wolf(Animal):
89
91
  sheep_to_eat.die()
90
92
 
91
93
 
92
- class GrassPatch(mesa.Agent):
93
- """
94
- A patch of grass that grows at a fixed rate and it is eaten by sheep
95
- """
94
+ class GrassPatch(FixedAgent):
95
+ """A patch of grass that grows at a fixed rate and it is eaten by sheep."""
96
96
 
97
97
  @property
98
- def fully_grown(self) -> bool:
98
+ def fully_grown(self) -> bool: # noqa: D102
99
99
  return self._fully_grown
100
100
 
101
101
  @fully_grown.setter
@@ -109,15 +109,16 @@ class GrassPatch(mesa.Agent):
109
109
  function_args=[self, "fully_grown", True],
110
110
  )
111
111
 
112
- def __init__(self, unique_id, model, fully_grown, countdown, grass_regrowth_time):
113
- """
114
- Creates a new patch of grass
112
+ def __init__(self, model, fully_grown, countdown, grass_regrowth_time):
113
+ """Creates a new patch of grass.
115
114
 
116
115
  Args:
117
- grown: (boolean) Whether the patch of grass is fully grown or not
116
+ model: a model instance
117
+ fully_grown: (boolean) Whether the patch of grass is fully grown or not
118
118
  countdown: Time for the patch of grass to be fully grown again
119
+ grass_regrowth_time: regrowth time for the grass
119
120
  """
120
- super().__init__(unique_id, model)
121
+ super().__init__(model)
121
122
  self._fully_grown = fully_grown
122
123
  self.grass_regrowth_time = grass_regrowth_time
123
124
 
@@ -126,13 +127,12 @@ class GrassPatch(mesa.Agent):
126
127
  setattr, countdown, function_args=[self, "fully_grown", True]
127
128
  )
128
129
 
129
- def set_fully_grown(self):
130
+ def set_fully_grown(self): # noqa
130
131
  self.fully_grown = True
131
132
 
132
133
 
133
134
  class WolfSheep(mesa.Model):
134
- """
135
- Wolf-Sheep Predation Model
135
+ """Wolf-Sheep Predation Model.
136
136
 
137
137
  A model for simulating wolf and sheep (predator-prey) ecosystem modelling.
138
138
  """
@@ -152,10 +152,11 @@ class WolfSheep(mesa.Model):
152
152
  simulator=None,
153
153
  seed=None,
154
154
  ):
155
- """
156
- Create a new Wolf-Sheep model with the given parameters.
155
+ """Create a new Wolf-Sheep model with the given parameters.
157
156
 
158
157
  Args:
158
+ height: height of the grid
159
+ width: width of the grid
159
160
  initial_sheep: Number of sheep to start with
160
161
  initial_wolves: Number of wolves to start with
161
162
  sheep_reproduce: Probability of each sheep reproducing each step
@@ -165,7 +166,9 @@ class WolfSheep(mesa.Model):
165
166
  grass_regrowth_time: How long it takes for a grass patch to regrow
166
167
  once it is eaten
167
168
  sheep_gain_from_food: Energy sheep gain from grass, if enabled.
168
- moore:
169
+ moore: whether to use moore or von Neumann grid
170
+ simulator: Simulator to use for simulating wolf and sheep
171
+ seed: Random seed
169
172
  """
170
173
  super().__init__(seed=seed)
171
174
  # Set parameters
@@ -191,7 +194,6 @@ class WolfSheep(mesa.Model):
191
194
  )
192
195
  energy = self.random.randrange(2 * sheep_gain_from_food)
193
196
  sheep = Sheep(
194
- self.next_id(),
195
197
  self,
196
198
  moore,
197
199
  energy,
@@ -208,7 +210,6 @@ class WolfSheep(mesa.Model):
208
210
  )
209
211
  energy = self.random.randrange(2 * wolf_gain_from_food)
210
212
  wolf = Wolf(
211
- self.next_id(),
212
213
  self,
213
214
  moore,
214
215
  energy,
@@ -225,9 +226,7 @@ class WolfSheep(mesa.Model):
225
226
  countdown = grass_regrowth_time
226
227
  else:
227
228
  countdown = self.random.randrange(grass_regrowth_time)
228
- patch = GrassPatch(
229
- self.next_id(), self, fully_grown, countdown, grass_regrowth_time
230
- )
229
+ patch = GrassPatch(self, fully_grown, countdown, grass_regrowth_time)
231
230
  self.grid.place_agent(patch, pos)
232
231
 
233
232
  def step(self):
@@ -1,7 +1,15 @@
1
+ """Provides several simulator classes.
2
+
3
+ A Simulator is responsible for executing a simulation model. It controls time advancement and enables event scheduling.
4
+
5
+
6
+ """
7
+
1
8
  from __future__ import annotations
2
9
 
3
10
  import numbers
4
- from typing import Any, Callable
11
+ from collections.abc import Callable
12
+ from typing import Any
5
13
 
6
14
  from mesa import Model
7
15
 
@@ -26,6 +34,12 @@ class Simulator:
26
34
  # TODO: add experimentation support
27
35
 
28
36
  def __init__(self, time_unit: type, start_time: int | float):
37
+ """Initialize a Simulator instance.
38
+
39
+ Args:
40
+ time_unit: type of the smulaiton time
41
+ start_time: the starttime of the simulator
42
+ """
29
43
  # should model run in a separate thread,
30
44
  # and we can then interact with start, stop, run_until, and step?
31
45
  self.event_list = EventList()
@@ -35,10 +49,10 @@ class Simulator:
35
49
  self.time = self.start_time
36
50
  self.model = None
37
51
 
38
- def check_time_unit(self, time: int | float) -> bool: ...
52
+ def check_time_unit(self, time: int | float) -> bool: ... # noqa: D102
39
53
 
40
54
  def setup(self, model: Model) -> None:
41
- """Set up the simulator with the model to simulate
55
+ """Set up the simulator with the model to simulate.
42
56
 
43
57
  Args:
44
58
  model (Model): The model to simulate
@@ -48,12 +62,13 @@ class Simulator:
48
62
  self.model = model
49
63
 
50
64
  def reset(self):
51
- """Reset the simulator by clearing the event list and removing the model to simulate"""
65
+ """Reset the simulator by clearing the event list and removing the model to simulate."""
52
66
  self.event_list.clear()
53
67
  self.model = None
54
68
  self.time = self.start_time
55
69
 
56
70
  def run_until(self, end_time: int | float) -> None:
71
+ """Run the simulator until the end time."""
57
72
  while True:
58
73
  try:
59
74
  event = self.event_list.pop_event()
@@ -70,7 +85,7 @@ class Simulator:
70
85
  break
71
86
 
72
87
  def run_for(self, time_delta: int | float):
73
- """run the simulator for the specified time delta
88
+ """Run the simulator for the specified time delta.
74
89
 
75
90
  Args:
76
91
  time_delta (float| int): The time delta. The simulator is run from the current time to the current time
@@ -87,7 +102,7 @@ class Simulator:
87
102
  function_args: list[Any] | None = None,
88
103
  function_kwargs: dict[str, Any] | None = None,
89
104
  ) -> SimulationEvent:
90
- """Schedule event for the current time instant
105
+ """Schedule event for the current time instant.
91
106
 
92
107
  Args:
93
108
  function (Callable): The callable to execute for this event
@@ -115,7 +130,7 @@ class Simulator:
115
130
  function_args: list[Any] | None = None,
116
131
  function_kwargs: dict[str, Any] | None = None,
117
132
  ) -> SimulationEvent:
118
- """Schedule event for the specified time instant
133
+ """Schedule event for the specified time instant.
119
134
 
120
135
  Args:
121
136
  function (Callable): The callable to execute for this event
@@ -149,7 +164,7 @@ class Simulator:
149
164
  function_args: list[Any] | None = None,
150
165
  function_kwargs: dict[str, Any] | None = None,
151
166
  ) -> SimulationEvent:
152
- """Schedule event for the current time plus the time delta
167
+ """Schedule event for the current time plus the time delta.
153
168
 
154
169
  Args:
155
170
  function (Callable): The callable to execute for this event
@@ -173,13 +188,12 @@ class Simulator:
173
188
  return event
174
189
 
175
190
  def cancel_event(self, event: SimulationEvent) -> None:
176
- """remove the event from the event list
191
+ """Remove the event from the event list.
177
192
 
178
193
  Args:
179
194
  event (SimulationEvent): The simulation event to remove
180
195
 
181
196
  """
182
-
183
197
  self.event_list.remove(event)
184
198
 
185
199
  def _schedule_event(self, event: SimulationEvent):
@@ -203,13 +217,29 @@ class ABMSimulator(Simulator):
203
217
  """
204
218
 
205
219
  def __init__(self):
220
+ """Initialize a ABM simulator."""
206
221
  super().__init__(int, 0)
207
222
 
208
223
  def setup(self, model):
224
+ """Set up the simulator with the model to simulate.
225
+
226
+ Args:
227
+ model (Model): The model to simulate
228
+
229
+ """
209
230
  super().setup(model)
210
231
  self.schedule_event_now(self.model.step, priority=Priority.HIGH)
211
232
 
212
233
  def check_time_unit(self, time) -> bool:
234
+ """Check whether the time is of the correct unit.
235
+
236
+ Args:
237
+ time (int | float): the time
238
+
239
+ Returns:
240
+ bool: whether the time is of the correct unit
241
+
242
+ """
213
243
  if isinstance(time, int):
214
244
  return True
215
245
  if isinstance(time, float):
@@ -224,9 +254,9 @@ class ABMSimulator(Simulator):
224
254
  function_args: list[Any] | None = None,
225
255
  function_kwargs: dict[str, Any] | None = None,
226
256
  ) -> SimulationEvent:
227
- """Schedule a SimulationEvent for the next tick
257
+ """Schedule a SimulationEvent for the next tick.
228
258
 
229
- Args
259
+ Args:
230
260
  function (Callable): the callable to execute
231
261
  priority (Priority): the priority of the event
232
262
  function_args (List[Any]): List of arguments to pass to the callable
@@ -242,7 +272,7 @@ class ABMSimulator(Simulator):
242
272
  )
243
273
 
244
274
  def run_until(self, end_time: int) -> None:
245
- """run the simulator up to and included the specified end time
275
+ """Run the simulator up to and included the specified end time.
246
276
 
247
277
  Args:
248
278
  end_time (float| int): The end_time delta. The simulator is until the specified end time
@@ -269,7 +299,7 @@ class ABMSimulator(Simulator):
269
299
  break
270
300
 
271
301
  def run_for(self, time_delta: int):
272
- """run the simulator for the specified time delta
302
+ """Run the simulator for the specified time delta.
273
303
 
274
304
  Args:
275
305
  time_delta (float| int): The time delta. The simulator is run from the current time to the current time
@@ -281,13 +311,24 @@ class ABMSimulator(Simulator):
281
311
 
282
312
 
283
313
  class DEVSimulator(Simulator):
284
- """A simulator where the unit of time is a float. Can be used for full-blown discrete event simulating using
285
- event scheduling.
314
+ """A simulator where the unit of time is a float.
315
+
316
+ Can be used for full-blown discrete event simulating using event scheduling.
286
317
 
287
318
  """
288
319
 
289
320
  def __init__(self):
321
+ """Initialize a DEVS simulator."""
290
322
  super().__init__(float, 0.0)
291
323
 
292
324
  def check_time_unit(self, time) -> bool:
325
+ """Check whether the time is of the correct unit.
326
+
327
+ Args:
328
+ time (float): the time
329
+
330
+ Returns:
331
+ bool: whether the time is of the correct unit
332
+
333
+ """
293
334
  return isinstance(time, numbers.Number)