Skip to content

Commit ff14883

Browse files
committed
Remove key_by_name
Update model.py integrate comments
1 parent e1492ea commit ff14883

File tree

4 files changed

+47
-37
lines changed

4 files changed

+47
-37
lines changed

mesa/agent.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,11 @@ class Agent:
4848
# so, unique_id is unique relative to a model, and counting starts from 1
4949
_ids = defaultdict(functools.partial(itertools.count, 1))
5050

51-
def __init__(
52-
self, model: Model, *args, key_by_name: bool = False, **kwargs
53-
) -> None:
51+
def __init__(self, model: Model, *args, **kwargs) -> None:
5452
"""Create a new agent.
5553
5654
Args:
5755
model (Model): The model instance in which the agent exists.
58-
key_by_name (bool): If True, use Agent.__name__ as the key in the model's agents_by_type dictionary.
5956
args: Passed on to super.
6057
kwargs: Passed on to super.
6158
"""
@@ -64,7 +61,7 @@ def __init__(
6461
self.model: Model = model
6562
self.unique_id: int = next(self._ids[model])
6663
self.pos: Position | None = None
67-
self.model.register_agent(self, key_by_name=key_by_name)
64+
self.model.register_agent(self)
6865

6966
def remove(self) -> None:
7067
"""Remove and delete the agent from the model.

mesa/examples/advanced/alliance_formation/model.py

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import numpy as np
33

44
import mesa
5+
from mesa import Agent
56
from mesa.examples.advanced.alliance_formation.agents import AllianceAgent
67
from mesa.experimental.meta_agents.meta_agent import (
78
create_meta_agent,
@@ -165,6 +166,7 @@ def step(self):
165166
self,
166167
class_name,
167168
alliance,
169+
Agent,
168170
meta_attributes={
169171
"level": attributes[2],
170172
"power": attributes[0],

mesa/experimental/meta_agents/meta_agent.py

+37-32
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040

4141
import itertools
4242
from collections.abc import Callable, Iterable
43-
from concurrent.futures import ThreadPoolExecutor
4443
from types import MethodType
4544
from typing import Any
4645

@@ -95,28 +94,22 @@ def find_combinations(
9594
combinations. Defaults to None.
9695
9796
Returns:
98-
List[Tuple[AgentSet, float]]: The list of valuable combinations.
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.
99100
"""
100101
combinations = []
101-
with ThreadPoolExecutor() as executor:
102-
futures = []
103-
# Allow one size or range of sizes to be passed
104-
size_range = (size, size + 1) if isinstance(size, int) else size
102+
# Allow one size or range of sizes to be passed
103+
size_range = (size, size + 1) if isinstance(size, int) else size
105104

106-
candidate_groups = itertools.chain.from_iterable(
107-
itertools.combinations(group, size) for size in range(*size_range)
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
108110
)
109-
for candidate_group in candidate_groups:
110-
futures.append(
111-
executor.submit(
112-
evaluate_combination, candidate_group, model, evaluation_func
113-
)
114-
)
115-
116-
for future in futures:
117-
group_set, result = future.result()
118-
if result:
119-
combinations.append((group_set, result))
111+
if result:
112+
combinations.append((group_set, result))
120113

121114
if len(combinations) > 0 and filter_func:
122115
filtered_combinations = filter_func(combinations)
@@ -125,27 +118,31 @@ def find_combinations(
125118
return combinations
126119

127120

128-
def extract_class(agents_by_type: dict, new_agent_class: str):
121+
def extract_class(agents_by_type: dict, new_agent_class: object) -> type[Agent] | None:
129122
"""Helper function for create_meta_agents extracts the types of agents.
130123
131124
Args:
132125
agents_by_type (dict): The dictionary of agents by type.
133126
new_agent_class (str): The name of the agent class to be created
134127
135128
Returns:
136-
type(Agent) if it agent type exists
129+
type(Agent) if agent type exists
137130
None otherwise
138131
"""
139-
if new_agent_class in agents_by_type:
140-
return type(agents_by_type[new_agent_class][0])
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])
141138
return None
142139

143140

144141
def create_meta_agent(
145142
model: Any,
146143
new_agent_class: str,
147144
agents: Iterable[Any],
148-
mesa_agent_type=Agent,
145+
mesa_agent_type: type[Agent] | None,
149146
meta_attributes: dict[str, Any] | None = None,
150147
meta_methods: dict[str, Callable] | None = None,
151148
assume_subagent_methods: bool = False,
@@ -165,15 +162,17 @@ def create_meta_agent(
165162
from sub-agents.
166163
167164
Returns:
168-
Optional[Any]:
169-
- None if adding agent(s) to existing class
170-
- New class instance if created a new instance of a dynamically
171-
created agent type
172-
- New class instance if created a new dynamically created agent type
165+
- MetaAgent Instance
173166
"""
174167
# Convert agents to set to ensure uniqueness
175168
agents = set(agents)
176169

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+
177176
def add_methods(
178177
meta_agent_instance: Any,
179178
agents: Iterable[Any],
@@ -236,6 +235,8 @@ def add_attributes(
236235
add_methods(subagents[0].meta_agent, agents, meta_methods)
237236
subagents[0].meta_agent.add_subagents(agents)
238237

238+
return subagents[0].meta_agent # Return the existing meta-agent
239+
239240
else:
240241
subagent = model.random.choice(subagents)
241242
agents = set(agents) - set(subagents)
@@ -244,9 +245,12 @@ def add_attributes(
244245
subagent.meta_agent.add_subagents(agents)
245246
# TODO: Add way for user to specify how agents join meta-agent
246247
# instead of random choice
248+
return subagent.meta_agent
249+
247250
else:
248251
# Path 2 - Create a new instance of an existing meta-agent class
249252
agent_class = extract_class(model.agents_by_type, new_agent_class)
253+
250254
if agent_class:
251255
meta_agent_instance = agent_class(model, agents)
252256
add_attributes(meta_agent_instance, agents, meta_attributes)
@@ -256,7 +260,7 @@ def add_attributes(
256260
# Path 3 - Create a new meta-agent class
257261
meta_agent_class = type(
258262
new_agent_class,
259-
(MetaAgent, mesa_agent_type), # Use the meta_agent_type parameter here
263+
(MetaAgent, *mesa_agent_type), # Inherit Mesa Agent Classes
260264
{
261265
"unique_id": None,
262266
"_subset": None,
@@ -265,6 +269,7 @@ def add_attributes(
265269
meta_agent_instance = meta_agent_class(model, agents)
266270
add_attributes(meta_agent_instance, agents, meta_attributes)
267271
add_methods(meta_agent_instance, agents, meta_methods)
272+
print(meta_agent_instance.agents)
268273
return meta_agent_instance
269274

270275

@@ -282,7 +287,7 @@ def __init__(
282287
include in the MetaAgent. Defaults to None.
283288
name (str, optional): The name of the MetaAgent. Defaults to "MetaAgent".
284289
"""
285-
super().__init__(model, key_by_name=True)
290+
super().__init__(model)
286291
self._subset = AgentSet(agents or [], random=model.random)
287292
self.name = name
288293

@@ -305,7 +310,7 @@ def __contains__(self, agent: Agent) -> bool:
305310
@property
306311
def agents(self) -> AgentSet:
307312
"""Get list of Meta-Agent subagents."""
308-
return set(self._subset)
313+
return self._subset
309314

310315
@property
311316
def subagents_by_type(self) -> dict[type, list[Agent]]:

tests/test_meta_agents.py

+6
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def test_create_meta_agent_new_class(setup_agents):
5252
model,
5353
"MetaAgentClass",
5454
agents,
55+
Agent,
5556
meta_attributes={"attribute1": "value1"},
5657
meta_methods={"function1": lambda self: "function1"},
5758
assume_subagent_attributes=True,
@@ -77,6 +78,7 @@ def test_create_meta_agent_existing_class(setup_agents):
7778
model,
7879
"MetaAgentClass",
7980
[agents[0], agents[2]],
81+
Agent,
8082
meta_attributes={"attribute1": "value1"},
8183
meta_methods={"function1": lambda self: "function1"},
8284
)
@@ -86,6 +88,7 @@ def test_create_meta_agent_existing_class(setup_agents):
8688
model,
8789
"MetaAgentClass",
8890
[agents[1], agents[3]],
91+
Agent,
8992
meta_attributes={"attribute2": "value2"},
9093
meta_methods={"function2": lambda self: "function2"},
9194
assume_subagent_attributes=True,
@@ -112,6 +115,7 @@ def test_add_agents_to_existing_meta_agent(setup_agents):
112115
model,
113116
"MetaAgentClass",
114117
[agents[0], agents[3]],
118+
Agent,
115119
meta_attributes={"attribute1": "value1"},
116120
meta_methods={"function1": lambda self: "function1"},
117121
assume_subagent_attributes=True,
@@ -121,6 +125,7 @@ def test_add_agents_to_existing_meta_agent(setup_agents):
121125
model,
122126
"MetaAgentClass",
123127
[agents[1], agents[0], agents[2]],
128+
Agent,
124129
assume_subagent_attributes=True,
125130
assume_subagent_methods=True,
126131
)
@@ -145,6 +150,7 @@ def test_meta_agent_integration(setup_agents):
145150
model,
146151
"MetaAgentClass",
147152
agents,
153+
Agent,
148154
meta_attributes={"attribute1": "value1"},
149155
meta_methods={"function1": lambda self: "function1"},
150156
assume_subagent_attributes=True,

0 commit comments

Comments
 (0)