Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

meta-agent creation #2561

Closed
wants to merge 5 commits into from
Closed

Conversation

tpike3
Copy link
Member

@tpike3 tpike3 commented Dec 20, 2024

Summary

This PR is useful for creating meta-agents that represent groups of agents with interdependent characteristics.

New meta-agent classes are created dynamically using the provided name, attributes and functions of sub agents, and unique attributes and functions.

Motive

This exploits Mesa's agent set functionality to allow for more complex models

Implementation

Method has three paths of execution:

  1. Add agents to existing metaagent
  2. Create new meta-agent instance of existing metaagent class
  3. Create new meta-agent class

Added to Agent.py primarily lines 169 to 230
Added tests in test-agent.py

Usage Examples

I added a basic example of alliance formation using the bilateral shapley value

Step 0- 50 Agents:
image

Step 8 - 17 Agents of increasing hierarchy added dynamically during code execution:
image

Additional Notes

Currently restricted to one parent agent and one meta-agent per agent. Goal is to assess usage and expand functionality.

Copy link

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
BoltzmannWealth small 🔵 -0.0% [-0.8%, +0.9%] 🔵 -0.0% [-0.2%, +0.1%]
BoltzmannWealth large 🔵 -0.3% [-0.6%, +0.1%] 🔵 -0.7% [-1.5%, -0.0%]
Schelling small 🔵 -1.0% [-1.3%, -0.7%] 🟢 -48.7% [-49.0%, -48.4%]
Schelling large 🔵 -1.8% [-6.7%, +0.7%] 🟢 -47.7% [-48.1%, -47.4%]
WolfSheep small 🔵 -1.0% [-1.2%, -0.7%] 🔵 +0.8% [-0.5%, +2.1%]
WolfSheep large 🔵 +2.0% [+1.4%, +2.6%] 🔵 -1.1% [-2.4%, +0.3%]
BoidFlockers small 🔵 +0.5% [-0.0%, +1.0%] 🔵 -1.0% [-1.8%, -0.4%]
BoidFlockers large 🔵 -0.4% [-0.7%, -0.2%] 🔵 -0.8% [-1.7%, +0.0%]

- adds ability to dynamically create meta-agents
- adds alliance formation model to demonstrate
- adds tests to agent.py for meta agent creation
@tpike3 tpike3 force-pushed the network_activation branch from 5031937 to 2b0be46 Compare December 20, 2024 12:31
pre-commit-ci bot and others added 3 commits December 20, 2024 12:31
- adds ability to dynamically create meta-agents
- adds alliance formation model to demonstrate
- adds tests to agent.py for meta agent creation
@EwoutH
Copy link
Member

EwoutH commented Dec 21, 2024

Thanks for this PR. I need to read up a little about meta-agents to form an opinion on them. Especially what they are/aren't and do/don't. I hope to do that Sunday.

self.datacollector = mesa.DataCollector(model_reporters={"Network": "network"})

# Create Agents
power = np.random.normal(mean, std_dev, n)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change this to use self.rng to get the seeded numpy random number generator

"""
Calculate the Shapley value of the two agents
"""
other_agent.hierarchy = other_agent.hierarchy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line makes no sense to me.

Calculate the Shapley value of the two agents
"""
other_agent.hierarchy = other_agent.hierarchy
self.hierarchy = self.hierarchy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, you set self.hierarchy to itself.

import mesa


def calculate_shapley_value(self, other_agent):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems a function, so don't use self or make it a method on your agent.

@EwoutH
Copy link
Member

EwoutH commented Dec 22, 2024

Thanks for your PR, and thanks for your patience. I dove in a bit, and I really like meta agents conceptually.

Since a meta agent is a collection of agents, I was wondering if it could be an (extended) AgentSet. Having meta-agents extend both Agent and AgentSet would give them all the AgentSet functionality for working with their member agents, while adding meta-agent specific capabilities.

Something like:

class MetaAgent(AgentSet, Agent):
    """A meta-agent that is both an agent and a collection of agents."""
    
    def __init__(self, model, agents, **attributes):
        Agent.__init__(self, model) 
        AgentSet.__init__(self, agents, random=model.random)
        
        # Add any custom attributes
        for name, value in attributes.items():
            setattr(self, name, value)

This would give meta-agents all the powerful AgentSet functionality for working with their members (select, shuffle, sort, do, map, agg, groupby) while still allowing them to act as agents themselves.

Example usage:

class Alliance(MetaAgent):
    def __init__(self, model, agents, power_threshold=100):
        super().__init__(model, agents)
        self.total_power = sum(a.power for a in self)
        
    def step(self):
        # Use AgentSet methods on members
        self.shuffle_do("move")
        
        # Update group properties
        self.total_power = self.agg("power", sum)
        
        # Work with subsets of members
        elite = self.select(lambda a: a.power > 50)

Curious what you think!

@quaquel
Copy link
Member

quaquel commented Dec 22, 2024

The TLDR of my reaction is: conceptually, this is really interesting and something worth pursuing. Implementation-wise, I have some concerns.

Let's start with the implementation side of things first. Ideally, I would like to see the meta agent idea contained within the experimental name space. This makes it easier for me to grasp what is going on. It also gives a lot more leeway to play around with the API. I would suggest moving create_metaagent into a separate function that takes an agents rather than adding this as a method to Agent. Alternatively, we could subclass Agent into MetaAgent and use this to create a dedicated MetaAgent instance that has an AgentSet. The advantage of subclassing is that users can easily expand the meta agent to do a lot more. Either way, it becomes a lot easier to encapsulate this PR.

Conceptually, you have discussed a lot already in #2539. It would, however, be helpful if we could agree on some working definition of what a MetaAgent is. Effectively, a MetaAgent seems to be a group of agents. Agents within this group can show collective behavior. That is, the MetaAgent has state and behavior that is collective on its constituting agents. Moreover, when individuals are approached as members of this group, they might show behavior that they would not show otherwise. That is, individual agents might dynamically acquire access to behaviors when they become a member of a group and are approached as a member of this group.

I recently had a discussion with the professor of simulation in my group. He mentioned in passing that there had been an earlier 1970s AMB language that had interesting ideas on agent groups, group forming, collective behavior, and group identity-based individual behavior. I'll follow up with him again because he promised to send me some papers about this.

Minor remarkL it seems this pr is not in sync with #2539 because create_metaagent is a method on the Agent rather than the AgentSet as you suggested in #2539.

reaction to @ewout

Since a meta agent is a collection of agents, I was wondering if it could be an (extended) AgentSet. Having meta-agents extend both Agent and AgentSet would give them all the AgentSet functionality for working with their member agents, while adding meta-agent specific capabilities.

I probably would argue for composition over multiple inheritance in this case, so subclass Agent into MetaAgent and let it have an AgentSet. We might add a few methods to expose the behavior of the underlying agentset were appropriate. However, the Agent API should in most cases suffice and additional methods for joining and leaving the MetaAgent. Since this joining and leaving might involve more than just adding to and removing from the underlying AgentSet, it makes sense to have this as methods on MetaAgent.

@tpike3
Copy link
Member Author

tpike3 commented Dec 23, 2024

@EwoutH and @quaquel Thanks for the review!

To summarize (let me know if I am misunderstanding anything):

  • Will fix the bilateral shapely function. Also not sure what was going on with some of the lines of code. I think I just failed to go back an review it and co-pilot probably made some changes I wasn't tracking -- ahh LLMs a blessing and a curse
  • More importantly -- I will move metaagents to experimental and use composition vs inheritance
  • Regarding the desync with MetaAgents and agent activation based on networks #2539, fair points. I veered off from what I wrote as I got sidetracked with next steps of dealing with the exponential growth of all possible agent connections, additional functionality, and network activation. So there was a lot left on the chopping room floor so to speak. Of course probably one more reason to put it in experimental.
  • I also would be very curious in those papers you mentioned.

Thanks again!

@tpike3 tpike3 mentioned this pull request Dec 28, 2024
@tpike3
Copy link
Member Author

tpike3 commented Dec 28, 2024

Superseded by #2575

@tpike3 tpike3 closed this Dec 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants