40
40
41
41
import itertools
42
42
from collections .abc import Callable , Iterable
43
- from concurrent .futures import ThreadPoolExecutor
44
43
from types import MethodType
45
44
from typing import Any
46
45
@@ -95,28 +94,22 @@ def find_combinations(
95
94
combinations. Defaults to None.
96
95
97
96
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.
99
100
"""
100
101
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
105
104
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
108
110
)
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 ))
120
113
121
114
if len (combinations ) > 0 and filter_func :
122
115
filtered_combinations = filter_func (combinations )
@@ -125,27 +118,31 @@ def find_combinations(
125
118
return combinations
126
119
127
120
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 :
129
122
"""Helper function for create_meta_agents extracts the types of agents.
130
123
131
124
Args:
132
125
agents_by_type (dict): The dictionary of agents by type.
133
126
new_agent_class (str): The name of the agent class to be created
134
127
135
128
Returns:
136
- type(Agent) if it agent type exists
129
+ type(Agent) if agent type exists
137
130
None otherwise
138
131
"""
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 ])
141
138
return None
142
139
143
140
144
141
def create_meta_agent (
145
142
model : Any ,
146
143
new_agent_class : str ,
147
144
agents : Iterable [Any ],
148
- mesa_agent_type = Agent ,
145
+ mesa_agent_type : type [ Agent ] | None ,
149
146
meta_attributes : dict [str , Any ] | None = None ,
150
147
meta_methods : dict [str , Callable ] | None = None ,
151
148
assume_subagent_methods : bool = False ,
@@ -165,15 +162,17 @@ def create_meta_agent(
165
162
from sub-agents.
166
163
167
164
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
173
166
"""
174
167
# Convert agents to set to ensure uniqueness
175
168
agents = set (agents )
176
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
+
177
176
def add_methods (
178
177
meta_agent_instance : Any ,
179
178
agents : Iterable [Any ],
@@ -236,6 +235,8 @@ def add_attributes(
236
235
add_methods (subagents [0 ].meta_agent , agents , meta_methods )
237
236
subagents [0 ].meta_agent .add_subagents (agents )
238
237
238
+ return subagents [0 ].meta_agent # Return the existing meta-agent
239
+
239
240
else :
240
241
subagent = model .random .choice (subagents )
241
242
agents = set (agents ) - set (subagents )
@@ -244,9 +245,12 @@ def add_attributes(
244
245
subagent .meta_agent .add_subagents (agents )
245
246
# TODO: Add way for user to specify how agents join meta-agent
246
247
# instead of random choice
248
+ return subagent .meta_agent
249
+
247
250
else :
248
251
# Path 2 - Create a new instance of an existing meta-agent class
249
252
agent_class = extract_class (model .agents_by_type , new_agent_class )
253
+
250
254
if agent_class :
251
255
meta_agent_instance = agent_class (model , agents )
252
256
add_attributes (meta_agent_instance , agents , meta_attributes )
@@ -256,7 +260,7 @@ def add_attributes(
256
260
# Path 3 - Create a new meta-agent class
257
261
meta_agent_class = type (
258
262
new_agent_class ,
259
- (MetaAgent , mesa_agent_type ), # Use the meta_agent_type parameter here
263
+ (MetaAgent , * mesa_agent_type ), # Inherit Mesa Agent Classes
260
264
{
261
265
"unique_id" : None ,
262
266
"_subset" : None ,
@@ -265,6 +269,7 @@ def add_attributes(
265
269
meta_agent_instance = meta_agent_class (model , agents )
266
270
add_attributes (meta_agent_instance , agents , meta_attributes )
267
271
add_methods (meta_agent_instance , agents , meta_methods )
272
+ print (meta_agent_instance .agents )
268
273
return meta_agent_instance
269
274
270
275
@@ -282,7 +287,7 @@ def __init__(
282
287
include in the MetaAgent. Defaults to None.
283
288
name (str, optional): The name of the MetaAgent. Defaults to "MetaAgent".
284
289
"""
285
- super ().__init__ (model , key_by_name = True )
290
+ super ().__init__ (model )
286
291
self ._subset = AgentSet (agents or [], random = model .random )
287
292
self .name = name
288
293
@@ -305,7 +310,7 @@ def __contains__(self, agent: Agent) -> bool:
305
310
@property
306
311
def agents (self ) -> AgentSet :
307
312
"""Get list of Meta-Agent subagents."""
308
- return set ( self ._subset )
313
+ return self ._subset
309
314
310
315
@property
311
316
def subagents_by_type (self ) -> dict [type , list [Agent ]]:
0 commit comments