Skip to content

Mesa logo

mesa-frames

CI/CD CI Checks codecov
Package PyPI - Version PyPI - Downloads PyPI - Python Version
Meta linting - Ruff formatter - Ruff Hatch project Managed with uv
Chat chat

Scale Mesa beyond its limits

Classic Mesa stores each agent as a Python object, which quickly becomes a bottleneck at scale. mesa-frames reimagines agent storage using Polars DataFrames, so agents live in a columnar store rather than the Python heap.

You keep the Mesa-style Model / AgentSet structure, but updates are vectorized and memory-efficient.

Why it matters

  • 10× faster bulk updates on 10k+ agents (see Benchmarks)
  • 📊 Columnar execution via Polars: SIMD ops, multi-core support
  • 🔄 Declarative logic: agent rules as transformations, not Python loops
  • 🚀 Roadmap: Lazy queries and GPU support for even faster models

Who is it for?

  • Researchers needing to scale to tens or hundreds of thousands of agents
  • Users whose agent logic can be written as vectorized, set-based operations

Not a good fit if: your model depends on strict per-agent sequencing, complex non-vectorizable methods, or fine-grained identity tracking.


Why DataFrames?

DataFrames enable SIMD and columnar operations that are far more efficient than Python loops. mesa-frames currently uses Polars as its backend.

Feature mesa (classic) mesa-frames
Storage Python objects Polars DataFrame
Updates Loops Vectorized ops
Memory overhead High Low
Max agents (practical) ~10^3 ~10^6+

Benchmarks

Reproduce Benchmarks

mesa-frames consistently outperforms classic Mesa across both toy and canonical ABMs.

In the Boltzmann model, it maintains near-constant runtimes even as agent count rises, achieving up to 10× faster execution at scale.

In the more computation-intensive Sugarscape model, mesa-frames roughly halves total runtime.

We still have room to optimize performance further (see Roadmap).

Benchmark: Boltzmann Wealth

Benchmark: Sugarscape IG


Quick Start

Explore the Tutorials

  1. Install
   pip install mesa-frames

Or for development:

git clone https://github.com/mesa/mesa-frames.git
cd mesa-frames
uv sync --all-extras
  1. Create a model
from mesa_frames import AgentSet, Model
import polars as pl

class MoneyAgents(AgentSet):
    def __init__(self, n: int, model: Model):
        super().__init__(model)
        self += pl.DataFrame({"wealth": pl.ones(n, eager=True)})

    def give_money(self):
        self.select(self.wealth > 0)
        other_agents = self.df.sample(n=len(self.active_agents), with_replacement=True)
        self["active", "wealth"] -= 1
        new_wealth = other_agents.group_by("unique_id").len()
        self[new_wealth, "wealth"] += new_wealth["len"]

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

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

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

Roadmap

Community contributions welcome — see the full roadmap

  • Transition to LazyFrames for optimization and GPU support
  • Auto-vectorize existing Mesa models via decorator
  • Increase possible Spaces (Network, Continuous...)
  • Refine the API to align to Mesa

License

Copyright © 2025 Adam Amer, Mesa team and contributors

Licensed under the Apache License, Version 2.0.