-
Notifications
You must be signed in to change notification settings - Fork 927
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
PoC: Multiple-agent types scheduling and datacollection #1142
Conversation
Proof of concept. This code is not meant for production. This commit adds support for multiple agent-types, including scheduling and data collection. The scheduler is based on the RandomActivationByBreed scheduler from the wolf_sheep example. It supports RandomActivation by type, in the order that they are initialized. See https://github.com/projectmesa/mesa/blob/246c69d592a82e89c75d555c79736c3f619d434a/examples/wolf_sheep/wolf_sheep/schedule.py The DataCollection module is modified to support multiple agent types. It uses a dictionary structure for all agent reporters and records, with the agent class as the key. The ChartModule has been extended to enable data collection both Agent and Model variables, and agents of different types. Contains currently a breaking change by requiring "Type" key in the ChartModule input dictionary, which can either be "Model" or "Agent". If "Agent", a key "Agent_type" is also required. To-do: - Scheduler: Allow custom order of agent types in staging (and not just the order in which their created). - DataCollector: Ensure it still works with only a single/default agent type - ChartVisualisation: 1) Try to reduce breaking changes, 2) ensure it still works with a single/default agent-type, 3) Allow different kinds of statistical processing then mean (median, sum, min, max, standard deviation, etc.) (maybe implement this in DataCollector) - Cleanup - Testing - Documentation (including examples)
The Agents.jl implementation is much simpler and modular, because they can just use multiple dispatch. :/ |
I read a bit up about multiple dispatch, and it indeed seems very useful in this case to be able to handle both the model and different agent types. Julia is a very interesting language! A few Python packages implement this. multipledispatch seems unmaintained, while plum is newer and actively maintained but less used. Another option that could simplify things is using Structural Pattern Matching. This does require Python 3.10 however, and dropping support for all previous versions might be a bit too early. |
Moves the metric aggegration code to the datacollector, in a new function get_agent_metric(). It returns a single value from the agent variables, using either a function in the statistics module or one of the built-in functions "min", "max", "sum" or "len". In the ChartModule an optional "Metric" can now be called, which defaults to "mean".
Actually, upon rereading Agents.jl's implementation, they use a flat list of agents and reconstruct the set of agents grouped by type on-the-fly. And so the main design decision is whether we should use a flat dict like before (and generates the |
I moved the metric aggegration code to the Example: ExampleModel.datacollector.get_agent_metric("Weight", Cat, "min") In the Example: chart_size = ChartModule(
[{"Type": "Agent", "Agent_type": "Cat", "Label": "Size", "Metric": "max", "Color": "Blue"}],
data_collector_name="datacollector"
) Again, both architecture and implementation notes are much appreciated! (also CC @tpike3) |
Yes, this is a big design decision indeed. Love to hear your and everyone elses opinion about it! One idea I had, it to detect in the Another idea is to let the I think both options would be able to maintain backwards compatibility.
In this current draft, yes. One of the above solutions should be able to mitigate this as well. |
@EwoutH This is awesome! Glad to see so much progress, particularly as I have a very bad habit of ignoring the visualization piece. To make sure I am understanding correctly, right now the current approach has a flat dict My initial response would be whatever is faster. (I will try and run some comparisons but due to my current job probably can't get to it until next weekend...sorry I am the slow one in this group) My more thoughtful response is on the fly might allow for hypertypes. For the seminal wolf-sheep model this isn't a consideration but thinking of a social model where agents may change their type based on their situation (e.g. civil violence, politics, alliance) this could add some more capability where you can run the standard static type (e.g. wolf-sheep) but you can also allow for type adaption.
This thought would mess up the class approach though because the type could also be an attribute and not just a class. So I am not sure I helped or muddled the discussion, but I think grouping agents on the fly may offer some additional capabilities for more diverse model approaches. |
Things to consider:
|
Thank you both for you responses according the architecture! In the next week I will focus on finishing up my courses for this quarter (I'm still a student), and the week after that I'm a week on vacation and offline. So somewhere after February 7th, I will continue this effort. If anyone in the mean time wants to continue or try some things, feel free to checkout my branch (https://github.com/EwoutH/mesa/tree/multiple-agent-types) or install it ( A particularly piece of this PR wasn't about multi-agent support, but just about reading and plotting agent variables. Thus, I've created a separate PR, that implements this: If we get that in first, we can built multiple-agent types on top of it. Maybe #1145 can even make the 0.9.0 release! Also Tom, don't even sweat it for a second, your pretty involved as a maintainer. Thank you! |
@EwoutH sorry it didn't back the 0.9.0 release but these are pretty big challenges |
No worries, this isn't even close to ready yet. Purely a proof of concept. I hope to spend some more time on it in the coming weeks. |
#1162 is only the scheduler, there is some DataCollector and Visualisation stuff in here to. I did like to leave it open for a while, until I can properly implement it or someone else picks it up. |
Tracks agents in the model with a defaultdict. This PR adds a new `agents` dictionary to the Mesa `Model` class, enabling native support for handling multiple agent types within models. This way all modules can know which agents and agents type are in the model at any given time, by calling `model.agents`. NetLogo has had agent types, called [`breeds`](https://ccl.northwestern.edu/netlogo/docs/dict/breed.html), built-in from the start. It works perfectly in all NetLogo components, because it's a first class citizen and all components need to be designed to consider different breeds. In Mesa, agent types are an afterthought at best. Almost nothing is currently designed with multiple agent types in mind. That has caused several issues and limitations over the years, including: - projectmesa#348 - projectmesa#1142 - projectmesa#1162 Especially in scheduling, space and datacollection, lack of a native, consistent construct for agent types severely limits the possibilities. With the discussion about patches and "empty" this discussion done again. You might want empty to refer to all agents or only a subset of types or single type. That's currently cumbersome to implement. Basically, by always having dictionary available of which agents of which types are in the model, you can always trust on a consistent construct to iterate over agents and agent types. - The `Model` class now uses a `defaultdict` to store agents, ensuring a set is automatically created for each new agent type. - The `Agent` class has been updated to leverage this feature, simplifying the registration process when an agent is created. - The `remove` method in the `Agent` class now uses `discard`, providing a safer way to remove agents from the model.
Tracks agents in the model with a defaultdict. This PR adds a new `agents` dictionary to the Mesa `Model` class, enabling native support for handling multiple agent types within models. This way all modules can know which agents and agents type are in the model at any given time, by calling `model.agents`. NetLogo has had agent types, called [`breeds`](https://ccl.northwestern.edu/netlogo/docs/dict/breed.html), built-in from the start. It works perfectly in all NetLogo components, because it's a first class citizen and all components need to be designed to consider different breeds. In Mesa, agent types are an afterthought at best. Almost nothing is currently designed with multiple agent types in mind. That has caused several issues and limitations over the years, including: - #348 - #1142 - #1162 Especially in scheduling, space and datacollection, lack of a native, consistent construct for agent types severely limits the possibilities. With the discussion about patches and "empty" this discussion done again. You might want empty to refer to all agents or only a subset of types or single type. That's currently cumbersome to implement. Basically, by always having dictionary available of which agents of which types are in the model, you can always trust on a consistent construct to iterate over agents and agent types. - The `Model` class now uses a `defaultdict` to store agents, ensuring a set is automatically created for each new agent type. - The `Agent` class has been updated to leverage this feature, simplifying the registration process when an agent is created. - The `remove` method in the `Agent` class now uses `discard`, providing a safer way to remove agents from the model.
Proof of concept. This code is not meant for production.
This commit adds support for multiple agent-types, including scheduling and data collection.
The scheduler is based on the
RandomActivationByBreed
scheduler from thewolf_sheep
example. It supports RandomActivation by agent type, in the order that they are initialized. See examples/wolf_sheep/wolf_sheep/schedule.py.The DataCollection module is modified to support multiple agent types. It uses a dictionary structure for all agent reporters and records, with the agent class as the key.
The ChartModule has been extended to enable data collection both Agent and Model variables, and agents of different types. Contains currently a breaking change by requiring
"Type"
key in the ChartModule input dictionary, which can either be"Model"
or"Agent"
. If"Agent"
, a key"Agent_type"
is also required, which should be the exact name of the class as a string (__class__.__name__
).A Mesa Model class with a datacollector can now look like this:
Charts for a Mesa Server can now look like this:
To-do