Skip to content

Commit 5031937

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent d1baeeb commit 5031937

File tree

6 files changed

+126
-88
lines changed

6 files changed

+126
-88
lines changed

mesa/agent.py

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ def __init__(self, model: Model, *args, **kwargs) -> None:
6969
self.model.register_agent(self)
7070
# Private attribute to track parent agent if metaagents are created
7171
# Uses name mangling to prevent name clashes
72-
self.__metaagent = None # Currently restricted to one parent agent
73-
72+
self.__metaagent = None # Currently restricted to one parent agent
73+
7474
def remove(self) -> None:
7575
"""Remove and delete the agent from the model.
7676
@@ -135,9 +135,13 @@ def __getitem__(self, i):
135135
agent = cls(model, *instance_args, **instance_kwargs)
136136
agents.append(agent)
137137
return AgentSet(agents, random=model.random)
138-
139-
def create_metaagent(self, new_agent_class: str, agents: Iterable[Agent], **unique_attributes_functions) -> None:
140138

139+
def create_metaagent(
140+
self,
141+
new_agent_class: str,
142+
agents: Iterable[Agent],
143+
**unique_attributes_functions,
144+
) -> None:
141145
"""Dynamically create a new meta-agent class and instantiate agents in that class.
142146
143147
Args:
@@ -172,63 +176,74 @@ def create_metaagent(self, new_agent_class: str, agents: Iterable[Agent], **uniq
172176
def update_agents_metaagent(agents, metaagent):
173177
for agent in agents:
174178
agent._Agent__metaagent = metaagent
175-
179+
176180
# Path 1 - Add agents to existing meta-agent
177181
subagents = [agent for agent in agents if agent._Agent__metaagent is not None]
178-
182+
179183
if len(subagents) > 0:
180-
if len(subagents) == 1:
184+
if len(subagents) == 1:
181185
# Update metaagents agent set with new agents
182186
subagents[0]._Agent__metaagent.agents.update(agents)
183187
# Update subagents with metaagent
184188
update_agents_metaagent(agents, subagents[0]._Agent__metaagent)
185-
else:
189+
else:
186190
# If there are multiple subagents, one is chosen at random to be the parent metaagent
187191
subagent = self.random.choice(subagents)
188192
# Remove agent who are already part of metaagent
189193
agents = set(agents) - set(subagents)
190194
subagent._Agent__metaagent.agents.update(agents)
191195
update_agents_metaagent(agents, subagent._Agent__metaagent)
192196
# TODO: Add way for user to add function to specify how agents join metaagent
193-
194-
else:
197+
198+
else:
195199
# Path 2 - Create a new instance of an exsiting meta-agent class
196-
agent_class = next((agent_type for agent_type in self.model.agent_types if agent_type.__name__ == new_agent_class), None)
200+
agent_class = next(
201+
(
202+
agent_type
203+
for agent_type in self.model.agent_types
204+
if agent_type.__name__ == new_agent_class
205+
),
206+
None,
207+
)
197208
if agent_class:
198209
# Create an instance of the meta-agent class
199-
meta_agent_instance = agent_class(self.model, **unique_attributes_functions)
210+
meta_agent_instance = agent_class(
211+
self.model, **unique_attributes_functions
212+
)
200213
# Add agents to meta-agent instance
201214
meta_agent_instance.agents = agents
202215
# Update subagents Agent.__metaagent attribute
203-
update_agents_metaagent(agents, meta_agent_instance)
216+
update_agents_metaagent(agents, meta_agent_instance)
204217
# Register the new meta-agent instance
205218
self.model.register_agent(meta_agent_instance)
206219

207-
return meta_agent_instance
208-
220+
return meta_agent_instance
221+
209222
# Path 3 - Create a new meta-agent class
210-
else:
223+
else:
211224
# Get agent types of subagents to create the new meta-agent class
212-
agent_types = tuple(set((type(agent) for agent in agents)))
225+
agent_types = tuple({type(agent) for agent in agents})
213226

214227
meta_agent_class = type(
215228
new_agent_class,
216229
agent_types,
217230
{
218231
"unique_id": None,
219-
"agents": agents,
220-
}
232+
"agents": agents,
233+
},
221234
)
222-
235+
223236
# Create an instance of the meta-agent class
224-
meta_agent_instance = meta_agent_class(self.model, **unique_attributes_functions)
237+
meta_agent_instance = meta_agent_class(
238+
self.model, **unique_attributes_functions
239+
)
225240
# Register the new meta-agent instance
226241
self.model.register_agent(meta_agent_instance)
227242
# Update subagents Agent.__metaagent attribute
228-
update_agents_metaagent(agents, meta_agent_instance)
243+
update_agents_metaagent(agents, meta_agent_instance)
244+
245+
return meta_agent_instance
229246

230-
return meta_agent_instance
231-
232247
@property
233248
def random(self) -> Random:
234249
"""Return a seeded stdlib rng."""

mesa/examples/basic/alliance_formation_model/Readme.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
## Summary
44

5-
This model demonstrates Mesa's ability to dynamically create new classes of agents that are composed of existing agents. These meta-agents inherits functions and attributes from their sub-agents and users can specify new functionality or attributes they want the meta agent to have. For example, if a user is doing a factory simulation with autonomous systems, each major component of that system can be a sub-agent of the overall robot agent. Or, if someone is doing a simulation of an organization, individuals can be part of different organizational units that are working for some purpose.
5+
This model demonstrates Mesa's ability to dynamically create new classes of agents that are composed of existing agents. These meta-agents inherits functions and attributes from their sub-agents and users can specify new functionality or attributes they want the meta agent to have. For example, if a user is doing a factory simulation with autonomous systems, each major component of that system can be a sub-agent of the overall robot agent. Or, if someone is doing a simulation of an organization, individuals can be part of different organizational units that are working for some purpose.
66

7-
To provide a simple demonstration of this capability is an alliance formation model.
7+
To provide a simple demonstration of this capability is an alliance formation model.
88

9-
In this simulation n agents are created, who have two attributes (1) power and (2) preference. Each attribute is a number between 0 and 1 over a gaussian distribution. Agents then randomly select other agents and use the [bilateral shapley value](https://en.wikipedia.org/wiki/Shapley_value) to determine if they should form an alliance. If the expected utility support an alliances, the agent creates a meta-agent. Subsequent steps may add agents to the meta-agent, create new instances of similar hierarchy, or create a new hierarchy level where meta-agents form an alliance of meta-agents. In this visualization of this model a new meta-agent hierarchy will be a larger node and a new color.
9+
In this simulation n agents are created, who have two attributes (1) power and (2) preference. Each attribute is a number between 0 and 1 over a gaussian distribution. Agents then randomly select other agents and use the [bilateral shapley value](https://en.wikipedia.org/wiki/Shapley_value) to determine if they should form an alliance. If the expected utility support an alliances, the agent creates a meta-agent. Subsequent steps may add agents to the meta-agent, create new instances of similar hierarchy, or create a new hierarchy level where meta-agents form an alliance of meta-agents. In this visualization of this model a new meta-agent hierarchy will be a larger node and a new color.
1010

11-
In its current configuration, agents being part of multiple meta-agents is not supported
11+
In its current configuration, agents being part of multiple meta-agents is not supported
1212

1313
## Installation
1414

@@ -36,6 +36,6 @@ To run the model interactively, in this directory, run the following command
3636
The full tutorial describing how the model is built can be found at:
3737
https://mesa.readthedocs.io/en/latest/tutorials/intro_tutorial.html
3838

39-
An example of the bilateral shapley value in another model:
39+
An example of the bilateral shapley value in another model:
4040
[Techno-Social Energy Infrastructure Siting: Sustainable Energy Modeling Programming (SEMPro)](https://www.jasss.org/16/3/6.html)
4141

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,68 @@
11
import mesa
22

3+
34
def calculate_shapley_value(self, other_agent):
4-
"""
5-
Calculate the Shapley value of the two agents
6-
"""
7-
other_agent.hierarchy = other_agent.hierarchy
8-
self.hierarchy = self.hierarchy
9-
new_position = 1-abs(self.position - other_agent.position)
10-
potential_utility = (self.power+other_agent.power)*1.1 * new_position
11-
value_me = 0.5 * self.power + 0.5 * (potential_utility - other_agent.power)
12-
value_other = 0.5 * other_agent.power + 0.5 * (potential_utility - self.power)
13-
14-
15-
# Determine ig there is value in the alliance
16-
if value_me > self.power and value_other > other_agent.power:
17-
if other_agent.hierarchy>self.hierarchy:
18-
hierarchy = other_agent.hierarchy
19-
elif other_agent.hierarchy==self.hierarchy:
20-
hierarchy = self.hierarchy+1
21-
else:
22-
hierarchy = self.hierarchy
23-
24-
return (potential_utility, new_position, hierarchy)
5+
"""
6+
Calculate the Shapley value of the two agents
7+
"""
8+
other_agent.hierarchy = other_agent.hierarchy
9+
self.hierarchy = self.hierarchy
10+
new_position = 1 - abs(self.position - other_agent.position)
11+
potential_utility = (self.power + other_agent.power) * 1.1 * new_position
12+
value_me = 0.5 * self.power + 0.5 * (potential_utility - other_agent.power)
13+
value_other = 0.5 * other_agent.power + 0.5 * (potential_utility - self.power)
14+
15+
# Determine ig there is value in the alliance
16+
if value_me > self.power and value_other > other_agent.power:
17+
if other_agent.hierarchy > self.hierarchy:
18+
hierarchy = other_agent.hierarchy
19+
elif other_agent.hierarchy == self.hierarchy:
20+
hierarchy = self.hierarchy + 1
2521
else:
26-
return None
22+
hierarchy = self.hierarchy
23+
24+
return (potential_utility, new_position, hierarchy)
25+
else:
26+
return None
27+
2728

2829
class alliance_agent(mesa.Agent):
2930
"""
3031
Agent has three attirbutes power (float), position (float) and hierarchy (int)
31-
32+
3233
"""
34+
3335
def __init__(self, model, power, position, hierarchy=0):
3436
super().__init__(model)
3537
self.power = power
3638
self.position = position
3739
self.hierarchy = hierarchy
3840

39-
4041
def form_alliance(self):
4142
# Randomly select another agent of the same type
42-
other_agents = [agent for agent in self.model.agents_by_type[type(self)] if agent != self]
43-
43+
other_agents = [
44+
agent for agent in self.model.agents_by_type[type(self)] if agent != self
45+
]
46+
4447
# Determine if there is a beneficial alliance
45-
if other_agents:
48+
if other_agents:
4649
other_agent = self.random.choice(other_agents)
4750
shapley_value = calculate_shapley_value(self, other_agent)
4851
if shapley_value:
4952
class_name = f"MetaAgentHierarchy{shapley_value[2]}"
50-
meta = self.create_metaagent(class_name, {other_agent, self}, hierarchy=shapley_value[2],
51-
power=shapley_value[0],position=shapley_value[1])
52-
53+
meta = self.create_metaagent(
54+
class_name,
55+
{other_agent, self},
56+
hierarchy=shapley_value[2],
57+
power=shapley_value[0],
58+
position=shapley_value[1],
59+
)
60+
5361
# Update the network if a new meta agent instance created
54-
if meta:
55-
self.model.network.add_node(meta.unique_id, size =(meta.hierarchy+1)*200)
56-
self.model.new_agents=True
62+
if meta:
63+
self.model.network.add_node(
64+
meta.unique_id, size=(meta.hierarchy + 1) * 200
65+
)
66+
self.model.new_agents = True
5767
else:
58-
self.model.new_agents=False
68+
self.model.new_agents = False

mesa/examples/basic/alliance_formation_model/app.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import networkx as nx
21
import matplotlib.pyplot as plt
2+
import networkx as nx
3+
import solara
34
from matplotlib.figure import Figure
5+
46
from mesa.examples.basic.alliance_formation.model import alliance_model
5-
import solara
67
from mesa.mesa_logging import DEBUG, log_to_stderr
8+
from mesa.visualization import SolaraViz
79
from mesa.visualization.utils import update_counter
8-
from mesa.visualization import (SolaraViz)
910

1011
log_to_stderr(DEBUG)
1112

1213

13-
1414
model_params = {
1515
"seed": {
1616
"type": "InputText",
@@ -33,27 +33,31 @@
3333
# You can also author your own visualization elements, which can also be functions
3434
# that receive the model instance and return a valid solara component.
3535

36+
3637
@solara.component
3738
def plot_network(model):
38-
update_counter.get()
39+
update_counter.get()
3940
G = model.network
4041
pos = nx.spring_layout(G)
4142
fig = Figure()
4243
ax = fig.subplots()
4344
labels = {agent.unique_id: agent.unique_id for agent in model.agents}
44-
node_sizes = [G.nodes[node]['size'] for node in G.nodes]
45-
node_colors = [G.nodes[node]['size'] for node in G.nodes()]
45+
node_sizes = [G.nodes[node]["size"] for node in G.nodes]
46+
node_colors = [G.nodes[node]["size"] for node in G.nodes()]
47+
48+
nx.draw(
49+
G,
50+
pos,
51+
node_size=node_sizes,
52+
node_color=node_colors,
53+
cmap=plt.cm.coolwarm,
54+
labels=labels,
55+
ax=ax,
56+
)
4657

47-
nx.draw(G,
48-
pos,
49-
node_size = node_sizes,
50-
node_color = node_colors,
51-
cmap=plt.cm.coolwarm,
52-
labels=labels,
53-
ax=ax)
54-
5558
solara.FigureMatplotlib(fig)
5659

60+
5761
# Create initial model instance
5862
model = alliance_model(50)
5963

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
import networkx as nx
12
import numpy as np
2-
import mesa
33
from agent import alliance_agent
4-
import networkx as nx
4+
5+
import mesa
6+
57

68
class alliance_model(mesa.Model):
79
def __init__(self, n=50, mean=0.5, std_dev=0.1, seed=42):
810
super().__init__(seed=seed)
911
self.population = n
1012
self.network = nx.Graph() # Initialize the network
1113
self.datacollector = mesa.DataCollector(model_reporters={"Network": "network"})
12-
1314

1415
# Create Agents
1516
power = np.random.normal(mean, std_dev, n)
@@ -22,14 +23,15 @@ def __init__(self, n=50, mean=0.5, std_dev=0.1, seed=42):
2223

2324
def add_link(self, metaagent, agents):
2425
for agent in agents:
25-
self.network.add_edge(metaagent.unique_id, agent.unique_id)
26+
self.network.add_edge(metaagent.unique_id, agent.unique_id)
2627

2728
def step(self):
28-
for agent_class in list(self.agent_types): # Convert to list to avoid modification during iteration
29+
for agent_class in list(
30+
self.agent_types
31+
): # Convert to list to avoid modification during iteration
2932
self.agents_by_type[agent_class].shuffle_do("form_alliance")
3033

3134
# Update graph
3235
if agent_class is not alliance_agent:
3336
for metaagent in self.agents_by_type[agent_class]:
34-
self.add_link(metaagent, metaagent.agents)
35-
37+
self.add_link(metaagent, metaagent.agents)

tests/test_agent.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,7 @@ def __init__(self, model, power, position, hierarchy=0):
691691
self.position = position
692692
self.hierarchy = hierarchy
693693

694+
694695
def test_create_metaagent():
695696
model = Model()
696697
agent1 = TestMetaAgent(model, power=0.5, position=0.5)
@@ -699,21 +700,27 @@ def test_create_metaagent():
699700
agent4 = TestMetaAgent(model, power=0.8, position=0.8)
700701

701702
# Test creating a new meta-agent class
702-
meta = agent1.create_metaagent("MetaAgentClass1", {agent1, agent2}, power=1.1, position=0.55, hierarchy=1)
703+
meta = agent1.create_metaagent(
704+
"MetaAgentClass1", {agent1, agent2}, power=1.1, position=0.55, hierarchy=1
705+
)
703706
assert len(model.agent_types) == 2
704707
assert len(model.agents) == 5
705708
assert meta.power == 1.1
706709
assert meta.position == 0.55
707710
assert meta.hierarchy == 1
708711

709712
# Test adding agents to an existing meta-agent
710-
agent1.create_metaagent("MetaAgentClass1", {agent3, agent2}, power=1.8, position=0.65, hierarchy=1)
713+
agent1.create_metaagent(
714+
"MetaAgentClass1", {agent3, agent2}, power=1.8, position=0.65, hierarchy=1
715+
)
711716
assert len(model.agent_types) == 2
712717
assert len(model.agents) == 5
713718
assert len(meta.agents) == 3
714719

715720
# Test creating a new instance of an existing meta-agent class
716-
meta2 = agent4.create_metaagent("MetaAgentClass2", {agent4}, power=0.8, position=0.8, hierarchy=2)
721+
meta2 = agent4.create_metaagent(
722+
"MetaAgentClass2", {agent4}, power=0.8, position=0.8, hierarchy=2
723+
)
717724
assert len(model.agent_types) == 3
718725
assert len(model.agents) == 6
719726
assert meta2.power == 0.8

0 commit comments

Comments
 (0)