Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
231e3bd
Refactor tests to use updated Model and AgentSet classes
adamamer20 Aug 31, 2025
8d7fe14
Refactor agent set imports and introduce AgentSetRegistry
adamamer20 Aug 31, 2025
a814dd8
Refactor import statements for better readability in space.py and age…
adamamer20 Aug 31, 2025
5dbe6f5
Fix formatting in AGENTS.md for MESA_FRAMES_RUNTIME_TYPECHECKING vari…
adamamer20 Aug 31, 2025
79e94e5
Update type hints in AbstractAgentSetRegistry to reference abstract a…
adamamer20 Aug 31, 2025
09cb336
Introduce AbstractAgentSet class and refactor imports for consistency
adamamer20 Aug 31, 2025
ab80df0
Update type hints in AbstractAgentSetRegistry to reference concrete A…
adamamer20 Aug 31, 2025
7878392
Refactor import statements in agentset.py for improved readability
adamamer20 Sep 1, 2025
47a5413
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 1, 2025
dfa2287
Update docstring in AbstractAgentSet and improve type hints in Abstra…
adamamer20 Sep 1, 2025
ad53071
Merge branch '171-enhancement-rename-agentsetdf-to-abstractagentsetdf…
adamamer20 Sep 1, 2025
4dff1d8
Rename test class from Test_ModelDF to Test_Model for consistency
adamamer20 Sep 1, 2025
fccf344
Refactor GridPolars to Grid and update related references across the …
adamamer20 Sep 1, 2025
89454e2
Update copyright year in conf.py to use current year dynamically
adamamer20 Sep 3, 2025
36f132a
Rename MoneyAgentDF and MoneyModelDF classes to MoneyAgents and Money…
adamamer20 Sep 3, 2025
0771ef3
Add tests for CustomModel and its step functionality
adamamer20 Sep 3, 2025
a234bc8
Update space property type hint to use Space instead of SpaceDF for c…
adamamer20 Sep 3, 2025
e4737d9
Rename parameter in ExampleModel constructor from 'agents' to 'sets' …
adamamer20 Sep 3, 2025
ec1a357
Reorder DataCollector import to avoid circular import error
adamamer20 Sep 3, 2025
a3e2c56
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 3, 2025
9a0ecc8
Merge branch 'main' into 171-enhancement-rename-agentsetdf-to-abstrac…
adamamer20 Sep 3, 2025
84f186f
precommit
Ben-geo Sep 5, 2025
d50b00f
Replace MoneyAgentDF with MoneyAgents in MoneyModel constructor for c…
adamamer20 Sep 10, 2025
98f4859
Rename MoneyAgentDF to MoneyAgents for consistency in agent set imple…
adamamer20 Sep 10, 2025
d3402ee
Update tutorial to reflect renaming of agent classes from MoneyAgentP…
adamamer20 Sep 10, 2025
2d4854f
Refactor MoneyModel and MoneyAgents classes for consistency and clari…
adamamer20 Sep 10, 2025
dcee916
Update DataCollector tutorial with execution results and fix agent we…
adamamer20 Sep 10, 2025
0828832
Refactor agent and model classes for consistency: rename MoneyModel t…
adamamer20 Sep 10, 2025
2cd4e00
Fix agent type reference in SugarscapePolars model: update from AntPo…
adamamer20 Sep 10, 2025
73fa761
Fix model_reporters lambda function in ExampleModel to correctly sum …
adamamer20 Sep 10, 2025
4e02ffc
Refactor agent and model classes for consistency: update references f…
adamamer20 Sep 10, 2025
3637a35
Fix missing newline at end of file in ExampleModel documentation
adamamer20 Sep 10, 2025
2826c5c
Remove unused import of Model in agentset.py
adamamer20 Sep 10, 2025
475c4cb
Fix class name in documentation: update Space to AbstractSpace for cl…
adamamer20 Sep 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

- Install (dev stack): `uv sync` (always use uv)
- Lint & format: `uv run ruff check . --fix && uv run ruff format .`
- Tests (quiet + coverage): `export MESA_FRAMES_RUNTIME_TYPECHECKING = 1 && uv run pytest -q --cov=mesa_frames --cov-report=term-missing`
- Tests (quiet + coverage): `export MESA_FRAMES_RUNTIME_TYPECHECKING=1 && uv run pytest -q --cov=mesa_frames --cov-report=term-missing`
- Pre-commit (all files): `uv run pre-commit run -a`
- Docs preview: `uv run mkdocs serve`

Expand All @@ -36,7 +36,7 @@ Always run tools via uv: `uv run <command>`.
## Commit & Pull Request Guidelines

- Commits: Imperative mood, concise subject, meaningful body when needed.
Example: `Fix AgentsDF.sets copy binding and tests`.
Example: `Fix AgentSetRegistry.sets copy binding and tests`.
- PRs: Link issues, summarize changes, note API impacts, add/adjust tests and docs.
- CI hygiene: Run `ruff`, `pytest`, and `pre-commit` locally before pushing.

Expand Down
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ pip install -e .

### Creation of an Agent

The agent implementation differs from base mesa. Agents are only defined at the AgentSet level. You can import `AgentSetPolars`. As in mesa, you subclass and make sure to call `super().__init__(model)`. You can use the `add` method or the `+=` operator to add agents to the AgentSet. Most methods mirror the functionality of `mesa.AgentSet`. Additionally, `mesa-frames.AgentSet` implements many dunder methods such as `AgentSet[mask, attr]` to get and set items intuitively. All operations are by default inplace, but if you'd like to use functional programming, mesa-frames implements a fast copy method which aims to reduce memory usage, relying on reference-only and native copy methods.
The agent implementation differs from base mesa. Agents are only defined at the AgentSet level. You can import `AgentSet`. As in mesa, you subclass and make sure to call `super().__init__(model)`. You can use the `add` method or the `+=` operator to add agents to the AgentSet. Most methods mirror the functionality of `mesa.AgentSet`. Additionally, `mesa-frames.AgentSet` implements many dunder methods such as `AgentSet[mask, attr]` to get and set items intuitively. All operations are by default inplace, but if you'd like to use functional programming, mesa-frames implements a fast copy method which aims to reduce memory usage, relying on reference-only and native copy methods.

```python
from mesa-frames import AgentSetPolars
from mesa-frames import AgentSet

class MoneyAgentPolars(AgentSetPolars):
def __init__(self, n: int, model: ModelDF):
class MoneyAgents(AgentSet):
def __init__(self, n: int, model: Model):
super().__init__(model)
# Adding the agents to the agent set
self += pl.DataFrame(
Expand Down Expand Up @@ -126,20 +126,20 @@ class MoneyAgentPolars(AgentSetPolars):

### Creation of the Model

Creation of the model is fairly similar to the process in mesa. You subclass `ModelDF` and call `super().__init__()`. The `model.agents` attribute has the same interface as `mesa-frames.AgentSet`. You can use `+=` or `self.agents.add` with a `mesa-frames.AgentSet` (or a list of `AgentSet`) to add agents to the model.
Creation of the model is fairly similar to the process in mesa. You subclass `Model` and call `super().__init__()`. The `model.sets` attribute has the same interface as `mesa-frames.AgentSet`. You can use `+=` or `self.sets.add` with a `mesa-frames.AgentSet` (or a list of `AgentSet`) to add agents to the model.

```python
from mesa-frames import ModelDF
from mesa-frames import Model

class MoneyModelDF(ModelDF):
class MoneyModelDF(Model):
def __init__(self, N: int, agents_cls):
super().__init__()
self.n_agents = N
self.agents += MoneyAgentPolars(N, self)
self.sets += MoneyAgents(N, self)

def step(self):
# Executes the step method for every agentset in self.agents
self.agents.do("step")
# Executes the step method for every agentset in self.sets
self.sets.do("step")

def run_model(self, n):
for _ in range(n):
Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ The Sugarscape example demonstrates the need for this abstraction, as multiple a

#### Progress and Next Steps

- Create utility functions in `DiscreteSpaceDF` and `AgentContainer` to move agents optimally based on specified attributes
- Create utility functions in `DiscreteSpace` and `AgentSetRegistry` to move agents optimally based on specified attributes
- Provide built-in resolution strategies for common concurrency scenarios
- Ensure the implementation works efficiently with the vectorized approach of mesa-frames

Expand Down
3 changes: 2 additions & 1 deletion docs/api/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here.
import sys
from datetime import datetime
from pathlib import Path

sys.path.insert(0, str(Path("..").resolve()))

# -- Project information -----------------------------------------------------
project = "mesa-frames"
author = "Project Mesa, Adam Amer"
copyright = f"2023, {author}"
copyright = f"{datetime.now().year}, {author}"

# -- General configuration ---------------------------------------------------
extensions = [
Expand Down
6 changes: 3 additions & 3 deletions docs/api/reference/agents/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ Agents
.. currentmodule:: mesa_frames


.. autoclass:: AgentSetPolars
.. autoclass:: AgentSet
:members:
:inherited-members:
:autosummary:
:autosummary-nosignatures:

.. autoclass:: AgentsDF
.. autoclass:: AgentSetRegistry
:members:
:inherited-members:
:autosummary:
:autosummary-nosignatures:
:autosummary-nosignatures:
2 changes: 1 addition & 1 deletion docs/api/reference/model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Model

.. currentmodule:: mesa_frames

.. autoclass:: ModelDF
.. autoclass:: Model
:members:
:inherited-members:
:autosummary:
Expand Down
2 changes: 1 addition & 1 deletion docs/api/reference/space/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This page provides a high-level overview of possible space objects for mesa-fram

.. currentmodule:: mesa_frames

.. autoclass:: GridPolars
.. autoclass:: Grid
:members:
:inherited-members:
:autosummary:
Expand Down
12 changes: 6 additions & 6 deletions docs/general/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ pip install -e .
Here's a quick example of how to create a model using mesa-frames:

```python
from mesa_frames import AgentSetPolars, ModelDF
from mesa_frames import AgentSet, Model
import polars as pl

class MoneyAgentPolars(AgentSetPolars):
def __init__(self, n: int, model: ModelDF):
class MoneyAgents(AgentSet):
def __init__(self, n: int, model: Model):
super().__init__(model)
self += pl.DataFrame(
{"wealth": pl.ones(n, eager=True)}
Expand All @@ -57,13 +57,13 @@ class MoneyAgentPolars(AgentSetPolars):
def give_money(self):
# ... (implementation details)

class MoneyModelDF(ModelDF):
class MoneyModel(Model):
def __init__(self, N: int):
super().__init__()
self.agents += MoneyAgentPolars(N, self)
self.sets += MoneyAgents(N, self)

def step(self):
self.agents.do("step")
self.sets.do("step")

def run_model(self, n):
for _ in range(n):
Expand Down
16 changes: 8 additions & 8 deletions docs/general/user-guide/0_getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ Here's a comparison between mesa-frames and mesa:
=== "mesa-frames"

```python
class MoneyAgentPolarsConcise(AgentSetPolars):
class MoneyAgents(AgentSet):
# initialization...
def give_money(self):
# Active agents are changed to wealthy agents
self.select(self.wealth > 0)

# Receiving agents are sampled (only native expressions currently supported)
other_agents = self.agents.sample(
other_agents = self.sets.sample(
n=len(self.active_agents), with_replacement=True
)

Expand All @@ -64,7 +64,7 @@ Here's a comparison between mesa-frames and mesa:
def give_money(self):
# Verify agent has some wealth
if self.wealth > 0:
other_agent = self.random.choice(self.model.agents)
other_agent = self.random.choice(self.model.sets)
if other_agent is not None:
other_agent.wealth += 1
self.wealth -= 1
Expand All @@ -84,15 +84,15 @@ If you're familiar with mesa, this guide will help you understand the key differ
=== "mesa-frames"

```python
class MoneyAgentSet(AgentSetPolars):
class MoneyAgents(AgentSet):
def __init__(self, n, model):
super().__init__(model)
self += pl.DataFrame({
"wealth": pl.ones(n)
})
def step(self):
givers = self.wealth > 0
receivers = self.agents.sample(n=len(self.active_agents))
receivers = self.sets.sample(n=len(self.active_agents))
self[givers, "wealth"] -= 1
new_wealth = receivers.groupby("unique_id").count()
self[new_wealth["unique_id"], "wealth"] += new_wealth["count"]
Expand Down Expand Up @@ -121,13 +121,13 @@ If you're familiar with mesa, this guide will help you understand the key differ
=== "mesa-frames"

```python
class MoneyModel(ModelDF):
class MoneyModel(Model):
def __init__(self, N):
super().__init__()
self.agents += MoneyAgentSet(N, self)
self.sets += MoneyAgents(N, self)

def step(self):
self.agents.do("step")
self.sets.do("step")

```

Expand Down
44 changes: 22 additions & 22 deletions docs/general/user-guide/1_classes.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# Classes 📚

## AgentSetDF 👥
## AgentSet 👥

To create your own AgentSetDF class, you need to subclass the AgentSetPolars class and make sure to call `super().__init__(model)`.
To create your own AgentSet class, you need to subclass the AgentSet class and make sure to call `super().__init__(model)`.

Typically, the next step would be to populate the class with your agents. To do that, you need to add a DataFrame to the AgentSetDF. You can do `self += agents` or `self.add(agents)`, where `agents` is a DataFrame or something that could be passed to a DataFrame constructor, like a dictionary or lists of lists. You need to make sure your DataFrame doesn't have a 'unique_id' column because IDs are generated automatically, otherwise you will get an error raised. In the DataFrame, you should also put any attribute of the agent you are using.
Typically, the next step would be to populate the class with your agents. To do that, you need to add a DataFrame to the AgentSet. You can do `self += agents` or `self.add(agents)`, where `agents` is a DataFrame or something that could be passed to a DataFrame constructor, like a dictionary or lists of lists. You need to make sure your DataFrame doesn't have a 'unique_id' column because IDs are generated automatically, otherwise you will get an error raised. In the DataFrame, you should also put any attribute of the agent you are using.

How can you choose which agents should be in the same AgentSet? The idea is that you should minimize the missing values in the DataFrame (so they should have similar/same attributes) and mostly everybody should do the same actions.

Example:

```python
class MoneyAgent(AgentSetPolars):
def __init__(self, n: int, model: ModelDF):
class MoneyAgents(AgentSet):
def __init__(self, n: int, model: Model):
super().__init__(model)
self.initial_wealth = pl.ones(n)
self += pl.DataFrame({
Expand All @@ -25,28 +25,28 @@ class MoneyAgent(AgentSetPolars):

You can access the underlying DataFrame where agents are stored with `self.df`. This allows you to use DataFrame methods like `self.df.sample` or `self.df.group_by("wealth")` and more.

## ModelDF 🏗️
## Model 🏗️

To add your AgentSetDF to your ModelDF, you should also add it to the agents with `+=` or `add`.
To add your AgentSet to your Model, you should also add it to the sets with `+=` or `add`.

NOTE: ModelDF.agents are stored in a class which is entirely similar to AgentSetDF called AgentsDF. The API of the two are the same. If you try accessing AgentsDF.df, you will get a dictionary of `[AgentSetDF, DataFrame]`.
NOTE: Model.sets are stored in a class which is entirely similar to AgentSet called AgentSetRegistry. The API of the two are the same. If you try accessing AgentSetRegistry.df, you will get a dictionary of `[AgentSet, DataFrame]`.

Example:

```python
class EcosystemModel(ModelDF):
class EcosystemModel(Model):
def __init__(self, n_prey, n_predators):
super().__init__()
self.agents += Preys(n_prey, self)
self.agents += Predators(n_predators, self)
self.sets += Preys(n_prey, self)
self.sets += Predators(n_predators, self)

def step(self):
self.agents.do("move")
self.agents.do("hunt")
self.sets.do("move")
self.sets.do("hunt")
self.prey.do("reproduce")
```

## Space: GridDF 🌐
## Space: Grid 🌐

mesa-frames provides efficient implementations of spatial environments:

Expand All @@ -55,12 +55,12 @@ mesa-frames provides efficient implementations of spatial environments:
Example:

```python
class GridWorld(ModelDF):
class GridWorld(Model):
def __init__(self, width, height):
super().__init__()
self.space = GridPolars(self, (width, height))
self.agents += AgentSet(100, self)
self.space.place_to_empty(self.agents)
self.space = Grid(self, (width, height))
self.sets += AgentSet(100, self)
self.space.place_to_empty(self.sets)
```

A continuous GeoSpace, NetworkSpace, and a collection to have multiple spaces in the models are in the works! 🚧
Expand All @@ -73,21 +73,21 @@ You configure what to collect, how to store it, and when to trigger collection.
Example:

```python
class ExampleModel(ModelDF):
class ExampleModel(Model):
def __init__(self):
super().__init__()
self.agents = MoneyAgent(self)
self.sets = MoneyAgent(self)
self.datacollector = DataCollector(
model=self,
model_reporters={"total_wealth": lambda m: m.agents["wealth"].sum()},
model_reporters={"total_wealth": lambda m: lambda m: list(m.sets.df.values())[0]["wealth"].sum()},
agent_reporters={"wealth": "wealth"},
storage="csv",
storage_uri="./data",
trigger=lambda m: m.schedule.steps % 2 == 0
)

def step(self):
self.agents.step()
self.sets.step()
self.datacollector.conditional_collect()
self.datacollector.flush()
```
Loading
Loading