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.

Files changed (41) hide show
  1. mesa/__init__.py +2 -3
  2. mesa/agent.py +116 -85
  3. mesa/batchrunner.py +22 -23
  4. mesa/cookiecutter-mesa/hooks/post_gen_project.py +2 -0
  5. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/__init__.py +1 -0
  6. mesa/datacollection.py +138 -27
  7. mesa/experimental/UserParam.py +17 -6
  8. mesa/experimental/__init__.py +2 -0
  9. mesa/experimental/cell_space/__init__.py +14 -1
  10. mesa/experimental/cell_space/cell.py +84 -23
  11. mesa/experimental/cell_space/cell_agent.py +117 -21
  12. mesa/experimental/cell_space/cell_collection.py +54 -17
  13. mesa/experimental/cell_space/discrete_space.py +79 -7
  14. mesa/experimental/cell_space/grid.py +19 -8
  15. mesa/experimental/cell_space/network.py +9 -7
  16. mesa/experimental/cell_space/voronoi.py +26 -33
  17. mesa/experimental/components/altair.py +10 -0
  18. mesa/experimental/components/matplotlib.py +18 -0
  19. mesa/experimental/devs/__init__.py +2 -0
  20. mesa/experimental/devs/eventlist.py +36 -15
  21. mesa/experimental/devs/examples/epstein_civil_violence.py +65 -29
  22. mesa/experimental/devs/examples/wolf_sheep.py +40 -35
  23. mesa/experimental/devs/simulator.py +55 -15
  24. mesa/experimental/solara_viz.py +10 -19
  25. mesa/main.py +6 -4
  26. mesa/model.py +51 -54
  27. mesa/space.py +145 -120
  28. mesa/time.py +57 -67
  29. mesa/visualization/UserParam.py +19 -6
  30. mesa/visualization/__init__.py +3 -2
  31. mesa/visualization/components/altair.py +4 -2
  32. mesa/visualization/components/matplotlib.py +176 -85
  33. mesa/visualization/solara_viz.py +167 -84
  34. mesa/visualization/utils.py +3 -1
  35. {mesa-3.0.0a4.dist-info → mesa-3.0.0b0.dist-info}/METADATA +55 -13
  36. mesa-3.0.0b0.dist-info/RECORD +45 -0
  37. mesa-3.0.0b0.dist-info/licenses/LICENSE +202 -0
  38. mesa-3.0.0a4.dist-info/licenses/LICENSE → mesa-3.0.0b0.dist-info/licenses/NOTICE +2 -2
  39. mesa-3.0.0a4.dist-info/RECORD +0 -44
  40. {mesa-3.0.0a4.dist-info → mesa-3.0.0b0.dist-info}/WHEEL +0 -0
  41. {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
- Mesa Time Module
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
- - model (Model): The model instance associated with the scheduler.
50
- - steps (int): The number of steps the scheduler has taken.
51
- - time (TimeT): The current time in the simulation. Can be an integer or a float.
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. NOTE: The agent must
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
- A scheduler allowing agent activation to be divided into several stages, with all agents executing one stage
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
- super().__init__(model, agents)
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
- Remove all instances of a given agent from the schedule.
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
- shuffled.
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
@@ -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)
@@ -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, make_text
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: