Mesa 3.1.5__py3-none-any.whl → 3.2.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.
- mesa/__init__.py +3 -1
- mesa/agent.py +26 -9
- mesa/discrete_space/__init__.py +50 -0
- mesa/{experimental/cell_space → discrete_space}/cell.py +29 -10
- mesa/{experimental/cell_space → discrete_space}/cell_agent.py +1 -1
- mesa/{experimental/cell_space → discrete_space}/cell_collection.py +3 -3
- mesa/{experimental/cell_space → discrete_space}/discrete_space.py +65 -3
- mesa/{experimental/cell_space → discrete_space}/grid.py +2 -2
- mesa/{experimental/cell_space → discrete_space}/network.py +22 -2
- mesa/{experimental/cell_space → discrete_space}/property_layer.py +1 -10
- mesa/{experimental/cell_space → discrete_space}/voronoi.py +2 -2
- mesa/examples/README.md +1 -1
- mesa/examples/__init__.py +2 -0
- mesa/examples/advanced/alliance_formation/Readme.md +50 -0
- mesa/examples/advanced/alliance_formation/__init__ .py +0 -0
- mesa/examples/advanced/alliance_formation/agents.py +20 -0
- mesa/examples/advanced/alliance_formation/app.py +71 -0
- mesa/examples/advanced/alliance_formation/model.py +184 -0
- mesa/examples/advanced/epstein_civil_violence/agents.py +1 -1
- mesa/examples/advanced/epstein_civil_violence/model.py +1 -1
- mesa/examples/advanced/pd_grid/Readme.md +4 -6
- mesa/examples/advanced/pd_grid/agents.py +1 -1
- mesa/examples/advanced/pd_grid/model.py +1 -1
- mesa/examples/advanced/sugarscape_g1mt/Readme.md +4 -5
- mesa/examples/advanced/sugarscape_g1mt/agents.py +1 -1
- mesa/examples/advanced/sugarscape_g1mt/model.py +2 -2
- mesa/examples/advanced/wolf_sheep/Readme.md +2 -17
- mesa/examples/advanced/wolf_sheep/agents.py +1 -1
- mesa/examples/advanced/wolf_sheep/app.py +2 -1
- mesa/examples/advanced/wolf_sheep/model.py +1 -1
- mesa/examples/basic/boid_flockers/Readme.md +6 -1
- mesa/examples/basic/boid_flockers/agents.py +1 -0
- mesa/examples/basic/boid_flockers/app.py +17 -2
- mesa/examples/basic/boid_flockers/model.py +12 -0
- mesa/examples/basic/boltzmann_wealth_model/Readme.md +2 -12
- mesa/examples/basic/boltzmann_wealth_model/agents.py +6 -11
- mesa/examples/basic/boltzmann_wealth_model/app.py +2 -2
- mesa/examples/basic/boltzmann_wealth_model/model.py +7 -11
- mesa/examples/basic/conways_game_of_life/Readme.md +1 -9
- mesa/examples/basic/conways_game_of_life/agents.py +13 -5
- mesa/examples/basic/conways_game_of_life/model.py +10 -7
- mesa/examples/basic/schelling/Readme.md +0 -8
- mesa/examples/basic/schelling/agents.py +13 -8
- mesa/examples/basic/schelling/model.py +6 -9
- mesa/examples/basic/virus_on_network/Readme.md +0 -4
- mesa/examples/basic/virus_on_network/agents.py +13 -17
- mesa/examples/basic/virus_on_network/model.py +20 -24
- mesa/experimental/__init__.py +2 -2
- mesa/experimental/cell_space/__init__.py +18 -8
- mesa/experimental/meta_agents/__init__.py +25 -0
- mesa/experimental/meta_agents/meta_agent.py +387 -0
- mesa/model.py +3 -3
- mesa/space.py +1 -12
- mesa/visualization/__init__.py +2 -0
- mesa/visualization/command_console.py +482 -0
- mesa/visualization/components/altair_components.py +276 -16
- mesa/visualization/mpl_space_drawing.py +17 -9
- mesa/visualization/solara_viz.py +150 -21
- {mesa-3.1.5.dist-info → mesa-3.2.0.dist-info}/METADATA +12 -8
- mesa-3.2.0.dist-info/RECORD +105 -0
- mesa-3.1.5.dist-info/RECORD +0 -96
- {mesa-3.1.5.dist-info → mesa-3.2.0.dist-info}/WHEEL +0 -0
- {mesa-3.1.5.dist-info → mesa-3.2.0.dist-info}/licenses/LICENSE +0 -0
- {mesa-3.1.5.dist-info → mesa-3.2.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
"""Implementation of Mesa's meta agent capability.
|
|
2
|
+
|
|
3
|
+
Overview: Complex systems often have multiple levels of components. An
|
|
4
|
+
organization is not one entity, but is made of departments, sub-departments,
|
|
5
|
+
and people. A person is not a single entity, but it is made of micro biomes,
|
|
6
|
+
organs and cells. A city is not a single entity, but it is made of districts,
|
|
7
|
+
neighborhoods, buildings, and people. A forest comprises an ecosystem of
|
|
8
|
+
trees, plants, animals, and microorganisms.
|
|
9
|
+
|
|
10
|
+
This reality is the motivation for meta-agents. It allows users to represent
|
|
11
|
+
these multiple levels, where each level can have agents with constituting_agents.
|
|
12
|
+
|
|
13
|
+
To demonstrate meta-agents capability there are two examples:
|
|
14
|
+
1 - Alliance formation which shows emergent meta-agent formation in
|
|
15
|
+
advanced examples:
|
|
16
|
+
https://github.com/projectmesa/mesa/tree/main/mesa/examples/advanced/alliance_formation
|
|
17
|
+
2 - Warehouse model in the Mesa example's repository
|
|
18
|
+
https://github.com/projectmesa/mesa-examples/tree/main/examples/warehouse
|
|
19
|
+
|
|
20
|
+
To accomplish this the MetaAgent module is as follows:
|
|
21
|
+
|
|
22
|
+
This contains four helper functions and a MetaAgent class that can be used to
|
|
23
|
+
create agents that contain other agents as components.
|
|
24
|
+
|
|
25
|
+
Helper methods:
|
|
26
|
+
1 - find_combinations: Find combinations of agents to create a meta-agent
|
|
27
|
+
constituting_set.
|
|
28
|
+
2- evaluate_combination: Evaluate combinations of agents by some user based
|
|
29
|
+
criteria to determine if it should be a constituting_set of agents.
|
|
30
|
+
3- extract_class: Helper function for create_meta-agent. Extracts the types of
|
|
31
|
+
agent being created to create a new instance of that agent type.
|
|
32
|
+
4- create_meta_agent: Create a new meta-agent class and instantiate
|
|
33
|
+
agents in that class.
|
|
34
|
+
|
|
35
|
+
Meta-Agent class (MetaAgent): An agent that contains other agents
|
|
36
|
+
as components.
|
|
37
|
+
|
|
38
|
+
.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
import itertools
|
|
42
|
+
from collections.abc import Callable, Iterable
|
|
43
|
+
from types import MethodType
|
|
44
|
+
from typing import Any
|
|
45
|
+
|
|
46
|
+
from mesa.agent import Agent, AgentSet
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def evaluate_combination(
|
|
50
|
+
candidate_group: tuple[Agent, ...],
|
|
51
|
+
model,
|
|
52
|
+
evaluation_func: Callable[[AgentSet], float] | None,
|
|
53
|
+
) -> tuple[AgentSet, float] | None:
|
|
54
|
+
"""Evaluate a combination of agents.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
candidate_group (Tuple[Agent, ...]): The group of agents to evaluate.
|
|
58
|
+
model: The model instance.
|
|
59
|
+
evaluation_func (Optional[Callable[[AgentSet], float]]): The function
|
|
60
|
+
to evaluate the group.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Optional[Tuple[AgentSet, float]]: The evaluated group and its value,
|
|
64
|
+
or None.
|
|
65
|
+
"""
|
|
66
|
+
group_set = AgentSet(candidate_group, random=model.random)
|
|
67
|
+
if evaluation_func:
|
|
68
|
+
value = evaluation_func(group_set)
|
|
69
|
+
return group_set, value
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def find_combinations(
|
|
74
|
+
model,
|
|
75
|
+
group: AgentSet,
|
|
76
|
+
size: int | tuple[int, int] = (2, 5),
|
|
77
|
+
evaluation_func: Callable[[AgentSet], float] | None = None,
|
|
78
|
+
filter_func: Callable[[list[tuple[AgentSet, float]]], list[tuple[AgentSet, float]]]
|
|
79
|
+
| None = None,
|
|
80
|
+
) -> list[tuple[AgentSet, float]]:
|
|
81
|
+
"""Find valuable combinations of agents in this set.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
model: The model instance.
|
|
85
|
+
group (AgentSet): The set of agents to find combinations in.
|
|
86
|
+
size (Union[int, Tuple[int, int]], optional): The size or range of
|
|
87
|
+
sizes for combinations. Defaults to (2, 5).
|
|
88
|
+
evaluation_func (Optional[Callable[[AgentSet], float]], optional): The
|
|
89
|
+
function to evaluate combinations. Defaults to None.
|
|
90
|
+
filter_func (Optional[Callable[[List[Tuple[AgentSet, float]]]): Allows
|
|
91
|
+
the user to specify how agents are filtered to form groups.
|
|
92
|
+
Defaults to None.
|
|
93
|
+
List[Tuple[AgentSet, float]]]], optional): The function to filter
|
|
94
|
+
combinations. Defaults to None.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
List[Tuple[AgentSet, float]]: The list of valuable combinations, in
|
|
98
|
+
a tuple first agentset of valuable combination and then the value of
|
|
99
|
+
the combination.
|
|
100
|
+
"""
|
|
101
|
+
combinations = []
|
|
102
|
+
# Allow one size or range of sizes to be passed
|
|
103
|
+
size_range = (size, size + 1) if isinstance(size, int) else size
|
|
104
|
+
|
|
105
|
+
for candidate_group in itertools.chain.from_iterable(
|
|
106
|
+
itertools.combinations(group, size) for size in range(*size_range)
|
|
107
|
+
):
|
|
108
|
+
group_set, result = evaluate_combination(
|
|
109
|
+
candidate_group, model, evaluation_func
|
|
110
|
+
)
|
|
111
|
+
if result:
|
|
112
|
+
combinations.append((group_set, result))
|
|
113
|
+
|
|
114
|
+
if len(combinations) > 0 and filter_func:
|
|
115
|
+
filtered_combinations = filter_func(combinations)
|
|
116
|
+
return filtered_combinations
|
|
117
|
+
|
|
118
|
+
return combinations
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def extract_class(agents_by_type: dict, new_agent_class: object) -> type[Agent] | None:
|
|
122
|
+
"""Helper function for create_meta_agents extracts the types of agents.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
agents_by_type (dict): The dictionary of agents by type.
|
|
126
|
+
new_agent_class (str): The name of the agent class to be created
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
type(Agent) if agent type exists
|
|
130
|
+
None otherwise
|
|
131
|
+
"""
|
|
132
|
+
agent_type_names = {}
|
|
133
|
+
for agent in agents_by_type:
|
|
134
|
+
agent_type_names[agent.__name__] = agent
|
|
135
|
+
|
|
136
|
+
if new_agent_class in agent_type_names:
|
|
137
|
+
return type(agents_by_type[agent_type_names[new_agent_class]][0])
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def create_meta_agent(
|
|
142
|
+
model: Any,
|
|
143
|
+
new_agent_class: str,
|
|
144
|
+
agents: Iterable[Any],
|
|
145
|
+
mesa_agent_type: type[Agent] | None,
|
|
146
|
+
meta_attributes: dict[str, Any] | None = None,
|
|
147
|
+
meta_methods: dict[str, Callable] | None = None,
|
|
148
|
+
assume_constituting_agent_methods: bool = False,
|
|
149
|
+
assume_constituting_agent_attributes: bool = False,
|
|
150
|
+
) -> Any | None:
|
|
151
|
+
"""Create a new meta-agent class and instantiate agents.
|
|
152
|
+
|
|
153
|
+
Parameters:
|
|
154
|
+
model (Any): The model instance.
|
|
155
|
+
new_agent_class (str): The name of the new meta-agent class.
|
|
156
|
+
agents (Iterable[Any]): The agents to be included in the meta-agent.
|
|
157
|
+
meta_attributes (Dict[str, Any]): Attributes to be added to the meta-agent.
|
|
158
|
+
meta_methods (Dict[str, Callable]): Methods to be added to the meta-agent.
|
|
159
|
+
assume_constituting_agent_methods (bool): Whether to assume methods from
|
|
160
|
+
constituting_-agents as meta_agent methods.
|
|
161
|
+
assume_constituting_agent_attributes (bool): Whether to retain attributes
|
|
162
|
+
from constituting_-agents.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
- MetaAgent Instance
|
|
166
|
+
"""
|
|
167
|
+
# Convert agents to set to ensure uniqueness
|
|
168
|
+
agents = set(agents)
|
|
169
|
+
|
|
170
|
+
# Ensure there is at least one agent base class
|
|
171
|
+
if not mesa_agent_type:
|
|
172
|
+
mesa_agent_type = (Agent,)
|
|
173
|
+
elif not isinstance(mesa_agent_type, tuple):
|
|
174
|
+
mesa_agent_type = (mesa_agent_type,)
|
|
175
|
+
|
|
176
|
+
def add_methods(
|
|
177
|
+
meta_agent_instance: Any,
|
|
178
|
+
agents: Iterable[Any],
|
|
179
|
+
meta_methods: dict[str, Callable],
|
|
180
|
+
) -> None:
|
|
181
|
+
"""Add methods to the meta-agent instance.
|
|
182
|
+
|
|
183
|
+
Parameters:
|
|
184
|
+
meta_agent_instance (Any): The meta-agent instance.
|
|
185
|
+
agents (Iterable[Any]): The agents to derive methods from.
|
|
186
|
+
meta_methods (Dict[str, Callable]): methods to be added to the meta-agent.
|
|
187
|
+
"""
|
|
188
|
+
if assume_constituting_agent_methods:
|
|
189
|
+
agent_classes = {type(agent) for agent in agents}
|
|
190
|
+
if meta_methods is None:
|
|
191
|
+
# Initialize meta_methods if not provided
|
|
192
|
+
meta_methods = {}
|
|
193
|
+
for agent_class in agent_classes:
|
|
194
|
+
for name in agent_class.__dict__:
|
|
195
|
+
if callable(getattr(agent_class, name)) and not name.startswith(
|
|
196
|
+
"__"
|
|
197
|
+
):
|
|
198
|
+
original_method = getattr(agent_class, name)
|
|
199
|
+
meta_methods[name] = original_method
|
|
200
|
+
|
|
201
|
+
if meta_methods is not None:
|
|
202
|
+
for name, meth in meta_methods.items():
|
|
203
|
+
bound_method = MethodType(meth, meta_agent_instance)
|
|
204
|
+
setattr(meta_agent_instance, name, bound_method)
|
|
205
|
+
|
|
206
|
+
def add_attributes(
|
|
207
|
+
meta_agent_instance: Any, agents: Iterable[Any], meta_attributes: dict[str, Any]
|
|
208
|
+
) -> None:
|
|
209
|
+
"""Add attributes to the meta-agent instance.
|
|
210
|
+
|
|
211
|
+
Parameters:
|
|
212
|
+
meta_agent_instance (Any): The meta-agent instance.
|
|
213
|
+
agents (Iterable[Any]): The agents to derive attributes from.
|
|
214
|
+
meta_attributes (Dict[str, Any]): Attributes to be added to the
|
|
215
|
+
meta-agent.
|
|
216
|
+
"""
|
|
217
|
+
if assume_constituting_agent_attributes:
|
|
218
|
+
if meta_attributes is None:
|
|
219
|
+
# Initialize meta_attributes if not provided
|
|
220
|
+
meta_attributes = {}
|
|
221
|
+
for agent in agents:
|
|
222
|
+
for name, value in agent.__dict__.items():
|
|
223
|
+
if not callable(value):
|
|
224
|
+
meta_attributes[name] = value
|
|
225
|
+
|
|
226
|
+
if meta_attributes is not None:
|
|
227
|
+
for key, value in meta_attributes.items():
|
|
228
|
+
setattr(meta_agent_instance, key, value)
|
|
229
|
+
|
|
230
|
+
# Path 1 - Add agents to existing meta-agent
|
|
231
|
+
constituting_agents = [a for a in agents if hasattr(a, "meta_agent")]
|
|
232
|
+
if len(constituting_agents) > 0:
|
|
233
|
+
if len(constituting_agents) == 1:
|
|
234
|
+
add_attributes(constituting_agents[0].meta_agent, agents, meta_attributes)
|
|
235
|
+
add_methods(constituting_agents[0].meta_agent, agents, meta_methods)
|
|
236
|
+
constituting_agents[0].meta_agent.add_constituting_agents(agents)
|
|
237
|
+
|
|
238
|
+
return constituting_agents[0].meta_agent # Return the existing meta-agent
|
|
239
|
+
|
|
240
|
+
else:
|
|
241
|
+
constituting_agent = model.random.choice(constituting_agents)
|
|
242
|
+
agents = set(agents) - set(constituting_agents)
|
|
243
|
+
add_attributes(constituting_agent.meta_agent, agents, meta_attributes)
|
|
244
|
+
add_methods(constituting_agent.meta_agent, agents, meta_methods)
|
|
245
|
+
constituting_agent.meta_agent.add_constituting_agents(agents)
|
|
246
|
+
# TODO: Add way for user to specify how agents join meta-agent
|
|
247
|
+
# instead of random choice
|
|
248
|
+
return constituting_agent.meta_agent
|
|
249
|
+
|
|
250
|
+
else:
|
|
251
|
+
# Path 2 - Create a new instance of an existing meta-agent class
|
|
252
|
+
agent_class = extract_class(model.agents_by_type, new_agent_class)
|
|
253
|
+
|
|
254
|
+
if agent_class:
|
|
255
|
+
meta_agent_instance = agent_class(model, agents)
|
|
256
|
+
add_attributes(meta_agent_instance, agents, meta_attributes)
|
|
257
|
+
add_methods(meta_agent_instance, agents, meta_methods)
|
|
258
|
+
return meta_agent_instance
|
|
259
|
+
else:
|
|
260
|
+
# Path 3 - Create a new meta-agent class
|
|
261
|
+
meta_agent_class = type(
|
|
262
|
+
new_agent_class,
|
|
263
|
+
(MetaAgent, *mesa_agent_type), # Inherit Mesa Agent Classes
|
|
264
|
+
{
|
|
265
|
+
"unique_id": None,
|
|
266
|
+
"_constituting_set": None,
|
|
267
|
+
},
|
|
268
|
+
)
|
|
269
|
+
meta_agent_instance = meta_agent_class(model, agents)
|
|
270
|
+
add_attributes(meta_agent_instance, agents, meta_attributes)
|
|
271
|
+
add_methods(meta_agent_instance, agents, meta_methods)
|
|
272
|
+
return meta_agent_instance
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class MetaAgent(Agent):
|
|
276
|
+
"""A MetaAgent is an agent that contains other agents as components."""
|
|
277
|
+
|
|
278
|
+
def __init__(
|
|
279
|
+
self, model, agents: set[Agent] | None = None, name: str = "MetaAgent"
|
|
280
|
+
):
|
|
281
|
+
"""Create a new MetaAgent.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
model: The model instance.
|
|
285
|
+
agents (Optional[set[Agent]], optional): The set of agents to
|
|
286
|
+
include in the MetaAgent. Defaults to None.
|
|
287
|
+
name (str, optional): The name of the MetaAgent. Defaults to "MetaAgent".
|
|
288
|
+
"""
|
|
289
|
+
super().__init__(model)
|
|
290
|
+
self._constituting_set = AgentSet(agents or [], random=model.random)
|
|
291
|
+
self.name = name
|
|
292
|
+
|
|
293
|
+
# Add ref to meta_agent in constituting_agents
|
|
294
|
+
for agent in self._constituting_set:
|
|
295
|
+
agent.meta_agent = self # TODO: Make a set for meta_agents
|
|
296
|
+
|
|
297
|
+
def __len__(self) -> int:
|
|
298
|
+
"""Return the number of components."""
|
|
299
|
+
return len(self._constituting_set)
|
|
300
|
+
|
|
301
|
+
def __iter__(self):
|
|
302
|
+
"""Iterate over components."""
|
|
303
|
+
return iter(self._constituting_set)
|
|
304
|
+
|
|
305
|
+
def __contains__(self, agent: Agent) -> bool:
|
|
306
|
+
"""Check if an agent is a component."""
|
|
307
|
+
return agent in self._constituting_set
|
|
308
|
+
|
|
309
|
+
@property
|
|
310
|
+
def agents(self) -> AgentSet:
|
|
311
|
+
"""Get list of Meta-Agent constituting_agents."""
|
|
312
|
+
return self._constituting_set
|
|
313
|
+
|
|
314
|
+
@property
|
|
315
|
+
def constituting_agents_by_type(self) -> dict[type, list[Agent]]:
|
|
316
|
+
"""Get the constituting_agents grouped by type.
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
dict[type, list[Agent]]: A dictionary of constituting_agents grouped by type.
|
|
320
|
+
"""
|
|
321
|
+
constituting_agents_by_type = {}
|
|
322
|
+
for agent in self._constituting_set:
|
|
323
|
+
agent_type = type(agent)
|
|
324
|
+
if agent_type not in constituting_agents_by_type:
|
|
325
|
+
constituting_agents_by_type[agent_type] = []
|
|
326
|
+
constituting_agents_by_type[agent_type].append(agent)
|
|
327
|
+
return constituting_agents_by_type
|
|
328
|
+
|
|
329
|
+
@property
|
|
330
|
+
def constituting_agent_types(self) -> set[type]:
|
|
331
|
+
"""Get the types of all constituting_agents.
|
|
332
|
+
|
|
333
|
+
Returns:
|
|
334
|
+
set[type]: A set of unique types of the constituting_agents.
|
|
335
|
+
"""
|
|
336
|
+
return {type(agent) for agent in self._constituting_set}
|
|
337
|
+
|
|
338
|
+
def get_constituting_agent_instance(self, agent_type) -> set[type]:
|
|
339
|
+
"""Get the instance of a constituting_agent of the specified type.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
agent_type: The type of the constituting_agent to retrieve.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
The first instance of the specified constituting_agent type.
|
|
346
|
+
|
|
347
|
+
Raises:
|
|
348
|
+
ValueError: If no constituting_agent of the specified type is found.
|
|
349
|
+
"""
|
|
350
|
+
try:
|
|
351
|
+
return self.constituting_agents_by_type[agent_type][0]
|
|
352
|
+
except KeyError:
|
|
353
|
+
raise ValueError(
|
|
354
|
+
f"No constituting_agent of type {agent_type} found."
|
|
355
|
+
) from None
|
|
356
|
+
|
|
357
|
+
def add_constituting_agents(
|
|
358
|
+
self,
|
|
359
|
+
new_agents: set[Agent],
|
|
360
|
+
):
|
|
361
|
+
"""Add agents as components.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
new_agents (set[Agent]): The agents to add to MetaAgent constituting_set.
|
|
365
|
+
"""
|
|
366
|
+
for agent in new_agents:
|
|
367
|
+
self._constituting_set.add(agent)
|
|
368
|
+
agent.meta_agent = self # TODO: Make a set for meta_agents
|
|
369
|
+
self.model.register_agent(agent)
|
|
370
|
+
|
|
371
|
+
def remove_constituting_agents(self, remove_agents: set[Agent]):
|
|
372
|
+
"""Remove agents as components.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
remove_agents (set[Agent]): The agents to remove from MetaAgent.
|
|
376
|
+
"""
|
|
377
|
+
for agent in remove_agents:
|
|
378
|
+
self._constituting_set.discard(agent)
|
|
379
|
+
agent.meta_agent = None # TODO: Remove meta_agent from set
|
|
380
|
+
self.model.deregister_agent(agent)
|
|
381
|
+
|
|
382
|
+
def step(self):
|
|
383
|
+
"""Perform the agent's step.
|
|
384
|
+
|
|
385
|
+
Override this method to define the meta agent's behavior.
|
|
386
|
+
By default, does nothing.
|
|
387
|
+
"""
|
mesa/model.py
CHANGED
|
@@ -151,9 +151,9 @@ class Model:
|
|
|
151
151
|
agent: The agent to register.
|
|
152
152
|
|
|
153
153
|
Notes:
|
|
154
|
-
This method is called automatically by ``Agent.__init__``, so there
|
|
155
|
-
if you are subclassing Agent and calling its
|
|
156
|
-
|
|
154
|
+
This method is called automatically by ``Agent.__init__``, so there
|
|
155
|
+
is no need to use this if you are subclassing Agent and calling its
|
|
156
|
+
super in the ``__init__`` method.
|
|
157
157
|
"""
|
|
158
158
|
self._agents[agent] = None
|
|
159
159
|
|
mesa/space.py
CHANGED
|
@@ -6,7 +6,7 @@ Objects used to add a spatial component to a model.
|
|
|
6
6
|
All Grid classes (:class:`_Grid`, :class:`SingleGrid`, :class:`MultiGrid`,
|
|
7
7
|
:class:`HexGrid`, etc.) are now in maintenance-only mode. While these classes remain
|
|
8
8
|
fully supported, new development occurs in the experimental cell space module
|
|
9
|
-
(:mod:`mesa.
|
|
9
|
+
(:mod:`mesa.discrete_space`).
|
|
10
10
|
|
|
11
11
|
The :class:`PropertyLayer` and :class:`ContinuousSpace` classes remain fully supported
|
|
12
12
|
and actively developed.
|
|
@@ -607,8 +607,6 @@ class PropertyLayer:
|
|
|
607
607
|
|
|
608
608
|
"""
|
|
609
609
|
|
|
610
|
-
propertylayer_experimental_warning_given = False
|
|
611
|
-
|
|
612
610
|
def __init__(
|
|
613
611
|
self, name: str, width: int, height: int, default_value, dtype=np.float64
|
|
614
612
|
):
|
|
@@ -653,15 +651,6 @@ class PropertyLayer:
|
|
|
653
651
|
|
|
654
652
|
self.data = np.full((width, height), default_value, dtype=dtype)
|
|
655
653
|
|
|
656
|
-
if not self.__class__.propertylayer_experimental_warning_given:
|
|
657
|
-
warnings.warn(
|
|
658
|
-
"The new PropertyLayer and _PropertyGrid classes experimental. It may be changed or removed in any and all future releases, including patch releases.\n"
|
|
659
|
-
"We would love to hear what you think about this new feature. If you have any thoughts, share them with us here: https://github.com/projectmesa/mesa/discussions/1932",
|
|
660
|
-
FutureWarning,
|
|
661
|
-
stacklevel=2,
|
|
662
|
-
)
|
|
663
|
-
self.__class__.propertylayer_experimental_warning_given = True
|
|
664
|
-
|
|
665
654
|
def set_cell(self, position: Coordinate, value):
|
|
666
655
|
"""Update a single cell's value in-place."""
|
|
667
656
|
self.data[position] = value
|
mesa/visualization/__init__.py
CHANGED
|
@@ -9,12 +9,14 @@ from mesa.visualization.mpl_space_drawing import (
|
|
|
9
9
|
draw_space,
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
+
from .command_console import CommandConsole
|
|
12
13
|
from .components import make_plot_component, make_space_component
|
|
13
14
|
from .components.altair_components import make_space_altair
|
|
14
15
|
from .solara_viz import JupyterViz, SolaraViz
|
|
15
16
|
from .user_param import Slider
|
|
16
17
|
|
|
17
18
|
__all__ = [
|
|
19
|
+
"CommandConsole",
|
|
18
20
|
"JupyterViz",
|
|
19
21
|
"Slider",
|
|
20
22
|
"SolaraViz",
|