-
Notifications
You must be signed in to change notification settings - Fork 6
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
Refactoring mesa.Agent, mesa.AgentSet, mesa.Model -> AgentSetDF, AgentsDF, ModelDF #8
Changes from 7 commits
5bf030f
64767b7
a4e17c0
5eef752
a8327e6
12a2f63
1a15b3f
8a17517
9d264c7
4e61b0d
a79d1b5
8282f42
f313991
9914834
a17468a
5ad192e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
from hmac import new | ||
from random import seed | ||
from typing import TYPE_CHECKING | ||
|
||
import mesa | ||
import numpy as np | ||
import pandas as pd | ||
import perfplot | ||
|
||
from mesa_frames.agent import AgentDF | ||
from mesa_frames.model import ModelDF | ||
from mesa_frames import AgentSetDF, ModelDF | ||
|
||
|
||
# Mesa implementation | ||
|
@@ -57,6 +61,14 @@ def run_model(self, n_steps) -> None: | |
self.step() | ||
|
||
|
||
"""def compute_gini(model): | ||
agent_wealths = model.agents.get("wealth") | ||
x = sorted(agent_wealths) | ||
N = model.num_agents | ||
B = sum(xi * (N - i) for i, xi in enumerate(x)) / (N * sum(x)) | ||
return 1 + (1 / N) - 2 * B""" | ||
|
||
|
||
# Mesa Frames implementation | ||
def mesa_frames_implementation(n_agents: int) -> None: | ||
model = MoneyModelDF(n_agents) | ||
|
@@ -67,45 +79,48 @@ class MoneyModelDF(ModelDF): | |
def __init__(self, N): | ||
super().__init__() | ||
self.num_agents = N | ||
self.create_agents(N, {MoneyAgentDF: 1}) | ||
self.agents = self.agents.add(MoneyAgentsDF(N, model=self)) | ||
|
||
def step(self): | ||
self.agents = self.agents.do("step") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks good to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The API is simpler. |
||
|
||
def step(self, merged_mro=True): | ||
self.agents = self.agents.sample(frac=1) | ||
self.update_agents_masks() | ||
super().step(merged_mro) | ||
def run_model(self, n): | ||
for _ in range(n): | ||
self.step() | ||
|
||
|
||
class MoneyAgentDF(AgentDF): | ||
dtypes: dict[str, str] = {"wealth": "int64"} | ||
class MoneyAgentsDF(AgentSetDF): | ||
def __init__(self, n: int, model: MoneyModelDF): | ||
super().__init__(model=model) | ||
self.add(n, data={"wealth": np.ones(n)}) | ||
|
||
@classmethod | ||
def __init__(cls): | ||
super().__init__() | ||
cls.model.agents.loc[cls.mask, "wealth"] = 1 | ||
def step(self): | ||
wealthy_agents = self.agents["wealth"] > 0 | ||
self.select(wealthy_agents).do("give_money") | ||
|
||
@classmethod | ||
def step(cls): | ||
wealthy_agents = cls.model.agents.loc[cls.mask, "wealth"] > 0 | ||
if wealthy_agents.any(): | ||
other_agents = cls.model.agents.index.isin( | ||
cls.model.agents.sample(n=wealthy_agents.sum()).index | ||
) | ||
cls.model.agents.loc[wealthy_agents, "wealth"] -= 1 | ||
cls.model.agents.loc[other_agents, "wealth"] += 1 | ||
def give_money(self): | ||
other_agents = self.agents.sample(len(self.active_agents), replace=True) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't the term "active agent" an internal one, given that it is the ones selected by There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but i declared it as a property so it should be fine to use it in the public api right? it returns a view. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can change the term |
||
new_wealth = ( | ||
other_agents.index.value_counts() | ||
.reindex(self.active_agents.index) | ||
.fillna(-1) | ||
) | ||
self.set_attribute("wealth", self.get_attribute("wealth") + new_wealth) | ||
|
||
|
||
def main(): | ||
mesa_frames_implementation(100) | ||
out = perfplot.bench( | ||
setup=lambda n: n, | ||
kernels=[mesa_implementation, mesa_frames_implementation], | ||
labels=["mesa", "mesa-frames"], | ||
n_range=[k for k in range(10, 10000, 100)], | ||
n_range=[k for k in range(100, 1000, 100)], | ||
xlabel="Number of agents", | ||
equality_check=None, | ||
title="100 steps of the Boltzmann Wealth model", | ||
) | ||
out.show() | ||
out.save("docs/images/readme_plot.png") | ||
# out.save("docs/images/readme_plot.png") | ||
|
||
|
||
if __name__ == "__main__": | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from .agent import AgentsDF, AgentSetDF | ||
from .model import ModelDF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be an inplace operation, based on the API of
AgentSet
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it because Polars doesn't support inplace operations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rht I've set up a fast immutable system using custom DataFrame copies, aligning better with the pandas/polars API. I think it reduces confusion.
I'll update the script soon.