Skip to content

Adds move_to_optimal function in DiscreteSpaceDF class #118

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

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
df26a23
test commit
suryanshgargbpgc Mar 11, 2025
7afe600
Added move_to function in DiscreteSpaceDF class
suryanshgargbpgc Mar 17, 2025
1d75987
Merge branch 'main' into optimizefunction
suryanshgargbpgc Mar 17, 2025
d26561e
Revert "test commit"
suryanshgargbpgc Mar 18, 2025
94daca7
moving type hint to types_ module
adamamer20 Mar 19, 2025
4bd0533
tests for move_to function
suryanshgargbpgc Mar 21, 2025
25e3baf
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 21, 2025
4859e2c
Update test_grid_polars.py
suryanshgargbpgc Mar 21, 2025
a9d9e8f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 21, 2025
06ac4eb
Update test_grid_polars.py
suryanshgargbpgc Mar 22, 2025
ab6f845
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 22, 2025
fc6be7c
Update space.py
suryanshgargbpgc Mar 22, 2025
3f7c26d
Merge branch 'optimizefunction' of https://github.com/suryanshgargbpg…
suryanshgargbpgc Mar 22, 2025
002a5d9
Update space.py
suryanshgargbpgc Mar 22, 2025
08c927d
Update agents.py
suryanshgargbpgc Mar 22, 2025
ec10744
adds blank line
suryanshgargbpgc Mar 22, 2025
0747f98
Update test_grid_polars.py
suryanshgargbpgc Mar 22, 2025
8cd426b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 22, 2025
5b8f8db
adds tests for move_to_optimal
suryanshgargbpgc Mar 23, 2025
3d28340
Update test_grid_polars.py
suryanshgargbpgc Mar 23, 2025
20b3968
Revert "Update test_grid_polars.py"
suryanshgargbpgc Mar 23, 2025
3a2dc16
update test_grid_polars
suryanshgargbpgc Mar 23, 2025
891f296
resolve conflicts
suryanshgargbpgc Mar 23, 2025
04246e8
Fix whitespace in AgentSetPandas docstring
suryanshgargbpgc Mar 24, 2025
f278e56
Fix docstring conflict in _prepare_cells method with proper format
suryanshgargbpgc Mar 24, 2025
56fdabc
Merge branch 'main' into optimizefunction
suryanshgargbpgc Mar 24, 2025
efc65e7
Merge branch 'main' into optimizefunction
adamamer20 Mar 29, 2025
f437548
update agenets.py
suryanshgargbpgc Mar 30, 2025
90351ba
Merge upstream changes and resolve conflicts
suryanshgargbpgc Apr 15, 2025
02e49c2
Revert "Merge upstream changes and resolve conflicts"
suryanshgargbpgc Apr 15, 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 .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ci:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.11.4
rev: v0.11.2
hooks:
# Run the linter.
- id: ruff
Expand Down Expand Up @@ -42,7 +42,7 @@ repos:
".markdownlint.json",
]
- repo: https://github.com/jsh9/pydoclint # For checking docstrings
rev: 0.6.5
rev: 0.6.2
hooks:
- id: pydoclint
args: [--style=numpy, --skip-checking-raises=True, --allow-init-docstring=True]
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ mesa-frames is an extension of the [mesa](https://github.com/projectmesa/mesa) f

## Why DataFrames? 📊

DataFrames are optimized for simultaneous operations through [SIMD processing](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data). At the moment, mesa-frames supports the use of Polars library.
DataFrames are optimized for simultaneous operations through [SIMD processing](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data). At the moment, mesa-frames supports the use of two main libraries: pandas and Polars.

>[!WARNING]
>The pandas version will be deprecated in the next release. Refer to [this issue](https://github.com/projectmesa/mesa-frames/issues/89) for more information. Please consider transitioning to Polars for future compatibility.

- [pandas](https://pandas.pydata.org/) is a popular data-manipulation Python library, developed using C and Cython. pandas is known for its ease of use, allowing for declarative programming and high performance.
- [Polars](https://pola.rs/) is a new DataFrame library with a syntax similar to pandas but with several innovations, including a backend implemented in Rust, the Apache Arrow memory format, query optimization, and support for larger-than-memory DataFrames.

The following is a performance graph showing execution time using mesa and mesa-frames for the [Boltzmann Wealth model](https://mesa.readthedocs.io/en/stable/tutorials/intro_tutorial.html).
Expand Down Expand Up @@ -86,7 +90,7 @@ You can find the API documentation [here](https://projectmesa.github.io/mesa-fra

### 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 either `AgentSetPandas` or `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.

```python
from mesa-frames import AgentSetPolars
Expand Down
11 changes: 6 additions & 5 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ This document outlines the development roadmap for the mesa-frames project. It p

## 0.1.0 Stable Release Goals 🎯

### 1. Transitioning polars implementation from eager API to lazy API
### 1. Deprecating pandas and Transitioning to polars

One of our major priorities was to move from pandas to polars as the primary dataframe backend. This transition was motivated by performance considerations.
Now we should transition to using the lazily evaluated version of polars.
One of our major priorities is to move from pandas to polars as the primary dataframe backend. This transition is motivated by performance considerations. We should use the lazily evaluated version of polars.

**Related issues:** [#10: GPU integration: Dask, cuda (cudf) and RAPIDS (Polars)](https://github.com/projectmesa/mesa-frames/issues/10), [#89: Investigate using Ibis for the common interface library to any DF backend](https://github.com/projectmesa/mesa-frames/issues/89), [#52: Use of LazyFrames for Polars implementation](https://github.com/projectmesa/mesa-frames/issues/52)
**Related issues:** [#89: Investigate using Ibis for the common interface library to any DF backend](https://github.com/projectmesa/mesa-frames/issues/89), [#10: GPU integration: Dask, cuda (cudf) and RAPIDS (Polars)](https://github.com/projectmesa/mesa-frames/issues/10)

#### Progress and Next Steps

- We are exploring [Ibis](https://ibis-project.org/) or [narwhals](https://github.com/narwhals-dev/narwhals) as a common interface library that could support multiple backends (Polars, DuckDB, Spark etc.), but since most of the development is currently in polars, we will currently continue using Polars.
- We're transitioning to the lazy API, mainly in order to use GPU acceleration
- The pandas backend is becoming increasingly problematic to maintain and will eventually be deprecated
- Benchmarking is underway to quantify performance differences between different backends
- We're investigating GPU acceleration options, including the potential integration with RAPIDS ecosystem

### 2. Handling Concurrency Management

Expand Down
4 changes: 2 additions & 2 deletions docs/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ This page provides a high-level overview of all public mesa-frames objects, func
.. grid-item-card::

.. toctree::
:maxdepth: 2
:maxdepth: 1

reference/model

.. grid-item-card::

.. toctree::
:maxdepth: 2
:maxdepth: 3

reference/space/index
12 changes: 6 additions & 6 deletions docs/api/reference/agents/index.rst
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
Agents
======
AgentSetDF
==========

.. currentmodule:: mesa_frames


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

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

4 changes: 2 additions & 2 deletions docs/api/reference/model.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Model
=====
ModelDF
=======

.. currentmodule:: mesa_frames

Expand Down
16 changes: 16 additions & 0 deletions docs/api/reference/space/grid/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
GridDF
======

.. currentmodule:: mesa_frames

.. autoclass:: GridPandas
:members:
:inherited-members:
:autosummary:
:autosummary-nosignatures:

.. autoclass:: GridPolars
:members:
:inherited-members:
:autosummary:
:autosummary-nosignatures:
9 changes: 3 additions & 6 deletions docs/api/reference/space/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ Space
=====
This page provides a high-level overview of possible space objects for mesa-frames models.

.. currentmodule:: mesa_frames
.. toctree::
:maxdepth: 2

.. autoclass:: GridPolars
:members:
:inherited-members:
:autosummary:
:autosummary-nosignatures:
grid/index
6 changes: 5 additions & 1 deletion docs/general/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ You can get a model which is multiple orders of magnitude faster based on the nu

## Why DataFrames? 📊

DataFrames are optimized for simultaneous operations through [SIMD processing](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data). Currently, mesa-frames supports the library:
!!! warning
The pandas version will be deprecated in the next release. Refer to [this issue](https://github.com/projectmesa/mesa-frames/issues/89) for more information. Please consider transitioning to Polars for future compatibility.

DataFrames are optimized for simultaneous operations through [SIMD processing](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data). Currently, mesa-frames supports two main libraries:

- [pandas](https://pandas.pydata.org/): A popular data-manipulation Python library, known for its ease of use and high performance.
- [Polars](https://pola.rs/): A new DataFrame library with a Rust backend, offering innovations like Apache Arrow memory format and support for larger-than-memory DataFrames.

## Performance Boost 🏎️
Expand Down
48 changes: 32 additions & 16 deletions docs/general/user-guide/0_getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ Check out these resources to understand vectorization and why it speeds up the c
Here's a comparison between mesa-frames and mesa:

=== "mesa-frames"

```python
class MoneyAgentPolarsConcise(AgentSetPolars):
# initialization...

def give_money(self):
# Active agents are changed to wealthy agents
self.select(self.wealth > 0)
Expand All @@ -57,10 +57,10 @@ Here's a comparison between mesa-frames and mesa:
```

=== "mesa"

```python
class MoneyAgent(mesa.Agent):
# initialization...

def give_money(self):
# Verify agent has some wealth
if self.wealth > 0:
Expand All @@ -72,6 +72,25 @@ Here's a comparison between mesa-frames and mesa:

As you can see, while in mesa you should iterate through all the agents' steps in the model class, here you execute the method once for all agents.

### Backend Flexibility 🔄

mesa-frames aims to support multiple DataFrame backends:
The supported backends right now are

- **pandas**: A widely-used data manipulation library
- **Polars**: A high-performance DataFrame library written in Rust

Users can choose the backend that best suits their needs:

```python
from mesa_frames import AgentSetPandas # or AgentSetPolars
```

Currently, there are two implementations of AgentSetDF and GridDF, one for each backend implementation: AgentSetPandas and AgentSetPolars, and GridPandas and GridPolars.
We encourage you to use the Polars implementation for increased performance. We are working on creating a unique interface [here](https://github.com/projectmesa/mesa-frames/discussions/12). Let us know what you think!

Soon we will also have multiple other backends like Dask, cuDF, and Dask-cuDF!

## Coming from mesa 🔀

If you're familiar with mesa, this guide will help you understand the key differences in code structure between mesa and mesa-frames.
Expand All @@ -82,15 +101,15 @@ If you're familiar with mesa, this guide will help you understand the key differ
- mesa-frames: Agents are rows in a DataFrame, grouped into AgentSets. Methods are defined for AgentSets and operate on all agents simultaneously.

=== "mesa-frames"

```python
class MoneyAgentSet(AgentSetPolars):
def __init__(self, n, model):
super().__init__(model)
def **init**(self, n, model):
super().**init**(model)
self += pl.DataFrame({
"unique_id": pl.arange(n),
"wealth": pl.ones(n)
})
})

def step(self):
givers = self.wealth > 0
receivers = self.agents.sample(n=len(self.active_agents))
Expand All @@ -100,11 +119,10 @@ If you're familiar with mesa, this guide will help you understand the key differ
```

=== "mesa"

```python
class MoneyAgent(Agent):
def __init__(self, unique_id, model):
super().__init__(unique_id, model)
def **init**(self, unique_id, model):
super().**init**(unique_id, model)
self.wealth = 1

def step(self):
Expand All @@ -120,23 +138,20 @@ If you're familiar with mesa, this guide will help you understand the key differ
- mesa-frames: Models manage AgentSets and directly control the simulation flow.

=== "mesa-frames"

```python
class MoneyModel(ModelDF):
def __init__(self, N):
super().__init__()
def **init**(self, N):
super().**init**()
self.agents += MoneyAgentSet(N, self)

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

```

=== "mesa"

```python
class MoneyModel(Model):
def __init__(self, N):
def **init**(self, N):
self.num_agents = N
self.schedule = RandomActivation(self)
for i in range(self.num_agents):
Expand All @@ -150,7 +165,7 @@ If you're familiar with mesa, this guide will help you understand the key differ
### Transition Tips 💡

1. **Think in Sets 🎭**: Instead of individual agents, think about operations on groups of agents.
2. **Leverage DataFrame Operations 🛠️**: Familiarize yourself with Polars operations for efficient agent manipulation.
2. **Leverage DataFrame Operations 🛠️**: Familiarize yourself with pandas or Polars operations for efficient agent manipulation.
3. **Vectorize Logic 🚅**: Convert loops and conditionals to vectorized operations where possible.
4. **Use AgentSets 📦**: Group similar agents into AgentSets instead of creating many individual agent classes.

Expand All @@ -161,6 +176,7 @@ When simultaneous activation is not possible, you need to handle race conditions
1. **Custom UDF with Numba 🔧**: Use a custom User Defined Function (UDF) with Numba for efficient sequential processing.

- [Polars UDF Guide](https://docs.pola.rs/user-guide/expressions/user-defined-functions/)
- [pandas Numba Engine](https://pandas.pydata.org/pandas-docs/stable/user_guide/window.html#numba-engine)

2. **Looping Mechanism 🔁**: Implement a looping mechanism on vectorized operations.

Expand Down
2 changes: 1 addition & 1 deletion docs/general/user-guide/1_classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## AgentSetDF 👥

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 AgentSetDF class, you need to subclass the AgentSetPolars or AgentSetPandas 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 has a 'unique_id' column and that the ids are unique across the model, otherwise you will get an error raised. In the DataFrame, you should also put any attribute of the agent you are using.

Expand Down
Loading