Mesa 3.0.3__py3-none-any.whl → 3.1.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 +4 -6
- mesa/agent.py +48 -25
- mesa/batchrunner.py +14 -1
- mesa/datacollection.py +1 -6
- mesa/examples/__init__.py +2 -2
- mesa/examples/advanced/epstein_civil_violence/app.py +5 -0
- mesa/examples/advanced/pd_grid/app.py +5 -0
- mesa/examples/advanced/sugarscape_g1mt/app.py +7 -2
- mesa/examples/basic/boid_flockers/app.py +5 -0
- mesa/examples/basic/boltzmann_wealth_model/app.py +8 -5
- mesa/examples/basic/boltzmann_wealth_model/st_app.py +1 -1
- mesa/examples/basic/conways_game_of_life/app.py +5 -0
- mesa/examples/basic/conways_game_of_life/st_app.py +2 -2
- mesa/examples/basic/schelling/app.py +5 -0
- mesa/examples/basic/virus_on_network/app.py +5 -0
- mesa/experimental/__init__.py +17 -10
- mesa/experimental/cell_space/__init__.py +19 -7
- mesa/experimental/cell_space/cell.py +22 -37
- mesa/experimental/cell_space/cell_agent.py +12 -1
- mesa/experimental/cell_space/cell_collection.py +14 -1
- mesa/experimental/cell_space/discrete_space.py +15 -64
- mesa/experimental/cell_space/grid.py +74 -4
- mesa/experimental/cell_space/network.py +13 -1
- mesa/experimental/cell_space/property_layer.py +444 -0
- mesa/experimental/cell_space/voronoi.py +13 -1
- mesa/experimental/devs/__init__.py +20 -2
- mesa/experimental/devs/eventlist.py +19 -1
- mesa/experimental/devs/simulator.py +24 -8
- mesa/experimental/mesa_signals/__init__.py +23 -0
- mesa/experimental/mesa_signals/mesa_signal.py +485 -0
- mesa/experimental/mesa_signals/observable_collections.py +133 -0
- mesa/experimental/mesa_signals/signals_util.py +52 -0
- mesa/mesa_logging.py +190 -0
- mesa/model.py +17 -74
- mesa/visualization/__init__.py +2 -2
- mesa/visualization/mpl_space_drawing.py +2 -2
- mesa/visualization/solara_viz.py +12 -0
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/METADATA +3 -4
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/RECORD +43 -44
- mesa/experimental/UserParam.py +0 -67
- mesa/experimental/components/altair.py +0 -81
- mesa/experimental/components/matplotlib.py +0 -242
- mesa/experimental/devs/examples/epstein_civil_violence.py +0 -305
- mesa/experimental/devs/examples/wolf_sheep.py +0 -250
- mesa/experimental/solara_viz.py +0 -453
- mesa/time.py +0 -391
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/WHEEL +0 -0
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/entry_points.txt +0 -0
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/licenses/LICENSE +0 -0
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/licenses/NOTICE +0 -0
mesa/__init__.py
CHANGED
|
@@ -7,24 +7,22 @@ import datetime
|
|
|
7
7
|
|
|
8
8
|
import mesa.experimental as experimental
|
|
9
9
|
import mesa.space as space
|
|
10
|
-
import mesa.time as time
|
|
11
10
|
from mesa.agent import Agent
|
|
12
11
|
from mesa.batchrunner import batch_run
|
|
13
12
|
from mesa.datacollection import DataCollector
|
|
14
13
|
from mesa.model import Model
|
|
15
14
|
|
|
16
15
|
__all__ = [
|
|
17
|
-
"Model",
|
|
18
16
|
"Agent",
|
|
19
|
-
"time",
|
|
20
|
-
"space",
|
|
21
17
|
"DataCollector",
|
|
18
|
+
"Model",
|
|
22
19
|
"batch_run",
|
|
23
20
|
"experimental",
|
|
21
|
+
"space",
|
|
24
22
|
]
|
|
25
23
|
|
|
26
24
|
__title__ = "mesa"
|
|
27
|
-
__version__ = "3.0
|
|
25
|
+
__version__ = "3.1.0"
|
|
28
26
|
__license__ = "Apache 2.0"
|
|
29
|
-
_this_year = datetime.datetime.now(tz=datetime.
|
|
27
|
+
_this_year = datetime.datetime.now(tz=datetime.UTC).date().year
|
|
30
28
|
__copyright__ = f"Copyright {_this_year} Project Mesa Team"
|
mesa/agent.py
CHANGED
|
@@ -85,6 +85,54 @@ class Agent:
|
|
|
85
85
|
def advance(self) -> None: # noqa: D102
|
|
86
86
|
pass
|
|
87
87
|
|
|
88
|
+
@classmethod
|
|
89
|
+
def create_agents(cls, model: Model, n: int, *args, **kwargs) -> AgentSet[Agent]:
|
|
90
|
+
"""Create N agents.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
model: the model to which the agents belong
|
|
94
|
+
args: arguments to pass onto agent instances
|
|
95
|
+
each arg is either a single object or a sequence of length n
|
|
96
|
+
n: the number of agents to create
|
|
97
|
+
kwargs: keyword arguments to pass onto agent instances
|
|
98
|
+
each keyword arg is either a single object or a sequence of length n
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
AgentSet containing the agents created.
|
|
102
|
+
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
class ListLike:
|
|
106
|
+
"""Helper class to make default arguments act as if they are in a list of length N."""
|
|
107
|
+
|
|
108
|
+
def __init__(self, value):
|
|
109
|
+
self.value = value
|
|
110
|
+
|
|
111
|
+
def __getitem__(self, i):
|
|
112
|
+
return self.value
|
|
113
|
+
|
|
114
|
+
listlike_args = []
|
|
115
|
+
for arg in args:
|
|
116
|
+
if isinstance(arg, (list | np.ndarray | tuple)) and len(arg) == n:
|
|
117
|
+
listlike_args.append(arg)
|
|
118
|
+
else:
|
|
119
|
+
listlike_args.append(ListLike(arg))
|
|
120
|
+
|
|
121
|
+
listlike_kwargs = {}
|
|
122
|
+
for k, v in kwargs.items():
|
|
123
|
+
if isinstance(v, (list | np.ndarray | tuple)) and len(v) == n:
|
|
124
|
+
listlike_kwargs[k] = v
|
|
125
|
+
else:
|
|
126
|
+
listlike_kwargs[k] = ListLike(v)
|
|
127
|
+
|
|
128
|
+
agents = []
|
|
129
|
+
for i in range(n):
|
|
130
|
+
instance_args = [arg[i] for arg in listlike_args]
|
|
131
|
+
instance_kwargs = {k: v[i] for k, v in listlike_kwargs.items()}
|
|
132
|
+
agent = cls(model, *instance_args, **instance_kwargs)
|
|
133
|
+
agents.append(agent)
|
|
134
|
+
return AgentSet(agents, random=model.random)
|
|
135
|
+
|
|
88
136
|
@property
|
|
89
137
|
def random(self) -> Random:
|
|
90
138
|
"""Return a seeded stdlib rng."""
|
|
@@ -155,7 +203,6 @@ class AgentSet(MutableSet, Sequence):
|
|
|
155
203
|
at_most: int | float = float("inf"),
|
|
156
204
|
inplace: bool = False,
|
|
157
205
|
agent_type: type[Agent] | None = None,
|
|
158
|
-
n: int | None = None,
|
|
159
206
|
) -> AgentSet:
|
|
160
207
|
"""Select a subset of agents from the AgentSet based on a filter function and/or quantity limit.
|
|
161
208
|
|
|
@@ -167,7 +214,6 @@ class AgentSet(MutableSet, Sequence):
|
|
|
167
214
|
- If a float between 0 and 1, at most that fraction of original the agents are selected.
|
|
168
215
|
inplace (bool, optional): If True, modifies the current AgentSet; otherwise, returns a new AgentSet. Defaults to False.
|
|
169
216
|
agent_type (type[Agent], optional): The class type of the agents to select. Defaults to None, meaning no type filtering is applied.
|
|
170
|
-
n (int): deprecated, use at_most instead
|
|
171
217
|
|
|
172
218
|
Returns:
|
|
173
219
|
AgentSet: A new AgentSet containing the selected agents, unless inplace is True, in which case the current AgentSet is updated.
|
|
@@ -176,14 +222,6 @@ class AgentSet(MutableSet, Sequence):
|
|
|
176
222
|
- at_most just return the first n or fraction of agents. To take a random sample, shuffle() beforehand.
|
|
177
223
|
- at_most is an upper limit. When specifying other criteria, the number of agents returned can be smaller.
|
|
178
224
|
"""
|
|
179
|
-
if n is not None:
|
|
180
|
-
warnings.warn(
|
|
181
|
-
"The parameter 'n' is deprecated and will be removed in Mesa 3.1. Use 'at_most' instead.",
|
|
182
|
-
DeprecationWarning,
|
|
183
|
-
stacklevel=2,
|
|
184
|
-
)
|
|
185
|
-
at_most = n
|
|
186
|
-
|
|
187
225
|
inf = float("inf")
|
|
188
226
|
if filter_func is None and agent_type is None and at_most == inf:
|
|
189
227
|
return self if inplace else copy.copy(self)
|
|
@@ -281,21 +319,6 @@ class AgentSet(MutableSet, Sequence):
|
|
|
281
319
|
Returns:
|
|
282
320
|
AgentSet | list[Any]: The results of the callable calls if return_results is True, otherwise the AgentSet itself.
|
|
283
321
|
"""
|
|
284
|
-
try:
|
|
285
|
-
return_results = kwargs.pop("return_results")
|
|
286
|
-
except KeyError:
|
|
287
|
-
return_results = False
|
|
288
|
-
else:
|
|
289
|
-
warnings.warn(
|
|
290
|
-
"Using return_results is deprecated and will be removed in Mesa 3.1."
|
|
291
|
-
"Use AgenSet.do in case of return_results=False, and AgentSet.map in case of return_results=True",
|
|
292
|
-
DeprecationWarning,
|
|
293
|
-
stacklevel=2,
|
|
294
|
-
)
|
|
295
|
-
|
|
296
|
-
if return_results:
|
|
297
|
-
return self.map(method, *args, **kwargs)
|
|
298
|
-
|
|
299
322
|
# we iterate over the actual weakref keys and check if weakref is alive before calling the method
|
|
300
323
|
if isinstance(method, str):
|
|
301
324
|
for agentref in self._agents.keyrefs():
|
mesa/batchrunner.py
CHANGED
|
@@ -106,7 +106,14 @@ def _make_model_kwargs(
|
|
|
106
106
|
Parameters
|
|
107
107
|
----------
|
|
108
108
|
parameters : Mapping[str, Union[Any, Iterable[Any]]]
|
|
109
|
-
Single or multiple values for each model parameter name
|
|
109
|
+
Single or multiple values for each model parameter name.
|
|
110
|
+
|
|
111
|
+
Allowed values for each parameter:
|
|
112
|
+
- A single value (e.g., `32`, `"relu"`).
|
|
113
|
+
- A non-empty iterable (e.g., `[0.01, 0.1]`, `["relu", "sigmoid"]`).
|
|
114
|
+
|
|
115
|
+
Not allowed:
|
|
116
|
+
- Empty lists or empty iterables (e.g., `[]`, `()`, etc.). These should be removed manually.
|
|
110
117
|
|
|
111
118
|
Returns:
|
|
112
119
|
-------
|
|
@@ -118,6 +125,12 @@ def _make_model_kwargs(
|
|
|
118
125
|
if isinstance(values, str):
|
|
119
126
|
# The values is a single string, so we shouldn't iterate over it.
|
|
120
127
|
all_values = [(param, values)]
|
|
128
|
+
elif isinstance(values, list | tuple | set) and len(values) == 0:
|
|
129
|
+
# If it's an empty iterable, raise an error
|
|
130
|
+
raise ValueError(
|
|
131
|
+
f"Parameter '{param}' contains an empty iterable, which is not allowed."
|
|
132
|
+
)
|
|
133
|
+
|
|
121
134
|
else:
|
|
122
135
|
try:
|
|
123
136
|
all_values = [(param, value) for value in values]
|
mesa/datacollection.py
CHANGED
|
@@ -228,12 +228,7 @@ class DataCollector:
|
|
|
228
228
|
reports = tuple(rep(agent) for rep in rep_funcs)
|
|
229
229
|
return _prefix + reports
|
|
230
230
|
|
|
231
|
-
agent_records = map(
|
|
232
|
-
get_reports,
|
|
233
|
-
model.schedule.agents
|
|
234
|
-
if hasattr(model, "schedule") and model.schedule is not None
|
|
235
|
-
else model.agents,
|
|
236
|
-
)
|
|
231
|
+
agent_records = map(get_reports, model.agents)
|
|
237
232
|
return agent_records
|
|
238
233
|
|
|
239
234
|
def _record_agenttype(self, model, agent_type):
|
mesa/examples/__init__.py
CHANGED
|
@@ -24,6 +24,11 @@ def pd_agent_portrayal(agent):
|
|
|
24
24
|
|
|
25
25
|
# Model parameters
|
|
26
26
|
model_params = {
|
|
27
|
+
"seed": {
|
|
28
|
+
"type": "InputText",
|
|
29
|
+
"value": 42,
|
|
30
|
+
"label": "Random Seed",
|
|
31
|
+
},
|
|
27
32
|
"width": Slider("Grid Width", value=50, min=10, max=100, step=1),
|
|
28
33
|
"height": Slider("Grid Height", value=50, min=10, max=100, step=1),
|
|
29
34
|
"activation_order": {
|
|
@@ -47,6 +47,11 @@ def SpaceDrawer(model):
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
model_params = {
|
|
50
|
+
"seed": {
|
|
51
|
+
"type": "InputText",
|
|
52
|
+
"value": 42,
|
|
53
|
+
"label": "Random Seed",
|
|
54
|
+
},
|
|
50
55
|
"width": 50,
|
|
51
56
|
"height": 50,
|
|
52
57
|
# Population parameters
|
|
@@ -66,10 +71,10 @@ model_params = {
|
|
|
66
71
|
"enable_trade": {"type": "Checkbox", "value": True, "label": "Enable Trading"},
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
|
|
74
|
+
model = SugarscapeG1mt()
|
|
70
75
|
|
|
71
76
|
page = SolaraViz(
|
|
72
|
-
|
|
77
|
+
model,
|
|
73
78
|
components=[SpaceDrawer, make_plot_component(["Trader", "Price"])],
|
|
74
79
|
model_params=model_params,
|
|
75
80
|
name="Sugarscape {G1, M, T}",
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
from mesa.examples.basic.boltzmann_wealth_model.model import BoltzmannWealth
|
|
2
|
+
from mesa.mesa_logging import DEBUG, log_to_stderr
|
|
2
3
|
from mesa.visualization import (
|
|
3
4
|
SolaraViz,
|
|
4
5
|
make_plot_component,
|
|
5
6
|
make_space_component,
|
|
6
7
|
)
|
|
7
8
|
|
|
9
|
+
log_to_stderr(DEBUG)
|
|
10
|
+
|
|
8
11
|
|
|
9
12
|
def agent_portrayal(agent):
|
|
10
13
|
color = agent.wealth # we are using a colormap to translate wealth to color
|
|
@@ -12,6 +15,11 @@ def agent_portrayal(agent):
|
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
model_params = {
|
|
18
|
+
"seed": {
|
|
19
|
+
"type": "InputText",
|
|
20
|
+
"value": 42,
|
|
21
|
+
"label": "Random Seed",
|
|
22
|
+
},
|
|
15
23
|
"n": {
|
|
16
24
|
"type": "SliderInt",
|
|
17
25
|
"value": 50,
|
|
@@ -20,11 +28,6 @@ model_params = {
|
|
|
20
28
|
"max": 100,
|
|
21
29
|
"step": 1,
|
|
22
30
|
},
|
|
23
|
-
"seed": {
|
|
24
|
-
"type": "InputText",
|
|
25
|
-
"value": 42,
|
|
26
|
-
"label": "Random Seed",
|
|
27
|
-
},
|
|
28
31
|
"width": 10,
|
|
29
32
|
"height": 10,
|
|
30
33
|
}
|
|
@@ -68,7 +68,7 @@ if run:
|
|
|
68
68
|
for i in range(num_ticks):
|
|
69
69
|
model.step()
|
|
70
70
|
my_bar.progress((i / num_ticks), text="Simulation progress")
|
|
71
|
-
placeholder.text("Step =
|
|
71
|
+
placeholder.text(f"Step = {i}")
|
|
72
72
|
for cell in model.grid.coord_iter():
|
|
73
73
|
cell_content, (x, y) = cell
|
|
74
74
|
agent_count = len(cell_content)
|
|
@@ -49,9 +49,9 @@ if run:
|
|
|
49
49
|
for i in range(num_ticks):
|
|
50
50
|
model.step()
|
|
51
51
|
my_bar.progress((i / num_ticks), text="Simulation progress")
|
|
52
|
-
placeholder.text("Step =
|
|
52
|
+
placeholder.text(f"Step = {i}")
|
|
53
53
|
for contents, (x, y) in model.grid.coord_iter():
|
|
54
|
-
# print(
|
|
54
|
+
# print(f"x: {x}, y: {y}, state: {contents}")
|
|
55
55
|
selected_row = df_grid[(df_grid["x"] == x) & (df_grid["y"] == y)]
|
|
56
56
|
df_grid.loc[selected_row.index, "state"] = (
|
|
57
57
|
contents.state
|
|
@@ -19,6 +19,11 @@ def agent_portrayal(agent):
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
model_params = {
|
|
22
|
+
"seed": {
|
|
23
|
+
"type": "InputText",
|
|
24
|
+
"value": 42,
|
|
25
|
+
"label": "Random Seed",
|
|
26
|
+
},
|
|
22
27
|
"density": Slider("Agent density", 0.8, 0.1, 1.0, 0.1),
|
|
23
28
|
"minority_pc": Slider("Fraction minority", 0.2, 0.0, 1.0, 0.05),
|
|
24
29
|
"homophily": Slider("Homophily", 3, 0, 8, 1),
|
mesa/experimental/__init__.py
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
"""Experimental
|
|
1
|
+
"""Experimental features package for Mesa.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This package contains modules that are under active development and testing. These
|
|
4
|
+
features are provided to allow early access and feedback from the Mesa community, but
|
|
5
|
+
their APIs may change between releases without following semantic versioning.
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
Current experimental modules:
|
|
8
|
+
cell_space: Alternative API for discrete spaces with cell-centric functionality
|
|
9
|
+
devs: Discrete event simulation system for scheduling events at arbitrary times
|
|
10
|
+
mesa_signals: Reactive programming capabilities for tracking state changes
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
Notes:
|
|
13
|
+
- Features in this package may be changed or removed without notice
|
|
14
|
+
- APIs are not guaranteed to be stable between releases
|
|
15
|
+
- Features graduate from experimental status once their APIs are stabilized
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from mesa.experimental import cell_space, devs, mesa_signals
|
|
19
|
+
|
|
20
|
+
__all__ = ["cell_space", "devs", "mesa_signals"]
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
"""Cell spaces.
|
|
1
|
+
"""Cell spaces for active, property-rich spatial modeling in Mesa.
|
|
2
2
|
|
|
3
|
-
Cell spaces
|
|
4
|
-
|
|
3
|
+
Cell spaces extend Mesa's spatial modeling capabilities by making the space itself active -
|
|
4
|
+
each position (cell) can have properties and behaviors rather than just containing agents.
|
|
5
|
+
This enables more sophisticated environmental modeling and agent-environment interactions.
|
|
5
6
|
|
|
7
|
+
Key components:
|
|
8
|
+
- Cells: Active positions that can have properties and contain agents
|
|
9
|
+
- CellAgents: Agents that understand how to interact with cells
|
|
10
|
+
- Spaces: Different cell organization patterns (grids, networks, etc.)
|
|
11
|
+
- PropertyLayers: Efficient property storage and manipulation
|
|
12
|
+
|
|
13
|
+
This is particularly useful for models where the environment plays an active role,
|
|
14
|
+
like resource growth, pollution diffusion, or infrastructure networks. The cell
|
|
15
|
+
space system is experimental and under active development.
|
|
6
16
|
"""
|
|
7
17
|
|
|
8
18
|
from mesa.experimental.cell_space.cell import Cell
|
|
@@ -20,19 +30,21 @@ from mesa.experimental.cell_space.grid import (
|
|
|
20
30
|
OrthogonalVonNeumannGrid,
|
|
21
31
|
)
|
|
22
32
|
from mesa.experimental.cell_space.network import Network
|
|
33
|
+
from mesa.experimental.cell_space.property_layer import PropertyLayer
|
|
23
34
|
from mesa.experimental.cell_space.voronoi import VoronoiGrid
|
|
24
35
|
|
|
25
36
|
__all__ = [
|
|
26
|
-
"CellCollection",
|
|
27
37
|
"Cell",
|
|
28
38
|
"CellAgent",
|
|
29
|
-
"
|
|
30
|
-
"FixedAgent",
|
|
39
|
+
"CellCollection",
|
|
31
40
|
"DiscreteSpace",
|
|
41
|
+
"FixedAgent",
|
|
32
42
|
"Grid",
|
|
43
|
+
"Grid2DMovingAgent",
|
|
33
44
|
"HexGrid",
|
|
45
|
+
"Network",
|
|
34
46
|
"OrthogonalMooreGrid",
|
|
35
47
|
"OrthogonalVonNeumannGrid",
|
|
36
|
-
"
|
|
48
|
+
"PropertyLayer",
|
|
37
49
|
"VoronoiGrid",
|
|
38
50
|
]
|
|
@@ -1,15 +1,25 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Cells are positions in space that can have properties and contain agents.
|
|
2
|
+
|
|
3
|
+
A cell represents a location that can:
|
|
4
|
+
- Have properties (like temperature or resources)
|
|
5
|
+
- Track and limit the agents it contains
|
|
6
|
+
- Connect to neighboring cells
|
|
7
|
+
- Provide neighborhood information
|
|
8
|
+
|
|
9
|
+
Cells form the foundation of the cell space system, enabling rich spatial
|
|
10
|
+
environments where both location properties and agent behaviors matter. They're
|
|
11
|
+
useful for modeling things like varying terrain, infrastructure capacity, or
|
|
12
|
+
environmental conditions.
|
|
13
|
+
"""
|
|
2
14
|
|
|
3
15
|
from __future__ import annotations
|
|
4
16
|
|
|
5
|
-
from collections.abc import Callable
|
|
6
17
|
from functools import cache, cached_property
|
|
7
18
|
from random import Random
|
|
8
|
-
from typing import TYPE_CHECKING
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
9
20
|
|
|
10
21
|
from mesa.experimental.cell_space.cell_agent import CellAgent
|
|
11
22
|
from mesa.experimental.cell_space.cell_collection import CellCollection
|
|
12
|
-
from mesa.space import PropertyLayer
|
|
13
23
|
|
|
14
24
|
if TYPE_CHECKING:
|
|
15
25
|
from mesa.agent import Agent
|
|
@@ -24,31 +34,20 @@ class Cell:
|
|
|
24
34
|
coordinate (Tuple[int, int]) : the position of the cell in the discrete space
|
|
25
35
|
agents (List[Agent]): the agents occupying the cell
|
|
26
36
|
capacity (int): the maximum number of agents that can simultaneously occupy the cell
|
|
27
|
-
properties (dict[str, Any]): the properties of the cell
|
|
28
37
|
random (Random): the random number generator
|
|
29
38
|
|
|
30
39
|
"""
|
|
31
40
|
|
|
32
41
|
__slots__ = [
|
|
33
|
-
"
|
|
34
|
-
"connections",
|
|
42
|
+
"__dict__",
|
|
35
43
|
"agents",
|
|
36
44
|
"capacity",
|
|
45
|
+
"connections",
|
|
46
|
+
"coordinate",
|
|
37
47
|
"properties",
|
|
38
48
|
"random",
|
|
39
|
-
"_mesa_property_layers",
|
|
40
|
-
"__dict__",
|
|
41
49
|
]
|
|
42
50
|
|
|
43
|
-
# def __new__(cls,
|
|
44
|
-
# coordinate: tuple[int, ...],
|
|
45
|
-
# capacity: float | None = None,
|
|
46
|
-
# random: Random | None = None,):
|
|
47
|
-
# if capacity != 1:
|
|
48
|
-
# return object.__new__(cls)
|
|
49
|
-
# else:
|
|
50
|
-
# return object.__new__(SingleAgentCell)
|
|
51
|
-
|
|
52
51
|
def __init__(
|
|
53
52
|
self,
|
|
54
53
|
coordinate: Coordinate,
|
|
@@ -70,9 +69,10 @@ class Cell:
|
|
|
70
69
|
Agent
|
|
71
70
|
] = [] # TODO:: change to AgentSet or weakrefs? (neither is very performant, )
|
|
72
71
|
self.capacity: int | None = capacity
|
|
73
|
-
self.properties: dict[
|
|
72
|
+
self.properties: dict[
|
|
73
|
+
Coordinate, object
|
|
74
|
+
] = {} # fixme still used by voronoi mesh
|
|
74
75
|
self.random = random
|
|
75
|
-
self._mesa_property_layers: dict[str, PropertyLayer] = {}
|
|
76
76
|
|
|
77
77
|
def connect(self, other: Cell, key: Coordinate | None = None) -> None:
|
|
78
78
|
"""Connects this cell to another cell.
|
|
@@ -105,6 +105,7 @@ class Cell:
|
|
|
105
105
|
|
|
106
106
|
"""
|
|
107
107
|
n = len(self.agents)
|
|
108
|
+
self.empty = False
|
|
108
109
|
|
|
109
110
|
if self.capacity and n >= self.capacity:
|
|
110
111
|
raise Exception(
|
|
@@ -121,6 +122,7 @@ class Cell:
|
|
|
121
122
|
|
|
122
123
|
"""
|
|
123
124
|
self.agents.remove(agent)
|
|
125
|
+
self.empty = self.is_empty
|
|
124
126
|
|
|
125
127
|
@property
|
|
126
128
|
def is_empty(self) -> bool:
|
|
@@ -195,23 +197,6 @@ class Cell:
|
|
|
195
197
|
neighborhood.pop(self, None)
|
|
196
198
|
return neighborhood
|
|
197
199
|
|
|
198
|
-
# PropertyLayer methods
|
|
199
|
-
def get_property(self, property_name: str) -> Any:
|
|
200
|
-
"""Get the value of a property."""
|
|
201
|
-
return self._mesa_property_layers[property_name].data[self.coordinate]
|
|
202
|
-
|
|
203
|
-
def set_property(self, property_name: str, value: Any):
|
|
204
|
-
"""Set the value of a property."""
|
|
205
|
-
self._mesa_property_layers[property_name].set_cell(self.coordinate, value)
|
|
206
|
-
|
|
207
|
-
def modify_property(
|
|
208
|
-
self, property_name: str, operation: Callable, value: Any = None
|
|
209
|
-
):
|
|
210
|
-
"""Modify the value of a property."""
|
|
211
|
-
self._mesa_property_layers[property_name].modify_cell(
|
|
212
|
-
self.coordinate, operation, value
|
|
213
|
-
)
|
|
214
|
-
|
|
215
200
|
def __getstate__(self):
|
|
216
201
|
"""Return state of the Cell with connections set to empty."""
|
|
217
202
|
# fixme, once we shift to 3.11, replace this with super. __getstate__
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Agents that understand how to exist in and move through cell spaces.
|
|
2
|
+
|
|
3
|
+
Provides specialized agent classes that handle cell occupation, movement, and
|
|
4
|
+
proper registration:
|
|
5
|
+
- CellAgent: Mobile agents that can move between cells
|
|
6
|
+
- FixedAgent: Immobile agents permanently fixed to cells
|
|
7
|
+
- Grid2DMovingAgent: Agents with grid-specific movement capabilities
|
|
8
|
+
|
|
9
|
+
These classes ensure consistent agent-cell relationships and proper state management
|
|
10
|
+
as agents move through the space. They can be used directly or as examples for
|
|
11
|
+
creating custom cell-aware agents.
|
|
12
|
+
"""
|
|
2
13
|
|
|
3
14
|
from __future__ import annotations
|
|
4
15
|
|
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Collection class for managing and querying groups of cells.
|
|
2
|
+
|
|
3
|
+
The CellCollection class provides a consistent interface for operating on multiple
|
|
4
|
+
cells, supporting:
|
|
5
|
+
- Filtering and selecting cells based on conditions
|
|
6
|
+
- Random cell and agent selection
|
|
7
|
+
- Access to contained agents
|
|
8
|
+
- Group operations
|
|
9
|
+
|
|
10
|
+
This is useful for implementing area effects, zones, or any operation that needs
|
|
11
|
+
to work with multiple cells as a unit. The collection handles efficient iteration
|
|
12
|
+
and agent access across cells. The class is used throughout the cell space
|
|
13
|
+
implementation to represent neighborhoods, selections, and other cell groupings.
|
|
14
|
+
"""
|
|
2
15
|
|
|
3
16
|
from __future__ import annotations
|
|
4
17
|
|