Skip to content

Commit

Permalink
Native support for multiple agent types
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
EwoutH authored and tpike3 committed Dec 18, 2023
1 parent 3b326c8 commit 6e62857
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 4 deletions.
23 changes: 19 additions & 4 deletions mesa/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,34 @@


class Agent:
"""Base class for a model agent."""
"""
Base class for a model agent in Mesa.
Attributes:
unique_id (int): A unique identifier for this agent.
model (Model): A reference to the model instance.
self.pos: Position | None = None
"""

def __init__(self, unique_id: int, model: Model) -> None:
"""Create a new agent.
"""
Create a new agent.
Args:
unique_id (int): A unique numeric identified for the agent
model: (Model): Instance of the model that contains the agent
unique_id (int): A unique identifier for this agent.
model (Model): The model instance in which the agent exists.
"""
self.unique_id = unique_id
self.model = model
self.pos: Position | None = None

# Register the agent with the model using defaultdict
self.model.agents[type(self)].add(self)

def remove(self) -> None:
"""Remove and delete the agent from the model."""
self.model.agents[type(self)].discard(self)

def step(self) -> None:
"""A single step of the agent."""

Expand Down
7 changes: 7 additions & 0 deletions mesa/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from __future__ import annotations

import random
from collections import defaultdict

# mypy
from typing import Any
Expand Down Expand Up @@ -41,6 +42,12 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
self.running = True
self.schedule = None
self.current_id = 0
self.agents: defaultdict[type, set] = defaultdict(set)

@property
def agent_types(self) -> list:
"""Return a list of different agent types."""
return list(self.agents.keys())

def run_model(self) -> None:
"""Run the model until the end condition is reached. Overload as
Expand Down

0 comments on commit 6e62857

Please sign in to comment.