Mesa 3.1.0__py3-none-any.whl → 3.1.0.dev0__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 -3
- mesa/agent.py +0 -48
- mesa/batchrunner.py +1 -14
- mesa/datacollection.py +6 -1
- mesa/examples/__init__.py +2 -2
- mesa/examples/advanced/epstein_civil_violence/app.py +0 -5
- mesa/examples/advanced/pd_grid/app.py +0 -5
- mesa/examples/advanced/sugarscape_g1mt/app.py +2 -7
- mesa/examples/basic/boid_flockers/app.py +0 -5
- mesa/examples/basic/boltzmann_wealth_model/app.py +5 -8
- mesa/examples/basic/boltzmann_wealth_model/st_app.py +1 -1
- mesa/examples/basic/conways_game_of_life/app.py +0 -5
- mesa/examples/basic/conways_game_of_life/st_app.py +2 -2
- mesa/examples/basic/schelling/app.py +0 -5
- mesa/examples/basic/virus_on_network/app.py +0 -5
- mesa/experimental/UserParam.py +67 -0
- mesa/experimental/__init__.py +10 -17
- mesa/experimental/cell_space/__init__.py +7 -19
- mesa/experimental/cell_space/cell.py +37 -22
- mesa/experimental/cell_space/cell_agent.py +1 -12
- mesa/experimental/cell_space/cell_collection.py +3 -18
- mesa/experimental/cell_space/discrete_space.py +64 -15
- mesa/experimental/cell_space/grid.py +4 -74
- mesa/experimental/cell_space/network.py +1 -13
- mesa/experimental/cell_space/voronoi.py +1 -13
- mesa/experimental/components/altair.py +81 -0
- mesa/experimental/components/matplotlib.py +242 -0
- mesa/experimental/devs/__init__.py +2 -20
- mesa/experimental/devs/eventlist.py +1 -19
- mesa/experimental/devs/examples/epstein_civil_violence.py +305 -0
- mesa/experimental/devs/examples/wolf_sheep.py +250 -0
- mesa/experimental/devs/simulator.py +8 -24
- mesa/experimental/solara_viz.py +453 -0
- mesa/model.py +23 -17
- mesa/visualization/__init__.py +2 -2
- mesa/visualization/mpl_space_drawing.py +2 -2
- mesa/visualization/solara_viz.py +5 -23
- {mesa-3.1.0.dist-info → mesa-3.1.0.dev0.dist-info}/METADATA +1 -1
- {mesa-3.1.0.dist-info → mesa-3.1.0.dev0.dist-info}/RECORD +43 -43
- {mesa-3.1.0.dist-info → mesa-3.1.0.dev0.dist-info}/WHEEL +1 -1
- mesa/experimental/cell_space/property_layer.py +0 -444
- mesa/experimental/mesa_signals/__init__.py +0 -23
- mesa/experimental/mesa_signals/mesa_signal.py +0 -485
- mesa/experimental/mesa_signals/observable_collections.py +0 -133
- mesa/experimental/mesa_signals/signals_util.py +0 -52
- mesa/mesa_logging.py +0 -190
- {mesa-3.1.0.dist-info → mesa-3.1.0.dev0.dist-info}/entry_points.txt +0 -0
- {mesa-3.1.0.dist-info → mesa-3.1.0.dev0.dist-info}/licenses/LICENSE +0 -0
- {mesa-3.1.0.dist-info → mesa-3.1.0.dev0.dist-info}/licenses/NOTICE +0 -0
mesa/__init__.py
CHANGED
|
@@ -13,16 +13,16 @@ from mesa.datacollection import DataCollector
|
|
|
13
13
|
from mesa.model import Model
|
|
14
14
|
|
|
15
15
|
__all__ = [
|
|
16
|
+
"Model",
|
|
16
17
|
"Agent",
|
|
18
|
+
"space",
|
|
17
19
|
"DataCollector",
|
|
18
|
-
"Model",
|
|
19
20
|
"batch_run",
|
|
20
21
|
"experimental",
|
|
21
|
-
"space",
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
__title__ = "mesa"
|
|
25
|
-
__version__ = "3.1.0"
|
|
25
|
+
__version__ = "3.1.0.dev"
|
|
26
26
|
__license__ = "Apache 2.0"
|
|
27
27
|
_this_year = datetime.datetime.now(tz=datetime.UTC).date().year
|
|
28
28
|
__copyright__ = f"Copyright {_this_year} Project Mesa Team"
|
mesa/agent.py
CHANGED
|
@@ -85,54 +85,6 @@ 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
|
-
|
|
136
88
|
@property
|
|
137
89
|
def random(self) -> Random:
|
|
138
90
|
"""Return a seeded stdlib rng."""
|
mesa/batchrunner.py
CHANGED
|
@@ -106,14 +106,7 @@ 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
|
|
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.
|
|
109
|
+
Single or multiple values for each model parameter name
|
|
117
110
|
|
|
118
111
|
Returns:
|
|
119
112
|
-------
|
|
@@ -125,12 +118,6 @@ def _make_model_kwargs(
|
|
|
125
118
|
if isinstance(values, str):
|
|
126
119
|
# The values is a single string, so we shouldn't iterate over it.
|
|
127
120
|
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
|
-
|
|
134
121
|
else:
|
|
135
122
|
try:
|
|
136
123
|
all_values = [(param, value) for value in values]
|
mesa/datacollection.py
CHANGED
|
@@ -228,7 +228,12 @@ class DataCollector:
|
|
|
228
228
|
reports = tuple(rep(agent) for rep in rep_funcs)
|
|
229
229
|
return _prefix + reports
|
|
230
230
|
|
|
231
|
-
agent_records = map(
|
|
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
|
+
)
|
|
232
237
|
return agent_records
|
|
233
238
|
|
|
234
239
|
def _record_agenttype(self, model, agent_type):
|
mesa/examples/__init__.py
CHANGED
|
@@ -24,11 +24,6 @@ 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
|
-
},
|
|
32
27
|
"width": Slider("Grid Width", value=50, min=10, max=100, step=1),
|
|
33
28
|
"height": Slider("Grid Height", value=50, min=10, max=100, step=1),
|
|
34
29
|
"activation_order": {
|
|
@@ -47,11 +47,6 @@ def SpaceDrawer(model):
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
model_params = {
|
|
50
|
-
"seed": {
|
|
51
|
-
"type": "InputText",
|
|
52
|
-
"value": 42,
|
|
53
|
-
"label": "Random Seed",
|
|
54
|
-
},
|
|
55
50
|
"width": 50,
|
|
56
51
|
"height": 50,
|
|
57
52
|
# Population parameters
|
|
@@ -71,10 +66,10 @@ model_params = {
|
|
|
71
66
|
"enable_trade": {"type": "Checkbox", "value": True, "label": "Enable Trading"},
|
|
72
67
|
}
|
|
73
68
|
|
|
74
|
-
|
|
69
|
+
model1 = SugarscapeG1mt()
|
|
75
70
|
|
|
76
71
|
page = SolaraViz(
|
|
77
|
-
|
|
72
|
+
model1,
|
|
78
73
|
components=[SpaceDrawer, make_plot_component(["Trader", "Price"])],
|
|
79
74
|
model_params=model_params,
|
|
80
75
|
name="Sugarscape {G1, M, T}",
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
from mesa.examples.basic.boltzmann_wealth_model.model import BoltzmannWealth
|
|
2
|
-
from mesa.mesa_logging import DEBUG, log_to_stderr
|
|
3
2
|
from mesa.visualization import (
|
|
4
3
|
SolaraViz,
|
|
5
4
|
make_plot_component,
|
|
6
5
|
make_space_component,
|
|
7
6
|
)
|
|
8
7
|
|
|
9
|
-
log_to_stderr(DEBUG)
|
|
10
|
-
|
|
11
8
|
|
|
12
9
|
def agent_portrayal(agent):
|
|
13
10
|
color = agent.wealth # we are using a colormap to translate wealth to color
|
|
@@ -15,11 +12,6 @@ def agent_portrayal(agent):
|
|
|
15
12
|
|
|
16
13
|
|
|
17
14
|
model_params = {
|
|
18
|
-
"seed": {
|
|
19
|
-
"type": "InputText",
|
|
20
|
-
"value": 42,
|
|
21
|
-
"label": "Random Seed",
|
|
22
|
-
},
|
|
23
15
|
"n": {
|
|
24
16
|
"type": "SliderInt",
|
|
25
17
|
"value": 50,
|
|
@@ -28,6 +20,11 @@ model_params = {
|
|
|
28
20
|
"max": 100,
|
|
29
21
|
"step": 1,
|
|
30
22
|
},
|
|
23
|
+
"seed": {
|
|
24
|
+
"type": "InputText",
|
|
25
|
+
"value": 42,
|
|
26
|
+
"label": "Random Seed",
|
|
27
|
+
},
|
|
31
28
|
"width": 10,
|
|
32
29
|
"height": 10,
|
|
33
30
|
}
|
|
@@ -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(
|
|
71
|
+
placeholder.text("Step = %d" % 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(
|
|
52
|
+
placeholder.text("Step = %d" % i)
|
|
53
53
|
for contents, (x, y) in model.grid.coord_iter():
|
|
54
|
-
# print(
|
|
54
|
+
# print('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,11 +19,6 @@ 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
|
-
},
|
|
27
22
|
"density": Slider("Agent density", 0.8, 0.1, 1.0, 0.1),
|
|
28
23
|
"minority_pc": Slider("Fraction minority", 0.2, 0.0, 1.0, 0.05),
|
|
29
24
|
"homophily": Slider("Homophily", 3, 0, 8, 1),
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""helper classes."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class UserParam: # noqa: D101
|
|
5
|
+
_ERROR_MESSAGE = "Missing or malformed inputs for '{}' Option '{}'"
|
|
6
|
+
|
|
7
|
+
def maybe_raise_error(self, param_type, valid): # noqa: D102
|
|
8
|
+
if valid:
|
|
9
|
+
return
|
|
10
|
+
msg = self._ERROR_MESSAGE.format(param_type, self.label)
|
|
11
|
+
raise ValueError(msg)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Slider(UserParam):
|
|
15
|
+
"""A number-based slider input with settable increment.
|
|
16
|
+
|
|
17
|
+
Example:
|
|
18
|
+
slider_option = Slider("My Slider", value=123, min=10, max=200, step=0.1)
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
label: The displayed label in the UI
|
|
22
|
+
value: The initial value of the slider
|
|
23
|
+
min: The minimum possible value of the slider
|
|
24
|
+
max: The maximum possible value of the slider
|
|
25
|
+
step: The step between min and max for a range of possible values
|
|
26
|
+
dtype: either int or float
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
label="",
|
|
32
|
+
value=None,
|
|
33
|
+
min=None,
|
|
34
|
+
max=None,
|
|
35
|
+
step=1,
|
|
36
|
+
dtype=None,
|
|
37
|
+
):
|
|
38
|
+
"""Slider class.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
label: The displayed label in the UI
|
|
42
|
+
value: The initial value of the slider
|
|
43
|
+
min: The minimum possible value of the slider
|
|
44
|
+
max: The maximum possible value of the slider
|
|
45
|
+
step: The step between min and max for a range of possible values
|
|
46
|
+
dtype: either int or float
|
|
47
|
+
"""
|
|
48
|
+
self.label = label
|
|
49
|
+
self.value = value
|
|
50
|
+
self.min = min
|
|
51
|
+
self.max = max
|
|
52
|
+
self.step = step
|
|
53
|
+
|
|
54
|
+
# Validate option type to make sure values are supplied properly
|
|
55
|
+
valid = not (self.value is None or self.min is None or self.max is None)
|
|
56
|
+
self.maybe_raise_error("slider", valid)
|
|
57
|
+
|
|
58
|
+
if dtype is None:
|
|
59
|
+
self.is_float_slider = self._check_values_are_float(value, min, max, step)
|
|
60
|
+
else:
|
|
61
|
+
self.is_float_slider = dtype is float
|
|
62
|
+
|
|
63
|
+
def _check_values_are_float(self, value, min, max, step):
|
|
64
|
+
return any(isinstance(n, float) for n in (value, min, max, step))
|
|
65
|
+
|
|
66
|
+
def get(self, attr): # noqa: D102
|
|
67
|
+
return getattr(self, attr)
|
mesa/experimental/__init__.py
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
|
-
"""Experimental
|
|
1
|
+
"""Experimental init."""
|
|
2
2
|
|
|
3
|
-
|
|
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.
|
|
3
|
+
from mesa.experimental import cell_space
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
devs: Discrete event simulation system for scheduling events at arbitrary times
|
|
10
|
-
mesa_signals: Reactive programming capabilities for tracking state changes
|
|
5
|
+
try:
|
|
6
|
+
from .solara_viz import JupyterViz, Slider, SolaraViz, make_text
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
from mesa.experimental import cell_space, devs, mesa_signals
|
|
19
|
-
|
|
20
|
-
__all__ = ["cell_space", "devs", "mesa_signals"]
|
|
8
|
+
__all__ = ["cell_space", "JupyterViz", "Slider", "SolaraViz", "make_text"]
|
|
9
|
+
except ImportError:
|
|
10
|
+
print(
|
|
11
|
+
"Could not import SolaraViz. If you need it, install with 'pip install --pre mesa[viz]'"
|
|
12
|
+
)
|
|
13
|
+
__all__ = ["cell_space"]
|
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
"""Cell spaces
|
|
1
|
+
"""Cell spaces.
|
|
2
2
|
|
|
3
|
-
Cell spaces
|
|
4
|
-
|
|
5
|
-
This enables more sophisticated environmental modeling and agent-environment interactions.
|
|
3
|
+
Cell spaces offer an alternative API for discrete spaces. It is experimental and under development. The API is more
|
|
4
|
+
expressive that the default grids available in `mesa.space`.
|
|
6
5
|
|
|
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.
|
|
16
6
|
"""
|
|
17
7
|
|
|
18
8
|
from mesa.experimental.cell_space.cell import Cell
|
|
@@ -30,21 +20,19 @@ from mesa.experimental.cell_space.grid import (
|
|
|
30
20
|
OrthogonalVonNeumannGrid,
|
|
31
21
|
)
|
|
32
22
|
from mesa.experimental.cell_space.network import Network
|
|
33
|
-
from mesa.experimental.cell_space.property_layer import PropertyLayer
|
|
34
23
|
from mesa.experimental.cell_space.voronoi import VoronoiGrid
|
|
35
24
|
|
|
36
25
|
__all__ = [
|
|
26
|
+
"CellCollection",
|
|
37
27
|
"Cell",
|
|
38
28
|
"CellAgent",
|
|
39
|
-
"
|
|
40
|
-
"DiscreteSpace",
|
|
29
|
+
"Grid2DMovingAgent",
|
|
41
30
|
"FixedAgent",
|
|
31
|
+
"DiscreteSpace",
|
|
42
32
|
"Grid",
|
|
43
|
-
"Grid2DMovingAgent",
|
|
44
33
|
"HexGrid",
|
|
45
|
-
"Network",
|
|
46
34
|
"OrthogonalMooreGrid",
|
|
47
35
|
"OrthogonalVonNeumannGrid",
|
|
48
|
-
"
|
|
36
|
+
"Network",
|
|
49
37
|
"VoronoiGrid",
|
|
50
38
|
]
|
|
@@ -1,25 +1,15 @@
|
|
|
1
|
-
"""
|
|
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
|
-
"""
|
|
1
|
+
"""The Cell in a cell space."""
|
|
14
2
|
|
|
15
3
|
from __future__ import annotations
|
|
16
4
|
|
|
5
|
+
from collections.abc import Callable
|
|
17
6
|
from functools import cache, cached_property
|
|
18
7
|
from random import Random
|
|
19
|
-
from typing import TYPE_CHECKING
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
20
9
|
|
|
21
10
|
from mesa.experimental.cell_space.cell_agent import CellAgent
|
|
22
11
|
from mesa.experimental.cell_space.cell_collection import CellCollection
|
|
12
|
+
from mesa.space import PropertyLayer
|
|
23
13
|
|
|
24
14
|
if TYPE_CHECKING:
|
|
25
15
|
from mesa.agent import Agent
|
|
@@ -34,20 +24,31 @@ class Cell:
|
|
|
34
24
|
coordinate (Tuple[int, int]) : the position of the cell in the discrete space
|
|
35
25
|
agents (List[Agent]): the agents occupying the cell
|
|
36
26
|
capacity (int): the maximum number of agents that can simultaneously occupy the cell
|
|
27
|
+
properties (dict[str, Any]): the properties of the cell
|
|
37
28
|
random (Random): the random number generator
|
|
38
29
|
|
|
39
30
|
"""
|
|
40
31
|
|
|
41
32
|
__slots__ = [
|
|
42
|
-
"
|
|
33
|
+
"coordinate",
|
|
34
|
+
"connections",
|
|
43
35
|
"agents",
|
|
44
36
|
"capacity",
|
|
45
|
-
"connections",
|
|
46
|
-
"coordinate",
|
|
47
37
|
"properties",
|
|
48
38
|
"random",
|
|
39
|
+
"_mesa_property_layers",
|
|
40
|
+
"__dict__",
|
|
49
41
|
]
|
|
50
42
|
|
|
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
|
+
|
|
51
52
|
def __init__(
|
|
52
53
|
self,
|
|
53
54
|
coordinate: Coordinate,
|
|
@@ -69,10 +70,9 @@ class Cell:
|
|
|
69
70
|
Agent
|
|
70
71
|
] = [] # TODO:: change to AgentSet or weakrefs? (neither is very performant, )
|
|
71
72
|
self.capacity: int | None = capacity
|
|
72
|
-
self.properties: dict[
|
|
73
|
-
Coordinate, object
|
|
74
|
-
] = {} # fixme still used by voronoi mesh
|
|
73
|
+
self.properties: dict[Coordinate, object] = {}
|
|
75
74
|
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,7 +105,6 @@ class Cell:
|
|
|
105
105
|
|
|
106
106
|
"""
|
|
107
107
|
n = len(self.agents)
|
|
108
|
-
self.empty = False
|
|
109
108
|
|
|
110
109
|
if self.capacity and n >= self.capacity:
|
|
111
110
|
raise Exception(
|
|
@@ -122,7 +121,6 @@ class Cell:
|
|
|
122
121
|
|
|
123
122
|
"""
|
|
124
123
|
self.agents.remove(agent)
|
|
125
|
-
self.empty = self.is_empty
|
|
126
124
|
|
|
127
125
|
@property
|
|
128
126
|
def is_empty(self) -> bool:
|
|
@@ -197,6 +195,23 @@ class Cell:
|
|
|
197
195
|
neighborhood.pop(self, None)
|
|
198
196
|
return neighborhood
|
|
199
197
|
|
|
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
|
+
|
|
200
215
|
def __getstate__(self):
|
|
201
216
|
"""Return state of the Cell with connections set to empty."""
|
|
202
217
|
# fixme, once we shift to 3.11, replace this with super. __getstate__
|
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
"""
|
|
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
|
-
"""
|
|
1
|
+
"""An agent with movement methods for cell spaces."""
|
|
13
2
|
|
|
14
3
|
from __future__ import annotations
|
|
15
4
|
|
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
"""
|
|
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
|
-
"""
|
|
1
|
+
"""CellCollection class."""
|
|
15
2
|
|
|
16
3
|
from __future__ import annotations
|
|
17
4
|
|
|
@@ -61,10 +48,8 @@ class CellCollection(Generic[T]):
|
|
|
61
48
|
else:
|
|
62
49
|
self._cells = {cell: cell.agents for cell in cells}
|
|
63
50
|
|
|
64
|
-
#
|
|
65
|
-
self._capacity: int
|
|
66
|
-
next(iter(self._cells.keys())).capacity if self._cells else None
|
|
67
|
-
)
|
|
51
|
+
#
|
|
52
|
+
self._capacity: int = next(iter(self._cells.keys())).capacity
|
|
68
53
|
|
|
69
54
|
if random is None:
|
|
70
55
|
warnings.warn(
|