Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
198db6b
Update dependencies: add 'mesa>=3.2.0' and retain existing versions f…
adamamer20 Aug 29, 2025
99daedb
update uv.lock
adamamer20 Aug 29, 2025
82b3c31
Refactor MoneyAgent initialization and agent addition in MoneyModel f…
adamamer20 Aug 29, 2025
e439960
Update introductory tutorial notebook: fix installation command, adju…
adamamer20 Aug 29, 2025
0786ebe
Refactor MoneyModel initialization loop to use underscore for unused …
adamamer20 Aug 29, 2025
c1702fb
Remove unused 'unique_id' field from DataFrame initialization in agen…
adamamer20 Aug 29, 2025
b826502
Remove 'unique_id' field from MoneyAgentPolars DataFrame initialization
adamamer20 Aug 29, 2025
7bb24e4
Remove 'unique_id' field from MoneyAgentPolars DataFrame initialization
adamamer20 Aug 29, 2025
e5c1c9b
Update AgentSetDF documentation to clarify 'unique_id' column require…
adamamer20 Aug 29, 2025
ab0f490
Refactor SugarscapeMesa to use set for agents instead of list for mes…
adamamer20 Aug 29, 2025
f5e552a
Remove 'unique_id' parameter from AntMesa and Sugar class initializers
adamamer20 Aug 29, 2025
eec5c04
Refactor SugarscapeMesa to remove agent_id and simplify Sugar initial…
adamamer20 Aug 29, 2025
ff8025b
Remove 'unique_id' from AntPolarsBase initialization and update null …
adamamer20 Aug 29, 2025
52f75a6
Update display name in introductory tutorial to 'mesa-frames'
adamamer20 Aug 29, 2025
ffe2ad9
Refactor AntPolarsLoop to improve readability by consolidating method…
adamamer20 Aug 29, 2025
d0360aa
Remove agent_id from AntMesa initialization in SugarscapeMesa
adamamer20 Aug 29, 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class MoneyAgentPolars(AgentSetPolars):
super().__init__(model)
# Adding the agents to the agent set
self += pl.DataFrame(
{"unique_id": pl.arange(n, eager=True), "wealth": pl.ones(n, eager=True)}
{"wealth": pl.ones(n, eager=True)}
)

def step(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion docs/general/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class MoneyAgentPolars(AgentSetPolars):
def __init__(self, n: int, model: ModelDF):
super().__init__(model)
self += pl.DataFrame(
{"unique_id": pl.arange(n, eager=True), "wealth": pl.ones(n, eager=True)}
{"wealth": pl.ones(n, eager=True)}
)

def step(self) -> None:
Expand Down
1 change: 0 additions & 1 deletion docs/general/user-guide/0_getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ If you're familiar with mesa, this guide will help you understand the key differ
def __init__(self, n, model):
super().__init__(model)
self += pl.DataFrame({
"unique_id": pl.arange(n),
"wealth": pl.ones(n)
})
def step(self):
Expand Down
3 changes: 1 addition & 2 deletions docs/general/user-guide/1_classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

To create your own AgentSetDF class, you need to subclass the AgentSetPolars 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.
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.

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.

Expand All @@ -16,7 +16,6 @@ class MoneyAgent(AgentSetPolars):
super().__init__(model)
self.initial_wealth = pl.ones(n)
self += pl.DataFrame({
"unique_id": pl.arange(n),
"wealth": self.initial_wealth
})

Expand Down
89 changes: 53 additions & 36 deletions docs/general/user-guide/2_introductory-tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 18,
"id": "df4d8623",
"metadata": {},
"outputs": [],
"source": [
"# !pip install mesa-frames mesa"
"# !pip install git+https://github.com/projectmesa/mesa-frames mesa"
]
},
{
Expand All @@ -44,7 +44,7 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 19,
"id": "fc0ee981",
"metadata": {},
"outputs": [],
Expand Down Expand Up @@ -79,7 +79,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 20,
"id": "2bac0126",
"metadata": {},
"outputs": [],
Expand All @@ -90,9 +90,7 @@
"class MoneyAgentPolars(AgentSetPolars):\n",
" def __init__(self, n: int, model: ModelDF):\n",
" super().__init__(model)\n",
" self += pl.DataFrame(\n",
" {\"unique_id\": pl.arange(n, eager=True), \"wealth\": pl.ones(n, eager=True)}\n",
" )\n",
" self += pl.DataFrame({\"wealth\": pl.ones(n, eager=True)})\n",
"\n",
" def step(self) -> None:\n",
" self.do(\"give_money\")\n",
Expand All @@ -118,10 +116,33 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 21,
"id": "65da4e6f",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"shape: (9, 2)\n",
"┌────────────┬──────────┐\n",
"│ statistic ┆ wealth │\n",
"│ --- ┆ --- │\n",
"│ str ┆ f64 │\n",
"╞════════════╪══════════╡\n",
"│ count ┆ 1000.0 │\n",
"│ null_count ┆ 0.0 │\n",
"│ mean ┆ 1.0 │\n",
"│ std ┆ 1.134587 │\n",
"│ min ┆ 0.0 │\n",
"│ 25% ┆ 0.0 │\n",
"│ 50% ┆ 1.0 │\n",
"│ 75% ┆ 2.0 │\n",
"│ max ┆ 8.0 │\n",
"└────────────┴──────────┘\n"
]
}
],
"source": [
"# Choose either MoneyAgentPandas or MoneyAgentPolars\n",
"agent_class = MoneyAgentPolars\n",
Expand All @@ -131,6 +152,7 @@
"model.run_model(100)\n",
"\n",
"wealth_dist = list(model.agents.df.values())[0]\n",
"\n",
"# Print the final wealth distribution\n",
"print(wealth_dist.select(pl.col(\"wealth\")).describe())"
]
Expand All @@ -150,7 +172,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 22,
"id": "fbdb540810924de8",
"metadata": {},
"outputs": [],
Expand All @@ -161,21 +183,18 @@
" ## Adding the agents to the agent set\n",
" # 1. Changing the df attribute directly (not recommended, if other agents were added before, they will be lost)\n",
" \"\"\"self.df = pl.DataFrame(\n",
" {\"unique_id\": pl.arange(n, eager=True), \"wealth\": pl.ones(n, eager=True)}\n",
" {\"wealth\": pl.ones(n, eager=True)}\n",
" )\"\"\"\n",
" # 2. Adding the dataframe with add\n",
" \"\"\"self.add(\n",
" pl.DataFrame(\n",
" {\n",
" \"unique_id\": pl.arange(n, eager=True),\n",
" \"wealth\": pl.ones(n, eager=True),\n",
" }\n",
" )\n",
" )\"\"\"\n",
" # 3. Adding the dataframe with __iadd__\n",
" self += pl.DataFrame(\n",
" {\"unique_id\": pl.arange(n, eager=True), \"wealth\": pl.ones(n, eager=True)}\n",
" )\n",
" self += pl.DataFrame({\"wealth\": pl.ones(n, eager=True)})\n",
"\n",
" def step(self) -> None:\n",
" # The give_money method is called\n",
Expand Down Expand Up @@ -216,9 +235,7 @@
"class MoneyAgentPolarsNative(AgentSetPolars):\n",
" def __init__(self, n: int, model: ModelDF):\n",
" super().__init__(model)\n",
" self += pl.DataFrame(\n",
" {\"unique_id\": pl.arange(n, eager=True), \"wealth\": pl.ones(n, eager=True)}\n",
" )\n",
" self += pl.DataFrame({\"wealth\": pl.ones(n, eager=True)})\n",
"\n",
" def step(self) -> None:\n",
" self.do(\"give_money\")\n",
Expand All @@ -231,7 +248,9 @@
"\n",
" # Wealth of wealthy is decreased by 1\n",
" self.df = self.df.with_columns(\n",
" wealth=pl.when(pl.col(\"unique_id\").is_in(self.active_agents[\"unique_id\"]))\n",
" wealth=pl.when(\n",
" pl.col(\"unique_id\").is_in(self.active_agents[\"unique_id\"].implode())\n",
" )\n",
" .then(pl.col(\"wealth\") - 1)\n",
" .otherwise(pl.col(\"wealth\"))\n",
" )\n",
Expand All @@ -257,14 +276,12 @@
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 23,
"id": "9dbe761af964af5b",
"metadata": {},
"outputs": [],
"source": [
"import mesa\n",
"import importlib.metadata\n",
"from packaging import version\n",
"\n",
"\n",
"class MoneyAgent(mesa.Agent):\n",
Expand Down Expand Up @@ -292,7 +309,7 @@
" def __init__(self, N: int):\n",
" super().__init__()\n",
" self.num_agents = N\n",
" for i in range(N):\n",
" for _ in range(N):\n",
" self.agents.add(MoneyAgent(self))\n",
"\n",
" def step(self):\n",
Expand All @@ -306,7 +323,7 @@
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": 24,
"id": "2d864cd3",
"metadata": {},
"outputs": [
Expand All @@ -317,21 +334,21 @@
"Execution times:\n",
"---------------\n",
"mesa:\n",
" Number of agents: 100, Time: 0.06 seconds\n",
" Number of agents: 1001, Time: 3.56 seconds\n",
" Number of agents: 2000, Time: 12.81 seconds\n",
" Number of agents: 100, Time: 0.03 seconds\n",
" Number of agents: 1001, Time: 1.45 seconds\n",
" Number of agents: 2000, Time: 5.40 seconds\n",
"---------------\n",
"---------------\n",
"mesa-frames (pl concise):\n",
" Number of agents: 100, Time: 0.20 seconds\n",
" Number of agents: 1001, Time: 0.21 seconds\n",
" Number of agents: 2000, Time: 0.23 seconds\n",
" Number of agents: 100, Time: 1.60 seconds\n",
" Number of agents: 1001, Time: 2.68 seconds\n",
" Number of agents: 2000, Time: 3.04 seconds\n",
"---------------\n",
"---------------\n",
"mesa-frames (pl native):\n",
" Number of agents: 100, Time: 0.11 seconds\n",
" Number of agents: 1001, Time: 0.12 seconds\n",
" Number of agents: 2000, Time: 0.13 seconds\n",
" Number of agents: 100, Time: 0.62 seconds\n",
" Number of agents: 1001, Time: 0.80 seconds\n",
" Number of agents: 2000, Time: 1.10 seconds\n",
"---------------\n"
]
}
Expand Down Expand Up @@ -390,7 +407,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "mesa-frames",
"language": "python",
"name": "python3"
},
Expand All @@ -404,9 +421,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.1"
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
}
30 changes: 13 additions & 17 deletions examples/boltzmann_wealth/performance_plot.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import importlib.metadata

import matplotlib.pyplot as plt
import mesa
import numpy as np

import perfplot
import polars as pl
import seaborn as sns
import importlib.metadata
from packaging import version

from mesa_frames import AgentSetPolars, ModelDF
Expand All @@ -20,9 +20,9 @@ def mesa_implementation(n_agents: int) -> None:
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""

def __init__(self, unique_id, model):
def __init__(self, model):
# Pass the parameters to the parent class.
super().__init__(unique_id, model)
super().__init__(model)

# Create the agent's variable and set the initial values.
self.wealth = 1
Expand All @@ -42,13 +42,12 @@ class MoneyModel(mesa.Model):
def __init__(self, N):
super().__init__()
self.num_agents = N
self.agents = [MoneyAgent(i, self) for i in range(self.num_agents)]
for _ in range(self.num_agents):
self.agents.add(MoneyAgent(self))

def step(self):
"""Advance the model by one step."""
self.random.shuffle(self.agents)
for agent in self.agents:
agent.step()
self.agents.shuffle_do("step")

def run_model(self, n_steps) -> None:
for _ in range(n_steps):
Expand All @@ -72,21 +71,18 @@ def __init__(self, n: int, model: ModelDF):
## Adding the agents to the agent set
# 1. Changing the agents attribute directly (not recommended, if other agents were added before, they will be lost)
"""self.agents = pl.DataFrame(
{"unique_id": pl.arange(n, eager=True), "wealth": pl.ones(n, eager=True)}
"wealth": pl.ones(n, eager=True)}
)"""
# 2. Adding the dataframe with add
"""self.add(
pl.DataFrame(
{
"unique_id": pl.arange(n, eager=True),
"wealth": pl.ones(n, eager=True),
}
)
)"""
# 3. Adding the dataframe with __iadd__
self += pl.DataFrame(
{"unique_id": pl.arange(n, eager=True), "wealth": pl.ones(n, eager=True)}
)
self += pl.DataFrame({"wealth": pl.ones(n, eager=True)})

def step(self) -> None:
# The give_money method is called
Expand Down Expand Up @@ -127,9 +123,7 @@ def give_money(self):
class MoneyAgentPolarsNative(AgentSetPolars):
def __init__(self, n: int, model: ModelDF):
super().__init__(model)
self += pl.DataFrame(
{"unique_id": pl.arange(n, eager=True), "wealth": pl.ones(n, eager=True)}
)
self += pl.DataFrame({"wealth": pl.ones(n, eager=True)})

def step(self) -> None:
self.do("give_money")
Expand All @@ -142,7 +136,9 @@ def give_money(self):

# Wealth of wealthy is decreased by 1
self.df = self.df.with_columns(
wealth=pl.when(pl.col("unique_id").is_in(self.active_agents["unique_id"]))
wealth=pl.when(
pl.col("unique_id").is_in(self.active_agents["unique_id"].implode())
)
.then(pl.col("wealth") - 1)
.otherwise(pl.col("wealth"))
)
Expand Down
8 changes: 4 additions & 4 deletions examples/sugarscape_ig/ss_mesa/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ def get_distance(pos_1, pos_2):


class AntMesa(mesa.Agent):
def __init__(self, unique_id, model, moore=False, sugar=0, metabolism=0, vision=0):
super().__init__(unique_id, model)
def __init__(self, model, moore=False, sugar=0, metabolism=0, vision=0):
super().__init__(model)
self.moore = moore
self.sugar = sugar
self.metabolism = metabolism
Expand Down Expand Up @@ -71,8 +71,8 @@ def step(self):


class Sugar(mesa.Agent):
def __init__(self, unique_id, model, max_sugar):
super().__init__(unique_id, model)
def __init__(self, model, max_sugar):
super().__init__(model)
self.amount = max_sugar
self.max_sugar = max_sugar

Expand Down
Loading
Loading