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.
- mesa/__init__.py +3 -5
- mesa/agent.py +105 -92
- mesa/batchrunner.py +55 -31
- mesa/datacollection.py +10 -14
- mesa/examples/README.md +37 -0
- mesa/examples/__init__.py +21 -0
- mesa/examples/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb +116 -0
- mesa/examples/advanced/epstein_civil_violence/Readme.md +34 -0
- mesa/examples/advanced/epstein_civil_violence/__init__.py +0 -0
- mesa/examples/advanced/epstein_civil_violence/agents.py +164 -0
- mesa/examples/advanced/epstein_civil_violence/app.py +73 -0
- mesa/examples/advanced/epstein_civil_violence/model.py +114 -0
- mesa/examples/advanced/pd_grid/Readme.md +43 -0
- mesa/examples/advanced/pd_grid/__init__.py +0 -0
- mesa/examples/advanced/pd_grid/agents.py +50 -0
- mesa/examples/advanced/pd_grid/analysis.ipynb +228 -0
- mesa/examples/advanced/pd_grid/app.py +54 -0
- mesa/examples/advanced/pd_grid/model.py +71 -0
- mesa/examples/advanced/sugarscape_g1mt/Readme.md +64 -0
- mesa/examples/advanced/sugarscape_g1mt/__init__.py +0 -0
- mesa/examples/advanced/sugarscape_g1mt/agents.py +344 -0
- mesa/examples/advanced/sugarscape_g1mt/app.py +62 -0
- mesa/examples/advanced/sugarscape_g1mt/model.py +180 -0
- mesa/examples/advanced/sugarscape_g1mt/sugar-map.txt +50 -0
- mesa/examples/advanced/sugarscape_g1mt/tests.py +69 -0
- mesa/examples/advanced/wolf_sheep/Readme.md +57 -0
- mesa/examples/advanced/wolf_sheep/__init__.py +0 -0
- mesa/examples/advanced/wolf_sheep/agents.py +102 -0
- mesa/examples/advanced/wolf_sheep/app.py +84 -0
- mesa/examples/advanced/wolf_sheep/model.py +137 -0
- mesa/examples/basic/__init__.py +0 -0
- mesa/examples/basic/boid_flockers/Readme.md +22 -0
- mesa/examples/basic/boid_flockers/__init__.py +0 -0
- mesa/examples/basic/boid_flockers/agents.py +71 -0
- mesa/examples/basic/boid_flockers/app.py +58 -0
- mesa/examples/basic/boid_flockers/model.py +69 -0
- mesa/examples/basic/boltzmann_wealth_model/Readme.md +56 -0
- mesa/examples/basic/boltzmann_wealth_model/__init__.py +0 -0
- mesa/examples/basic/boltzmann_wealth_model/agents.py +31 -0
- mesa/examples/basic/boltzmann_wealth_model/app.py +74 -0
- mesa/examples/basic/boltzmann_wealth_model/model.py +43 -0
- mesa/examples/basic/boltzmann_wealth_model/st_app.py +115 -0
- mesa/examples/basic/conways_game_of_life/Readme.md +39 -0
- mesa/examples/basic/conways_game_of_life/__init__.py +0 -0
- mesa/examples/basic/conways_game_of_life/agents.py +47 -0
- mesa/examples/basic/conways_game_of_life/app.py +51 -0
- mesa/examples/basic/conways_game_of_life/model.py +31 -0
- mesa/examples/basic/conways_game_of_life/st_app.py +72 -0
- mesa/examples/basic/schelling/Readme.md +40 -0
- mesa/examples/basic/schelling/__init__.py +0 -0
- mesa/examples/basic/schelling/agents.py +26 -0
- mesa/examples/basic/schelling/analysis.ipynb +205 -0
- mesa/examples/basic/schelling/app.py +42 -0
- mesa/examples/basic/schelling/model.py +59 -0
- mesa/examples/basic/virus_on_network/Readme.md +61 -0
- mesa/examples/basic/virus_on_network/__init__.py +0 -0
- mesa/examples/basic/virus_on_network/agents.py +69 -0
- mesa/examples/basic/virus_on_network/app.py +114 -0
- mesa/examples/basic/virus_on_network/model.py +96 -0
- mesa/experimental/UserParam.py +18 -7
- mesa/experimental/__init__.py +10 -2
- mesa/experimental/cell_space/__init__.py +16 -1
- mesa/experimental/cell_space/cell.py +93 -23
- mesa/experimental/cell_space/cell_agent.py +117 -21
- mesa/experimental/cell_space/cell_collection.py +56 -19
- mesa/experimental/cell_space/discrete_space.py +92 -8
- mesa/experimental/cell_space/grid.py +33 -9
- mesa/experimental/cell_space/network.py +15 -10
- mesa/experimental/cell_space/voronoi.py +257 -0
- mesa/experimental/components/altair.py +11 -2
- mesa/experimental/components/matplotlib.py +132 -26
- mesa/experimental/devs/__init__.py +2 -0
- mesa/experimental/devs/eventlist.py +54 -15
- mesa/experimental/devs/examples/epstein_civil_violence.py +69 -38
- mesa/experimental/devs/examples/wolf_sheep.py +42 -43
- mesa/experimental/devs/simulator.py +57 -16
- mesa/experimental/{jupyter_viz.py → solara_viz.py} +151 -99
- mesa/model.py +136 -78
- mesa/space.py +208 -148
- mesa/time.py +63 -80
- mesa/visualization/__init__.py +25 -6
- mesa/visualization/components/__init__.py +83 -0
- mesa/visualization/components/altair_components.py +188 -0
- mesa/visualization/components/matplotlib_components.py +175 -0
- mesa/visualization/mpl_space_drawing.py +593 -0
- mesa/visualization/solara_viz.py +458 -0
- mesa/visualization/user_param.py +69 -0
- mesa/visualization/utils.py +9 -0
- {mesa-2.4.0.dist-info → mesa-3.0.0.dist-info}/METADATA +62 -17
- mesa-3.0.0.dist-info/RECORD +95 -0
- mesa-3.0.0.dist-info/licenses/LICENSE +202 -0
- mesa-2.4.0.dist-info/licenses/LICENSE → mesa-3.0.0.dist-info/licenses/NOTICE +2 -2
- mesa/cookiecutter-mesa/cookiecutter.json +0 -8
- mesa/cookiecutter-mesa/hooks/post_gen_project.py +0 -11
- mesa/cookiecutter-mesa/{{cookiecutter.snake}}/README.md +0 -4
- mesa/cookiecutter-mesa/{{cookiecutter.snake}}/run.pytemplate +0 -3
- mesa/cookiecutter-mesa/{{cookiecutter.snake}}/setup.pytemplate +0 -11
- mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/model.pytemplate +0 -60
- mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/server.pytemplate +0 -36
- mesa/flat/__init__.py +0 -6
- mesa/flat/visualization.py +0 -5
- mesa/main.py +0 -63
- mesa/visualization/ModularVisualization.py +0 -1
- mesa/visualization/TextVisualization.py +0 -1
- mesa/visualization/UserParam.py +0 -1
- mesa/visualization/modules.py +0 -1
- mesa-2.4.0.dist-info/RECORD +0 -45
- /mesa/{cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}} → examples/advanced}/__init__.py +0 -0
- {mesa-2.4.0.dist-info → mesa-3.0.0.dist-info}/WHEEL +0 -0
- {mesa-2.4.0.dist-info → mesa-3.0.0.dist-info}/entry_points.txt +0 -0
mesa/model.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
The model class for Mesa framework.
|
|
1
|
+
"""The model class for Mesa framework.
|
|
3
2
|
|
|
4
3
|
Core Objects: Model
|
|
5
4
|
"""
|
|
@@ -9,15 +8,20 @@ Core Objects: Model
|
|
|
9
8
|
from __future__ import annotations
|
|
10
9
|
|
|
11
10
|
import random
|
|
11
|
+
import sys
|
|
12
12
|
import warnings
|
|
13
|
+
from collections.abc import Sequence
|
|
13
14
|
|
|
14
15
|
# mypy
|
|
15
|
-
from typing import Any
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
16
19
|
|
|
17
20
|
from mesa.agent import Agent, AgentSet
|
|
18
21
|
from mesa.datacollection import DataCollector
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
SeedLike = int | np.integer | Sequence[int] | np.random.SeedSequence
|
|
24
|
+
RNGLike = np.random.Generator | np.random.BitGenerator
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
class Model:
|
|
@@ -30,23 +34,9 @@ class Model:
|
|
|
30
34
|
Attributes:
|
|
31
35
|
running: A boolean indicating if the model should continue running.
|
|
32
36
|
schedule: An object to manage the order and execution of agent steps.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
agents: An AgentSet containing all agents in the model
|
|
37
|
-
agent_types: A list of different agent types present in the model.
|
|
38
|
-
agents_by_type: A dictionary where the keys are agent types and the values are the corresponding AgentSets.
|
|
39
|
-
|
|
40
|
-
Methods:
|
|
41
|
-
get_agents_of_type: Returns an AgentSet of agents of the specified type.
|
|
42
|
-
Deprecated: Use agents_by_type[agenttype] instead.
|
|
43
|
-
run_model: Runs the model's simulation until a defined end condition is reached.
|
|
44
|
-
step: Executes a single step of the model's simulation process.
|
|
45
|
-
next_id: Generates and returns the next unique identifier for an agent.
|
|
46
|
-
reset_randomizer: Resets the model's random number generator with a new or existing seed.
|
|
47
|
-
initialize_data_collector: Sets up the data collector for the model, requiring an initialized scheduler and agents.
|
|
48
|
-
register_agent : register an agent with the model
|
|
49
|
-
deregister_agent : remove an agent from the model
|
|
37
|
+
steps: the number of times `model.step()` has been called.
|
|
38
|
+
random: a seeded python.random number generator.
|
|
39
|
+
rng : a seeded numpy.random.Generator
|
|
50
40
|
|
|
51
41
|
Notes:
|
|
52
42
|
Model.agents returns the AgentSet containing all agents registered with the model. Changing
|
|
@@ -55,35 +45,80 @@ class Model:
|
|
|
55
45
|
|
|
56
46
|
"""
|
|
57
47
|
|
|
58
|
-
def
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
obj.random = random.Random(obj._seed)
|
|
67
|
-
|
|
68
|
-
# TODO: Remove these 2 lines just before Mesa 3.0
|
|
69
|
-
obj._steps = 0
|
|
70
|
-
obj._time = 0
|
|
71
|
-
return obj
|
|
72
|
-
|
|
73
|
-
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
74
|
-
"""Create a new model. Overload this method with the actual code to
|
|
75
|
-
start the model. Always start with super().__init__() to initialize the
|
|
76
|
-
model object properly.
|
|
77
|
-
"""
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
*args: Any,
|
|
51
|
+
seed: float | None = None,
|
|
52
|
+
rng: RNGLike | SeedLike | None = None,
|
|
53
|
+
**kwargs: Any,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Create a new model.
|
|
78
56
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
self.current_id = 0
|
|
57
|
+
Overload this method with the actual code to initialize the model. Always start with super().__init__()
|
|
58
|
+
to initialize the model object properly.
|
|
82
59
|
|
|
60
|
+
Args:
|
|
61
|
+
args: arguments to pass onto super
|
|
62
|
+
seed: the seed for the random number generator
|
|
63
|
+
rng : Pseudorandom number generator state. When `rng` is None, a new `numpy.random.Generator` is created
|
|
64
|
+
using entropy from the operating system. Types other than `numpy.random.Generator` are passed to
|
|
65
|
+
`numpy.random.default_rng` to instantiate a `Generator`.
|
|
66
|
+
kwargs: keyword arguments to pass onto super
|
|
67
|
+
|
|
68
|
+
Notes:
|
|
69
|
+
you have to pass either seed or rng, but not both.
|
|
70
|
+
|
|
71
|
+
"""
|
|
72
|
+
super().__init__(*args, **kwargs)
|
|
73
|
+
self.running = True
|
|
74
|
+
self.steps: int = 0
|
|
75
|
+
|
|
76
|
+
if (seed is not None) and (rng is not None):
|
|
77
|
+
raise ValueError("you have to pass either rng or seed, not both")
|
|
78
|
+
elif seed is None:
|
|
79
|
+
self.rng: np.random.Generator = np.random.default_rng(rng)
|
|
80
|
+
self._rng = (
|
|
81
|
+
self.rng.bit_generator.state
|
|
82
|
+
) # this allows for reproducing the rng
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
self.random = random.Random(rng)
|
|
86
|
+
except TypeError:
|
|
87
|
+
seed = int(self.rng.integers(np.iinfo(np.int32).max))
|
|
88
|
+
self.random = random.Random(seed)
|
|
89
|
+
self._seed = seed # this allows for reproducing stdlib.random
|
|
90
|
+
elif rng is None:
|
|
91
|
+
self.random = random.Random(seed)
|
|
92
|
+
self._seed = seed # this allows for reproducing stdlib.random
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
self.rng: np.random.Generator = np.random.default_rng(rng)
|
|
96
|
+
except TypeError:
|
|
97
|
+
rng = self.random.randint(0, sys.maxsize)
|
|
98
|
+
self.rng: np.random.Generator = np.random.default_rng(rng)
|
|
99
|
+
self._rng = self.rng.bit_generator.state
|
|
100
|
+
|
|
101
|
+
# Wrap the user-defined step method
|
|
102
|
+
self._user_step = self.step
|
|
103
|
+
self.step = self._wrapped_step
|
|
104
|
+
|
|
105
|
+
# setup agent registration data structures
|
|
83
106
|
self._setup_agent_registration()
|
|
84
107
|
|
|
85
|
-
|
|
86
|
-
|
|
108
|
+
def _wrapped_step(self, *args: Any, **kwargs: Any) -> None:
|
|
109
|
+
"""Automatically increments time and steps after calling the user's step method."""
|
|
110
|
+
# Automatically increment time and step counters
|
|
111
|
+
self.steps += 1
|
|
112
|
+
# Call the original user-defined step method
|
|
113
|
+
self._user_step(*args, **kwargs)
|
|
114
|
+
|
|
115
|
+
def next_id(self) -> int: # noqa: D102
|
|
116
|
+
warnings.warn(
|
|
117
|
+
"using model.next_id() is deprecated. Agents track their unique ID automatically",
|
|
118
|
+
DeprecationWarning,
|
|
119
|
+
stacklevel=2,
|
|
120
|
+
)
|
|
121
|
+
return 0
|
|
87
122
|
|
|
88
123
|
@property
|
|
89
124
|
def agents(self) -> AgentSet:
|
|
@@ -92,12 +127,10 @@ class Model:
|
|
|
92
127
|
|
|
93
128
|
@agents.setter
|
|
94
129
|
def agents(self, agents: Any) -> None:
|
|
95
|
-
|
|
130
|
+
raise AttributeError(
|
|
96
131
|
"You are trying to set model.agents. In Mesa 3.0 and higher, this attribute is "
|
|
97
132
|
"used by Mesa itself, so you cannot use it directly anymore."
|
|
98
|
-
"Please adjust your code to use a different attribute name for custom agent storage."
|
|
99
|
-
UserWarning,
|
|
100
|
-
stacklevel=2,
|
|
133
|
+
"Please adjust your code to use a different attribute name for custom agent storage."
|
|
101
134
|
)
|
|
102
135
|
|
|
103
136
|
@property
|
|
@@ -121,15 +154,17 @@ class Model:
|
|
|
121
154
|
return self.agents_by_type[agenttype]
|
|
122
155
|
|
|
123
156
|
def _setup_agent_registration(self):
|
|
124
|
-
"""
|
|
157
|
+
"""Helper method to initialize the agent registration datastructures."""
|
|
125
158
|
self._agents = {} # the hard references to all agents in the model
|
|
126
159
|
self._agents_by_type: dict[
|
|
127
160
|
type[Agent], AgentSet
|
|
128
161
|
] = {} # a dict with an agentset for each class of agents
|
|
129
|
-
self._all_agents = AgentSet(
|
|
162
|
+
self._all_agents = AgentSet(
|
|
163
|
+
[], random=self.random
|
|
164
|
+
) # an agenset with all agents
|
|
130
165
|
|
|
131
166
|
def register_agent(self, agent):
|
|
132
|
-
"""Register the agent with the model
|
|
167
|
+
"""Register the agent with the model.
|
|
133
168
|
|
|
134
169
|
Args:
|
|
135
170
|
agent: The agent to register.
|
|
@@ -160,16 +195,19 @@ class Model:
|
|
|
160
195
|
[
|
|
161
196
|
agent,
|
|
162
197
|
],
|
|
163
|
-
self,
|
|
198
|
+
random=self.random,
|
|
164
199
|
)
|
|
165
200
|
|
|
166
201
|
self._all_agents.add(agent)
|
|
167
202
|
|
|
168
203
|
def deregister_agent(self, agent):
|
|
169
|
-
"""Deregister the agent with the model
|
|
204
|
+
"""Deregister the agent with the model.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
agent: The agent to deregister.
|
|
170
208
|
|
|
171
|
-
Notes
|
|
172
|
-
|
|
209
|
+
Notes:
|
|
210
|
+
This method is called automatically by ``Agent.remove``
|
|
173
211
|
|
|
174
212
|
"""
|
|
175
213
|
del self._agents[agent]
|
|
@@ -177,8 +215,9 @@ class Model:
|
|
|
177
215
|
self._all_agents.remove(agent)
|
|
178
216
|
|
|
179
217
|
def run_model(self) -> None:
|
|
180
|
-
"""Run the model until the end condition is reached.
|
|
181
|
-
|
|
218
|
+
"""Run the model until the end condition is reached.
|
|
219
|
+
|
|
220
|
+
Overload as needed.
|
|
182
221
|
"""
|
|
183
222
|
while self.running:
|
|
184
223
|
self.step()
|
|
@@ -186,28 +225,26 @@ class Model:
|
|
|
186
225
|
def step(self) -> None:
|
|
187
226
|
"""A single step. Fill in here."""
|
|
188
227
|
|
|
189
|
-
def _advance_time(self, deltat: TimeT = 1):
|
|
190
|
-
"""Increment the model's steps counter and clock."""
|
|
191
|
-
self._steps += 1
|
|
192
|
-
self._time += deltat
|
|
193
|
-
|
|
194
|
-
def next_id(self) -> int:
|
|
195
|
-
"""Return the next unique ID for agents, increment current_id"""
|
|
196
|
-
self.current_id += 1
|
|
197
|
-
return self.current_id
|
|
198
|
-
|
|
199
228
|
def reset_randomizer(self, seed: int | None = None) -> None:
|
|
200
229
|
"""Reset the model random number generator.
|
|
201
230
|
|
|
202
231
|
Args:
|
|
203
232
|
seed: A new seed for the RNG; if None, reset using the current seed
|
|
204
233
|
"""
|
|
205
|
-
|
|
206
234
|
if seed is None:
|
|
207
235
|
seed = self._seed
|
|
208
236
|
self.random.seed(seed)
|
|
209
237
|
self._seed = seed
|
|
210
238
|
|
|
239
|
+
def reset_rng(self, rng: RNGLike | SeedLike | None = None) -> None:
|
|
240
|
+
"""Reset the model random number generator.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
rng: A new seed for the RNG; if None, reset using the current seed
|
|
244
|
+
"""
|
|
245
|
+
self.rng = np.random.default_rng(rng)
|
|
246
|
+
self._rng = self.rng.bit_generator.state
|
|
247
|
+
|
|
211
248
|
def initialize_data_collector(
|
|
212
249
|
self,
|
|
213
250
|
model_reporters=None,
|
|
@@ -215,14 +252,22 @@ class Model:
|
|
|
215
252
|
agenttype_reporters=None,
|
|
216
253
|
tables=None,
|
|
217
254
|
) -> None:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
255
|
+
"""Initialize the data collector for the model.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
model_reporters: model reporters to collect
|
|
259
|
+
agent_reporters: agent reporters to collect
|
|
260
|
+
agenttype_reporters: agent type reporters to collect
|
|
261
|
+
tables: tables to collect
|
|
262
|
+
|
|
263
|
+
"""
|
|
264
|
+
warnings.warn(
|
|
265
|
+
"initialize_data_collector() is deprecated. Please use the DataCollector class directly. "
|
|
266
|
+
"by using `self.datacollector = DataCollector(...)`.",
|
|
267
|
+
DeprecationWarning,
|
|
268
|
+
stacklevel=2,
|
|
269
|
+
)
|
|
270
|
+
|
|
226
271
|
self.datacollector = DataCollector(
|
|
227
272
|
model_reporters=model_reporters,
|
|
228
273
|
agent_reporters=agent_reporters,
|
|
@@ -231,3 +276,16 @@ class Model:
|
|
|
231
276
|
)
|
|
232
277
|
# Collect data for the first time during initialization.
|
|
233
278
|
self.datacollector.collect(self)
|
|
279
|
+
|
|
280
|
+
def remove_all_agents(self):
|
|
281
|
+
"""Remove all agents from the model.
|
|
282
|
+
|
|
283
|
+
Notes:
|
|
284
|
+
This method calls agent.remove for all agents in the model. If you need to remove agents from
|
|
285
|
+
e.g., a SingleGrid, you can either explicitly implement your own agent.remove method or clean this up
|
|
286
|
+
near where you are calling this method.
|
|
287
|
+
|
|
288
|
+
"""
|
|
289
|
+
# we need to wrap keys in a list to avoid a RunTimeError: dictionary changed size during iteration
|
|
290
|
+
for agent in list(self._agents.keys()):
|
|
291
|
+
agent.remove()
|