Mesa 3.1.0.dev0__py3-none-any.whl → 3.1.2__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 +48 -0
- 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/agents.py +2 -1
- mesa/examples/advanced/pd_grid/analysis.ipynb +44 -89
- mesa/examples/advanced/pd_grid/app.py +5 -0
- mesa/examples/advanced/pd_grid/model.py +3 -5
- mesa/examples/advanced/sugarscape_g1mt/agents.py +12 -65
- mesa/examples/advanced/sugarscape_g1mt/app.py +24 -19
- mesa/examples/advanced/sugarscape_g1mt/model.py +45 -52
- mesa/examples/advanced/wolf_sheep/agents.py +36 -2
- mesa/examples/advanced/wolf_sheep/model.py +17 -16
- 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/agents.py +11 -5
- mesa/examples/basic/schelling/analysis.ipynb +42 -36
- mesa/examples/basic/schelling/app.py +6 -1
- mesa/examples/basic/schelling/model.py +3 -3
- 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 +18 -3
- 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 -23
- mesa/visualization/__init__.py +2 -2
- mesa/visualization/mpl_space_drawing.py +8 -6
- mesa/visualization/solara_viz.py +49 -11
- {mesa-3.1.0.dev0.dist-info → mesa-3.1.2.dist-info}/METADATA +4 -2
- mesa-3.1.2.dist-info/RECORD +94 -0
- {mesa-3.1.0.dev0.dist-info → mesa-3.1.2.dist-info}/WHEEL +1 -1
- 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-3.1.0.dev0.dist-info/RECORD +0 -94
- {mesa-3.1.0.dev0.dist-info → mesa-3.1.2.dist-info}/entry_points.txt +0 -0
- {mesa-3.1.0.dev0.dist-info → mesa-3.1.2.dist-info}/licenses/LICENSE +0 -0
- {mesa-3.1.0.dev0.dist-info → mesa-3.1.2.dist-info}/licenses/NOTICE +0 -0
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"cell_type": "code",
|
|
20
|
+
"execution_count": null,
|
|
20
21
|
"metadata": {},
|
|
22
|
+
"outputs": [],
|
|
21
23
|
"source": [
|
|
22
24
|
"import matplotlib.pyplot as plt\n",
|
|
23
25
|
"import pandas as pd\n",
|
|
@@ -25,9 +27,7 @@
|
|
|
25
27
|
"%matplotlib inline\n",
|
|
26
28
|
"\n",
|
|
27
29
|
"from model import Schelling"
|
|
28
|
-
]
|
|
29
|
-
"outputs": [],
|
|
30
|
-
"execution_count": null
|
|
30
|
+
]
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"cell_type": "markdown",
|
|
@@ -38,10 +38,14 @@
|
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
"cell_type": "code",
|
|
41
|
+
"execution_count": null,
|
|
41
42
|
"metadata": {},
|
|
42
|
-
"source": "model = Schelling(height=10, width=10, homophily=3, density=0.8, minority_pc=0.2)",
|
|
43
43
|
"outputs": [],
|
|
44
|
-
"
|
|
44
|
+
"source": [
|
|
45
|
+
"schelling_model = Schelling(\n",
|
|
46
|
+
" height=10, width=10, homophily=3, density=0.8, minority_pc=0.2\n",
|
|
47
|
+
")"
|
|
48
|
+
]
|
|
45
49
|
},
|
|
46
50
|
{
|
|
47
51
|
"cell_type": "markdown",
|
|
@@ -52,14 +56,14 @@
|
|
|
52
56
|
},
|
|
53
57
|
{
|
|
54
58
|
"cell_type": "code",
|
|
59
|
+
"execution_count": null,
|
|
55
60
|
"metadata": {},
|
|
56
|
-
"source": [
|
|
57
|
-
"while model.running and model.steps < 100:\n",
|
|
58
|
-
" model.step()\n",
|
|
59
|
-
"print(model.steps) # Show how many steps have actually run"
|
|
60
|
-
],
|
|
61
61
|
"outputs": [],
|
|
62
|
-
"
|
|
62
|
+
"source": [
|
|
63
|
+
"while schelling_model.running and schelling_model.steps < 100:\n",
|
|
64
|
+
" schelling_model.step()\n",
|
|
65
|
+
"print(schelling_model.steps) # Show how many steps have actually run"
|
|
66
|
+
]
|
|
63
67
|
},
|
|
64
68
|
{
|
|
65
69
|
"cell_type": "markdown",
|
|
@@ -70,21 +74,21 @@
|
|
|
70
74
|
},
|
|
71
75
|
{
|
|
72
76
|
"cell_type": "code",
|
|
77
|
+
"execution_count": null,
|
|
73
78
|
"metadata": {},
|
|
74
|
-
"source": [
|
|
75
|
-
"model_out = model.datacollector.get_model_vars_dataframe()"
|
|
76
|
-
],
|
|
77
79
|
"outputs": [],
|
|
78
|
-
"
|
|
80
|
+
"source": [
|
|
81
|
+
"model_out = schelling_model.datacollector.get_model_vars_dataframe()"
|
|
82
|
+
]
|
|
79
83
|
},
|
|
80
84
|
{
|
|
81
85
|
"cell_type": "code",
|
|
86
|
+
"execution_count": null,
|
|
82
87
|
"metadata": {},
|
|
88
|
+
"outputs": [],
|
|
83
89
|
"source": [
|
|
84
90
|
"model_out.head()"
|
|
85
|
-
]
|
|
86
|
-
"outputs": [],
|
|
87
|
-
"execution_count": null
|
|
91
|
+
]
|
|
88
92
|
},
|
|
89
93
|
{
|
|
90
94
|
"cell_type": "markdown",
|
|
@@ -95,12 +99,12 @@
|
|
|
95
99
|
},
|
|
96
100
|
{
|
|
97
101
|
"cell_type": "code",
|
|
102
|
+
"execution_count": null,
|
|
98
103
|
"metadata": {},
|
|
104
|
+
"outputs": [],
|
|
99
105
|
"source": [
|
|
100
106
|
"model_out.happy.plot()"
|
|
101
|
-
]
|
|
102
|
-
"outputs": [],
|
|
103
|
-
"execution_count": null
|
|
107
|
+
]
|
|
104
108
|
},
|
|
105
109
|
{
|
|
106
110
|
"cell_type": "markdown",
|
|
@@ -115,10 +119,12 @@
|
|
|
115
119
|
},
|
|
116
120
|
{
|
|
117
121
|
"cell_type": "code",
|
|
122
|
+
"execution_count": null,
|
|
118
123
|
"metadata": {},
|
|
119
|
-
"source": "from mesa.batchrunner import batch_run",
|
|
120
124
|
"outputs": [],
|
|
121
|
-
"
|
|
125
|
+
"source": [
|
|
126
|
+
"from mesa.batchrunner import batch_run"
|
|
127
|
+
]
|
|
122
128
|
},
|
|
123
129
|
{
|
|
124
130
|
"cell_type": "markdown",
|
|
@@ -129,18 +135,20 @@
|
|
|
129
135
|
},
|
|
130
136
|
{
|
|
131
137
|
"cell_type": "code",
|
|
138
|
+
"execution_count": null,
|
|
132
139
|
"metadata": {},
|
|
140
|
+
"outputs": [],
|
|
133
141
|
"source": [
|
|
134
142
|
"fixed_params = {\"height\": 10, \"width\": 10, \"density\": 0.8, \"minority_pc\": 0.2}\n",
|
|
135
143
|
"variable_parms = {\"homophily\": range(1, 9)}\n",
|
|
136
144
|
"all_params = fixed_params | variable_parms"
|
|
137
|
-
]
|
|
138
|
-
"outputs": [],
|
|
139
|
-
"execution_count": null
|
|
145
|
+
]
|
|
140
146
|
},
|
|
141
147
|
{
|
|
142
148
|
"cell_type": "code",
|
|
149
|
+
"execution_count": null,
|
|
143
150
|
"metadata": {},
|
|
151
|
+
"outputs": [],
|
|
144
152
|
"source": [
|
|
145
153
|
"results = batch_run(\n",
|
|
146
154
|
" Schelling,\n",
|
|
@@ -148,23 +156,23 @@
|
|
|
148
156
|
" iterations=10,\n",
|
|
149
157
|
" max_steps=200,\n",
|
|
150
158
|
")"
|
|
151
|
-
]
|
|
152
|
-
"outputs": [],
|
|
153
|
-
"execution_count": null
|
|
159
|
+
]
|
|
154
160
|
},
|
|
155
161
|
{
|
|
156
|
-
"metadata": {},
|
|
157
162
|
"cell_type": "code",
|
|
163
|
+
"execution_count": null,
|
|
164
|
+
"metadata": {},
|
|
165
|
+
"outputs": [],
|
|
158
166
|
"source": [
|
|
159
167
|
"df = pd.DataFrame(results)\n",
|
|
160
168
|
"df"
|
|
161
|
-
]
|
|
162
|
-
"outputs": [],
|
|
163
|
-
"execution_count": null
|
|
169
|
+
]
|
|
164
170
|
},
|
|
165
171
|
{
|
|
166
172
|
"cell_type": "code",
|
|
173
|
+
"execution_count": null,
|
|
167
174
|
"metadata": {},
|
|
175
|
+
"outputs": [],
|
|
168
176
|
"source": [
|
|
169
177
|
"plt.scatter(df.homophily, df.happy)\n",
|
|
170
178
|
"plt.xlabel(\"Homophily\")\n",
|
|
@@ -172,9 +180,7 @@
|
|
|
172
180
|
"plt.grid()\n",
|
|
173
181
|
"plt.title(\"Effect of Homophily on segregation\")\n",
|
|
174
182
|
"plt.show()"
|
|
175
|
-
]
|
|
176
|
-
"outputs": [],
|
|
177
|
-
"execution_count": null
|
|
183
|
+
]
|
|
178
184
|
}
|
|
179
185
|
],
|
|
180
186
|
"metadata": {
|
|
@@ -19,9 +19,14 @@ 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
|
-
"homophily": Slider("Homophily",
|
|
29
|
+
"homophily": Slider("Homophily", 0.4, 0.0, 1.0, 0.125),
|
|
25
30
|
"width": 20,
|
|
26
31
|
"height": 20,
|
|
27
32
|
}
|
|
@@ -9,11 +9,11 @@ class Schelling(Model):
|
|
|
9
9
|
|
|
10
10
|
def __init__(
|
|
11
11
|
self,
|
|
12
|
-
height: int =
|
|
13
|
-
width: int =
|
|
12
|
+
height: int = 20,
|
|
13
|
+
width: int = 20,
|
|
14
14
|
density: float = 0.8,
|
|
15
15
|
minority_pc: float = 0.5,
|
|
16
|
-
homophily:
|
|
16
|
+
homophily: float = 0.4,
|
|
17
17
|
radius: int = 1,
|
|
18
18
|
seed=None,
|
|
19
19
|
):
|
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
|
|
|
@@ -48,8 +61,10 @@ class CellCollection(Generic[T]):
|
|
|
48
61
|
else:
|
|
49
62
|
self._cells = {cell: cell.agents for cell in cells}
|
|
50
63
|
|
|
51
|
-
#
|
|
52
|
-
self._capacity: int =
|
|
64
|
+
# Get capacity from first cell if collection is not empty
|
|
65
|
+
self._capacity: int | None = (
|
|
66
|
+
next(iter(self._cells.keys())).capacity if self._cells else None
|
|
67
|
+
)
|
|
53
68
|
|
|
54
69
|
if random is None:
|
|
55
70
|
warnings.warn(
|
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Base class for building cell-based spatial environments.
|
|
2
|
+
|
|
3
|
+
DiscreteSpace provides the core functionality needed by all cell-based spaces:
|
|
4
|
+
- Cell creation and tracking
|
|
5
|
+
- Agent-cell relationship management
|
|
6
|
+
- Property layer support
|
|
7
|
+
- Random selection capabilities
|
|
8
|
+
- Capacity management
|
|
9
|
+
|
|
10
|
+
This serves as the foundation for specific space implementations like grids
|
|
11
|
+
and networks, ensuring consistent behavior and shared functionality across
|
|
12
|
+
different space types. All concrete cell space implementations (grids, networks, etc.)
|
|
13
|
+
inherit from this class.
|
|
14
|
+
"""
|
|
2
15
|
|
|
3
16
|
from __future__ import annotations
|
|
4
17
|
|
|
5
18
|
import warnings
|
|
6
|
-
from collections.abc import Callable
|
|
7
19
|
from functools import cached_property
|
|
8
20
|
from random import Random
|
|
9
|
-
from typing import
|
|
21
|
+
from typing import Generic, TypeVar
|
|
10
22
|
|
|
11
23
|
from mesa.agent import AgentSet
|
|
12
24
|
from mesa.experimental.cell_space.cell import Cell
|
|
13
25
|
from mesa.experimental.cell_space.cell_collection import CellCollection
|
|
14
|
-
from mesa.space import PropertyLayer
|
|
15
26
|
|
|
16
27
|
T = TypeVar("T", bound=Cell)
|
|
17
28
|
|
|
@@ -61,8 +72,6 @@ class DiscreteSpace(Generic[T]):
|
|
|
61
72
|
self.cell_klass = cell_klass
|
|
62
73
|
|
|
63
74
|
self._empties: dict[tuple[int, ...], None] = {}
|
|
64
|
-
self._empties_initialized = False
|
|
65
|
-
self.property_layers: dict[str, PropertyLayer] = {}
|
|
66
75
|
|
|
67
76
|
@property
|
|
68
77
|
def cutoff_empties(self): # noqa
|
|
@@ -98,64 +107,6 @@ class DiscreteSpace(Generic[T]):
|
|
|
98
107
|
"""Select random empty cell."""
|
|
99
108
|
return self.random.choice(list(self.empties))
|
|
100
109
|
|
|
101
|
-
# PropertyLayer methods
|
|
102
|
-
def add_property_layer(
|
|
103
|
-
self, property_layer: PropertyLayer, add_to_cells: bool = True
|
|
104
|
-
):
|
|
105
|
-
"""Add a property layer to the grid.
|
|
106
|
-
|
|
107
|
-
Args:
|
|
108
|
-
property_layer: the property layer to add
|
|
109
|
-
add_to_cells: whether to add the property layer to all cells (default: True)
|
|
110
|
-
"""
|
|
111
|
-
if property_layer.name in self.property_layers:
|
|
112
|
-
raise ValueError(f"Property layer {property_layer.name} already exists.")
|
|
113
|
-
self.property_layers[property_layer.name] = property_layer
|
|
114
|
-
if add_to_cells:
|
|
115
|
-
for cell in self._cells.values():
|
|
116
|
-
cell._mesa_property_layers[property_layer.name] = property_layer
|
|
117
|
-
|
|
118
|
-
def remove_property_layer(self, property_name: str, remove_from_cells: bool = True):
|
|
119
|
-
"""Remove a property layer from the grid.
|
|
120
|
-
|
|
121
|
-
Args:
|
|
122
|
-
property_name: the name of the property layer to remove
|
|
123
|
-
remove_from_cells: whether to remove the property layer from all cells (default: True)
|
|
124
|
-
"""
|
|
125
|
-
del self.property_layers[property_name]
|
|
126
|
-
if remove_from_cells:
|
|
127
|
-
for cell in self._cells.values():
|
|
128
|
-
del cell._mesa_property_layers[property_name]
|
|
129
|
-
|
|
130
|
-
def set_property(
|
|
131
|
-
self, property_name: str, value, condition: Callable[[T], bool] | None = None
|
|
132
|
-
):
|
|
133
|
-
"""Set the value of a property for all cells in the grid.
|
|
134
|
-
|
|
135
|
-
Args:
|
|
136
|
-
property_name: the name of the property to set
|
|
137
|
-
value: the value to set
|
|
138
|
-
condition: a function that takes a cell and returns a boolean
|
|
139
|
-
"""
|
|
140
|
-
self.property_layers[property_name].set_cells(value, condition)
|
|
141
|
-
|
|
142
|
-
def modify_properties(
|
|
143
|
-
self,
|
|
144
|
-
property_name: str,
|
|
145
|
-
operation: Callable,
|
|
146
|
-
value: Any = None,
|
|
147
|
-
condition: Callable[[T], bool] | None = None,
|
|
148
|
-
):
|
|
149
|
-
"""Modify the values of a specific property for all cells in the grid.
|
|
150
|
-
|
|
151
|
-
Args:
|
|
152
|
-
property_name: the name of the property to modify
|
|
153
|
-
operation: the operation to perform
|
|
154
|
-
value: the value to use in the operation
|
|
155
|
-
condition: a function that takes a cell and returns a boolean (used to filter cells)
|
|
156
|
-
"""
|
|
157
|
-
self.property_layers[property_name].modify_cells(operation, value, condition)
|
|
158
|
-
|
|
159
110
|
def __setstate__(self, state):
|
|
160
111
|
"""Set the state of the discrete space and rebuild the connections."""
|
|
161
112
|
self.__dict__ = state
|