Mesa 3.0.0a4__py3-none-any.whl → 3.0.0b0__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 +2 -3
- mesa/agent.py +116 -85
- mesa/batchrunner.py +22 -23
- mesa/cookiecutter-mesa/hooks/post_gen_project.py +2 -0
- mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/__init__.py +1 -0
- mesa/datacollection.py +138 -27
- mesa/experimental/UserParam.py +17 -6
- mesa/experimental/__init__.py +2 -0
- mesa/experimental/cell_space/__init__.py +14 -1
- mesa/experimental/cell_space/cell.py +84 -23
- mesa/experimental/cell_space/cell_agent.py +117 -21
- mesa/experimental/cell_space/cell_collection.py +54 -17
- mesa/experimental/cell_space/discrete_space.py +79 -7
- mesa/experimental/cell_space/grid.py +19 -8
- mesa/experimental/cell_space/network.py +9 -7
- mesa/experimental/cell_space/voronoi.py +26 -33
- mesa/experimental/components/altair.py +10 -0
- mesa/experimental/components/matplotlib.py +18 -0
- mesa/experimental/devs/__init__.py +2 -0
- mesa/experimental/devs/eventlist.py +36 -15
- mesa/experimental/devs/examples/epstein_civil_violence.py +65 -29
- mesa/experimental/devs/examples/wolf_sheep.py +40 -35
- mesa/experimental/devs/simulator.py +55 -15
- mesa/experimental/solara_viz.py +10 -19
- mesa/main.py +6 -4
- mesa/model.py +51 -54
- mesa/space.py +145 -120
- mesa/time.py +57 -67
- mesa/visualization/UserParam.py +19 -6
- mesa/visualization/__init__.py +3 -2
- mesa/visualization/components/altair.py +4 -2
- mesa/visualization/components/matplotlib.py +176 -85
- mesa/visualization/solara_viz.py +167 -84
- mesa/visualization/utils.py +3 -1
- {mesa-3.0.0a4.dist-info → mesa-3.0.0b0.dist-info}/METADATA +55 -13
- mesa-3.0.0b0.dist-info/RECORD +45 -0
- mesa-3.0.0b0.dist-info/licenses/LICENSE +202 -0
- mesa-3.0.0a4.dist-info/licenses/LICENSE → mesa-3.0.0b0.dist-info/licenses/NOTICE +2 -2
- mesa-3.0.0a4.dist-info/RECORD +0 -44
- {mesa-3.0.0a4.dist-info → mesa-3.0.0b0.dist-info}/WHEEL +0 -0
- {mesa-3.0.0a4.dist-info → mesa-3.0.0b0.dist-info}/entry_points.txt +0 -0
mesa/time.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"""Mesa Time Module.
|
|
2
|
+
|
|
3
|
+
.. warning::
|
|
4
|
+
The time module and all its Schedulers are deprecated and will be removed in a future version.
|
|
5
|
+
They can be replaced with AgentSet functionality. See the migration guide for details:
|
|
6
|
+
https://mesa.readthedocs.io/latest/migration_guide.html#time-and-schedulers
|
|
4
7
|
|
|
5
8
|
Objects for handling the time component of a model. In particular, this module
|
|
6
9
|
contains Schedulers, which handle agent activation. A Scheduler is an object
|
|
@@ -39,23 +42,16 @@ TimeT = float | int
|
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
class BaseScheduler:
|
|
42
|
-
"""
|
|
43
|
-
A simple scheduler that activates agents one at a time, in the order they were added.
|
|
45
|
+
"""A simple scheduler that activates agents one at a time, in the order they were added.
|
|
44
46
|
|
|
45
47
|
This scheduler is designed to replicate the behavior of the scheduler in MASON, a multi-agent simulation toolkit.
|
|
46
48
|
It assumes that each agent added has a `step` method which takes no arguments and executes the agent's actions.
|
|
47
49
|
|
|
48
50
|
Attributes:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
Methods:
|
|
54
|
-
- add: Adds an agent to the scheduler.
|
|
55
|
-
- remove: Removes an agent from the scheduler.
|
|
56
|
-
- step: Executes a step, which involves activating each agent once.
|
|
57
|
-
- get_agent_count: Returns the number of agents in the scheduler.
|
|
58
|
-
- agents (property): Returns a list of all agent instances.
|
|
51
|
+
model (Model): The model instance associated with the scheduler.
|
|
52
|
+
steps (int): The number of steps the scheduler has taken.
|
|
53
|
+
time (TimeT): The current time in the simulation. Can be an integer or a float.
|
|
54
|
+
|
|
59
55
|
"""
|
|
60
56
|
|
|
61
57
|
def __init__(self, model: Model, agents: Iterable[Agent] | None = None) -> None:
|
|
@@ -66,6 +62,14 @@ class BaseScheduler:
|
|
|
66
62
|
agents (Iterable[Agent], None, optional): An iterable of agents who are controlled by the schedule
|
|
67
63
|
|
|
68
64
|
"""
|
|
65
|
+
warnings.warn(
|
|
66
|
+
"The time module and all its Schedulers are deprecated and will be removed in a future version. "
|
|
67
|
+
"They can be replaced with AgentSet functionality. See the migration guide for details. "
|
|
68
|
+
"https://mesa.readthedocs.io/latest/migration_guide.html#time-and-schedulers",
|
|
69
|
+
DeprecationWarning,
|
|
70
|
+
stacklevel=2,
|
|
71
|
+
)
|
|
72
|
+
|
|
69
73
|
self.model = model
|
|
70
74
|
self.steps = 0
|
|
71
75
|
self.time: TimeT = 0
|
|
@@ -82,10 +86,8 @@ class BaseScheduler:
|
|
|
82
86
|
"""Add an Agent object to the schedule.
|
|
83
87
|
|
|
84
88
|
Args:
|
|
85
|
-
agent: An Agent to be added to the schedule.
|
|
86
|
-
have a step() method.
|
|
89
|
+
agent (Agent): An Agent to be added to the schedule.
|
|
87
90
|
"""
|
|
88
|
-
|
|
89
91
|
if agent not in self._agents:
|
|
90
92
|
self._agents.add(agent)
|
|
91
93
|
else:
|
|
@@ -94,12 +96,13 @@ class BaseScheduler:
|
|
|
94
96
|
def remove(self, agent: Agent) -> None:
|
|
95
97
|
"""Remove all instances of a given agent from the schedule.
|
|
96
98
|
|
|
99
|
+
Args:
|
|
100
|
+
agent: An `Agent` instance.
|
|
101
|
+
|
|
97
102
|
Note:
|
|
98
103
|
It is only necessary to explicitly remove agents from the schedule if
|
|
99
104
|
the agent is not removed from the model.
|
|
100
105
|
|
|
101
|
-
Args:
|
|
102
|
-
agent: An agent object.
|
|
103
106
|
"""
|
|
104
107
|
self._agents.remove(agent)
|
|
105
108
|
|
|
@@ -117,10 +120,12 @@ class BaseScheduler:
|
|
|
117
120
|
|
|
118
121
|
@property
|
|
119
122
|
def agents(self) -> AgentSet:
|
|
123
|
+
"""Return agents in the scheduler."""
|
|
120
124
|
# a bit dirty, but returns a copy of the internal agent set
|
|
121
125
|
return self._agents.select()
|
|
122
126
|
|
|
123
127
|
def get_agent_keys(self, shuffle: bool = False) -> list[int]:
|
|
128
|
+
"""Deprecated."""
|
|
124
129
|
# To be able to remove and/or add agents during stepping
|
|
125
130
|
# it's necessary to cast the keys view to a list.
|
|
126
131
|
|
|
@@ -138,14 +143,21 @@ class BaseScheduler:
|
|
|
138
143
|
return agent_keys
|
|
139
144
|
|
|
140
145
|
def do_each(self, method, shuffle=False):
|
|
146
|
+
"""Perform `method` on each agent.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
method: method to call
|
|
150
|
+
shuffle: shuffle the agents or not prior to calling method
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
"""
|
|
141
154
|
if shuffle:
|
|
142
155
|
self._agents.shuffle(inplace=True)
|
|
143
156
|
self._agents.do(method)
|
|
144
157
|
|
|
145
158
|
|
|
146
159
|
class RandomActivation(BaseScheduler):
|
|
147
|
-
"""
|
|
148
|
-
A scheduler that activates each agent once per step, in a random order, with the order reshuffled each step.
|
|
160
|
+
"""A scheduler that activates each agent once per step, in a random order, with the order reshuffled each step.
|
|
149
161
|
|
|
150
162
|
This scheduler is equivalent to the NetLogo 'ask agents...' behavior and is a common default for ABMs.
|
|
151
163
|
It assumes that all agents have a `step` method.
|
|
@@ -155,23 +167,17 @@ class RandomActivation(BaseScheduler):
|
|
|
155
167
|
|
|
156
168
|
Inherits all attributes and methods from BaseScheduler.
|
|
157
169
|
|
|
158
|
-
Methods:
|
|
159
|
-
- step: Executes a step, activating each agent in a random order.
|
|
160
170
|
"""
|
|
161
171
|
|
|
162
172
|
def step(self) -> None:
|
|
163
|
-
"""Executes the step of all agents, one at a time, in
|
|
164
|
-
random order.
|
|
165
|
-
|
|
166
|
-
"""
|
|
173
|
+
"""Executes the step of all agents, one at a time, in random order."""
|
|
167
174
|
self.do_each("step", shuffle=True)
|
|
168
175
|
self.steps += 1
|
|
169
176
|
self.time += 1
|
|
170
177
|
|
|
171
178
|
|
|
172
179
|
class SimultaneousActivation(BaseScheduler):
|
|
173
|
-
"""
|
|
174
|
-
A scheduler that simulates the simultaneous activation of all agents.
|
|
180
|
+
"""A scheduler that simulates the simultaneous activation of all agents.
|
|
175
181
|
|
|
176
182
|
This scheduler is unique in that it requires agents to have both `step` and `advance` methods.
|
|
177
183
|
- The `step` method is for activating the agent and staging any changes without applying them immediately.
|
|
@@ -182,8 +188,6 @@ class SimultaneousActivation(BaseScheduler):
|
|
|
182
188
|
|
|
183
189
|
Inherits all attributes and methods from BaseScheduler.
|
|
184
190
|
|
|
185
|
-
Methods:
|
|
186
|
-
- step: Executes a step for all agents, first calling `step` then `advance` on each.
|
|
187
191
|
"""
|
|
188
192
|
|
|
189
193
|
def step(self) -> None:
|
|
@@ -198,9 +202,9 @@ class SimultaneousActivation(BaseScheduler):
|
|
|
198
202
|
|
|
199
203
|
|
|
200
204
|
class StagedActivation(BaseScheduler):
|
|
201
|
-
"""
|
|
202
|
-
|
|
203
|
-
before moving on to the next. This class is a generalization of SimultaneousActivation.
|
|
205
|
+
"""A scheduler allowing agent activation to be divided into several stages.
|
|
206
|
+
|
|
207
|
+
All agents executing one stage before moving on to the next. This class is a generalization of SimultaneousActivation.
|
|
204
208
|
|
|
205
209
|
This scheduler is useful for complex models where actions need to be broken down into distinct phases
|
|
206
210
|
for each agent in each time step. Agents must implement methods for each defined stage.
|
|
@@ -215,8 +219,6 @@ class StagedActivation(BaseScheduler):
|
|
|
215
219
|
- shuffle (bool): Determines whether to shuffle the order of agents each step.
|
|
216
220
|
- shuffle_between_stages (bool): Determines whether to shuffle agents between each stage.
|
|
217
221
|
|
|
218
|
-
Methods:
|
|
219
|
-
- step: Executes all the stages for all agents in the defined order.
|
|
220
222
|
"""
|
|
221
223
|
|
|
222
224
|
def __init__(
|
|
@@ -261,8 +263,7 @@ class StagedActivation(BaseScheduler):
|
|
|
261
263
|
|
|
262
264
|
|
|
263
265
|
class RandomActivationByType(BaseScheduler):
|
|
264
|
-
"""
|
|
265
|
-
A scheduler that activates each type of agent once per step, in random order, with the order reshuffled every step.
|
|
266
|
+
"""A scheduler that activates each type of agent once per step, in random order, with the order reshuffled every step.
|
|
266
267
|
|
|
267
268
|
This scheduler is useful for models with multiple types of agents, ensuring that each type is treated
|
|
268
269
|
equitably in terms of activation order. The randomness in activation order helps in reducing biases
|
|
@@ -278,14 +279,10 @@ class RandomActivationByType(BaseScheduler):
|
|
|
278
279
|
Attributes:
|
|
279
280
|
- agents_by_type (defaultdict): A dictionary mapping agent types to dictionaries of agents.
|
|
280
281
|
|
|
281
|
-
Methods:
|
|
282
|
-
- step: Executes the step of each agent type in a random order.
|
|
283
|
-
- step_type: Activates all agents of a given type.
|
|
284
|
-
- get_type_count: Returns the count of agents of a specific type.
|
|
285
282
|
"""
|
|
286
283
|
|
|
287
284
|
@property
|
|
288
|
-
def agents_by_type(self):
|
|
285
|
+
def agents_by_type(self): # noqa: D102
|
|
289
286
|
warnings.warn(
|
|
290
287
|
"Because of the shift to using AgentSet, in the future this attribute will return a dict with"
|
|
291
288
|
"type as key as AgentSet as value. Future behavior is available via RandomActivationByType._agents_by_type",
|
|
@@ -300,14 +297,13 @@ class RandomActivationByType(BaseScheduler):
|
|
|
300
297
|
return agentsbytype
|
|
301
298
|
|
|
302
299
|
def __init__(self, model: Model, agents: Iterable[Agent] | None = None) -> None:
|
|
303
|
-
|
|
304
|
-
"""
|
|
300
|
+
"""Initialize RandomActivationByType instance.
|
|
305
301
|
|
|
306
302
|
Args:
|
|
307
303
|
model (Model): The model to which the schedule belongs
|
|
308
304
|
agents (Iterable[Agent], None, optional): An iterable of agents who are controlled by the schedule
|
|
309
305
|
"""
|
|
310
|
-
|
|
306
|
+
super().__init__(model, agents)
|
|
311
307
|
# can't be a defaultdict because we need to pass model to AgentSet
|
|
312
308
|
self._agents_by_type: [type, AgentSet] = {}
|
|
313
309
|
|
|
@@ -319,8 +315,7 @@ class RandomActivationByType(BaseScheduler):
|
|
|
319
315
|
self._agents_by_type[type(agent)] = AgentSet([agent], self.model)
|
|
320
316
|
|
|
321
317
|
def add(self, agent: Agent) -> None:
|
|
322
|
-
"""
|
|
323
|
-
Add an Agent object to the schedule
|
|
318
|
+
"""Add an Agent object to the schedule.
|
|
324
319
|
|
|
325
320
|
Args:
|
|
326
321
|
agent: An Agent to be added to the schedule.
|
|
@@ -333,21 +328,21 @@ class RandomActivationByType(BaseScheduler):
|
|
|
333
328
|
self._agents_by_type[type(agent)] = AgentSet([agent], self.model)
|
|
334
329
|
|
|
335
330
|
def remove(self, agent: Agent) -> None:
|
|
336
|
-
"""
|
|
337
|
-
|
|
331
|
+
"""Remove all instances of a given agent from the schedule.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
agent: An Agent to be removed from the schedule.
|
|
335
|
+
|
|
338
336
|
"""
|
|
339
337
|
super().remove(agent)
|
|
340
338
|
self._agents_by_type[type(agent)].remove(agent)
|
|
341
339
|
|
|
342
340
|
def step(self, shuffle_types: bool = True, shuffle_agents: bool = True) -> None:
|
|
343
|
-
"""
|
|
344
|
-
Executes the step of each agent type, one at a time, in random order.
|
|
341
|
+
"""Executes the step of each agent type, one at a time, in random order.
|
|
345
342
|
|
|
346
343
|
Args:
|
|
347
|
-
shuffle_types: If True, the order of execution of each types is
|
|
348
|
-
|
|
349
|
-
shuffle_agents: If True, the order of execution of each agents in a
|
|
350
|
-
type group is shuffled.
|
|
344
|
+
shuffle_types: If True, the order of execution of each types is shuffled.
|
|
345
|
+
shuffle_agents: If True, the order of execution of each agents in a type group is shuffled.
|
|
351
346
|
"""
|
|
352
347
|
# To be able to remove and/or add agents during stepping
|
|
353
348
|
# it's necessary to cast the keys view to a list.
|
|
@@ -360,12 +355,11 @@ class RandomActivationByType(BaseScheduler):
|
|
|
360
355
|
self.time += 1
|
|
361
356
|
|
|
362
357
|
def step_type(self, agenttype: type[Agent], shuffle_agents: bool = True) -> None:
|
|
363
|
-
"""
|
|
364
|
-
Shuffle order and run all agents of a given type.
|
|
365
|
-
This method is equivalent to the NetLogo 'ask [breed]...'.
|
|
358
|
+
"""Shuffle order and run all agents of a given type.
|
|
366
359
|
|
|
367
360
|
Args:
|
|
368
361
|
agenttype: Class object of the type to run.
|
|
362
|
+
shuffle_agents: If True, shuffle agents
|
|
369
363
|
"""
|
|
370
364
|
agents = self._agents_by_type[agenttype]
|
|
371
365
|
|
|
@@ -374,19 +368,15 @@ class RandomActivationByType(BaseScheduler):
|
|
|
374
368
|
agents.do("step")
|
|
375
369
|
|
|
376
370
|
def get_type_count(self, agenttype: type[Agent]) -> int:
|
|
377
|
-
"""
|
|
378
|
-
Returns the current number of agents of certain type in the queue.
|
|
379
|
-
"""
|
|
371
|
+
"""Returns the current number of agents of certain type in the queue."""
|
|
380
372
|
return len(self._agents_by_type[agenttype])
|
|
381
373
|
|
|
382
374
|
|
|
383
375
|
class DiscreteEventScheduler(BaseScheduler):
|
|
384
|
-
"""
|
|
385
|
-
This class has been deprecated and replaced by the functionality provided by experimental.devs
|
|
386
|
-
"""
|
|
376
|
+
"""This class has been deprecated and replaced by the functionality provided by experimental.devs."""
|
|
387
377
|
|
|
388
378
|
def __init__(self, model: Model, time_step: TimeT = 1) -> None:
|
|
389
|
-
"""
|
|
379
|
+
"""Initialize DiscreteEventScheduler.
|
|
390
380
|
|
|
391
381
|
Args:
|
|
392
382
|
model (Model): The model to which the schedule belongs
|
mesa/visualization/UserParam.py
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
"""Solara visualization related helper classes."""
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
class UserParam:
|
|
5
|
+
"""UserParam."""
|
|
6
|
+
|
|
2
7
|
_ERROR_MESSAGE = "Missing or malformed inputs for '{}' Option '{}'"
|
|
3
8
|
|
|
4
|
-
def maybe_raise_error(self, param_type, valid):
|
|
9
|
+
def maybe_raise_error(self, param_type, valid): # noqa: D102
|
|
5
10
|
if valid:
|
|
6
11
|
return
|
|
7
12
|
msg = self._ERROR_MESSAGE.format(param_type, self.label)
|
|
@@ -9,11 +14,9 @@ class UserParam:
|
|
|
9
14
|
|
|
10
15
|
|
|
11
16
|
class Slider(UserParam):
|
|
12
|
-
"""
|
|
13
|
-
A number-based slider input with settable increment.
|
|
17
|
+
"""A number-based slider input with settable increment.
|
|
14
18
|
|
|
15
19
|
Example:
|
|
16
|
-
|
|
17
20
|
slider_option = Slider("My Slider", value=123, min=10, max=200, step=0.1)
|
|
18
21
|
|
|
19
22
|
Args:
|
|
@@ -34,6 +37,16 @@ class Slider(UserParam):
|
|
|
34
37
|
step=1,
|
|
35
38
|
dtype=None,
|
|
36
39
|
):
|
|
40
|
+
"""Initializes a slider.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
label: The displayed label in the UI
|
|
44
|
+
value: The initial value of the slider
|
|
45
|
+
min: The minimum possible value of the slider
|
|
46
|
+
max: The maximum possible value of the slider
|
|
47
|
+
step: The step between min and max for a range of possible values
|
|
48
|
+
dtype: either int or float
|
|
49
|
+
"""
|
|
37
50
|
self.label = label
|
|
38
51
|
self.value = value
|
|
39
52
|
self.min = min
|
|
@@ -49,8 +62,8 @@ class Slider(UserParam):
|
|
|
49
62
|
else:
|
|
50
63
|
self.is_float_slider = dtype is float
|
|
51
64
|
|
|
52
|
-
def _check_values_are_float(self, value, min, max, step):
|
|
65
|
+
def _check_values_are_float(self, value, min, max, step): # D103
|
|
53
66
|
return any(isinstance(n, float) for n in (value, min, max, step))
|
|
54
67
|
|
|
55
|
-
def get(self, attr):
|
|
68
|
+
def get(self, attr): # noqa: D102
|
|
56
69
|
return getattr(self, attr)
|
mesa/visualization/__init__.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
"""Solara based visualization for Mesa models."""
|
|
2
|
+
|
|
1
3
|
from .components.altair import make_space_altair
|
|
2
4
|
from .components.matplotlib import make_plot_measure, make_space_matplotlib
|
|
3
|
-
from .solara_viz import JupyterViz, SolaraViz
|
|
5
|
+
from .solara_viz import JupyterViz, SolaraViz
|
|
4
6
|
from .UserParam import Slider
|
|
5
7
|
|
|
6
8
|
__all__ = [
|
|
7
9
|
"JupyterViz",
|
|
8
10
|
"SolaraViz",
|
|
9
|
-
"make_text",
|
|
10
11
|
"Slider",
|
|
11
12
|
"make_space_altair",
|
|
12
13
|
"make_space_matplotlib",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Altair based solara components for visualization mesa spaces."""
|
|
2
|
+
|
|
1
3
|
import contextlib
|
|
2
4
|
|
|
3
5
|
import solara
|
|
@@ -8,7 +10,7 @@ with contextlib.suppress(ImportError):
|
|
|
8
10
|
from mesa.visualization.utils import update_counter
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
def make_space_altair(agent_portrayal=None):
|
|
13
|
+
def make_space_altair(agent_portrayal=None): # noqa: D103
|
|
12
14
|
if agent_portrayal is None:
|
|
13
15
|
|
|
14
16
|
def agent_portrayal(a):
|
|
@@ -21,7 +23,7 @@ def make_space_altair(agent_portrayal=None):
|
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
@solara.component
|
|
24
|
-
def SpaceAltair(model, agent_portrayal, dependencies: list[any] | None = None):
|
|
26
|
+
def SpaceAltair(model, agent_portrayal, dependencies: list[any] | None = None): # noqa: D103
|
|
25
27
|
update_counter.get()
|
|
26
28
|
space = getattr(model, "grid", None)
|
|
27
29
|
if space is None:
|